WireGuard가 인터페이스를 만들지 못할 때: 커널인가 권한인가?
피어 핸드셰이크가 시작되기도 전에 인터페이스 생성이 실패한다. 오류를 읽어 빠진 모듈인지 권한 경계인지 이미 존재하는 인터페이스 소유자인지 구분한다.
WireGuard가 인터페이스를 만들지 못하면 구성할 장치도, 교환할 키도, 디버깅할 핸드셰이크도 없다. 실패는 전적으로 로컬 머신에 있으며, 오류 텍스트는 로컬 스택의 어느 부분이 거부했는지 알려 준다. 이를 올바로 읽는 편이 피어 구성을 다시 설치하는 것보다 빠르다. 계층은 분리할 수 있고, 메시지는 거부한 계층을 지목한다.
오류는 어떤 피어도 말하기 전에 발생한다
인터페이스를 만드는 것은 wireguard 유형의 장치를 요청하는 커널에 대한 netlink 요청 하나다. 커널에 그 유형을 이해하는 드라이버가 있거나 없고, 답은 즉시 돌아온다. 이 단계에서는 패킷이 머신을 떠나지 않으므로 엔드포인트 주소와 서버 키가 원인이 될 수 없다.
이 순서는 진단에 중요하다. 명령이 장치를 만든 적이 없다면 문제는 잘못된 공개 키나 차단된 UDP 포트일 수 없다. 먼저 로컬 생성 경로를 고치고 그다음에야 바깥을 살펴본다.
어떤 구현이 장치를 소유해야 하는가
그 요청에 두 구현이 답할 수 있다. 커널 내부 모듈은 wireguard 장치 유형을 등록하고, wireguard-go 같은 사용자 공간 구현은 다른 메커니즘으로 같은 인터페이스를 제공한다. 모듈이 없으면 커널은 지원되지 않는 장치 오류로 요청을 거부하며, 해법은 모듈을 적재하거나 도구를 사용자 공간 구현으로 향하게 하는 것이다.
둘 중에서 고르기 전에 실제로 무엇이 있는지 확인한다. 첫 번째 명령은 모듈이 적재되었는지 보여 주고 두 번째는 커널에 직접 묻는다:
lsmod | grep wireguard
ip link add wgtest0 type wireguard
두 번째 명령은 가능한 가장 작은 재현이다: 장치만 요청하고 그 밖의 것은 요청하지 않는다. 지원되지 않는 유형이라는 메시지로 실패한다면 빠진 조각은 구현이며 당신의 구성 파일이 아니다.
| Error text | What refused | Next step |
|---|---|---|
| Unknown device type or operation not supported | The kernel has no wireguard driver | Load the module or use the userspace implementation |
| Operation not permitted | Missing privilege | Use the service context or grant the capability |
| File exists | The name is already in use | Inspect the owner before touching it |
| No such device in a container | No tunnel device or capability | Add the device and NET_ADMIN to the container |
권한과 컨테이너 경계
네트워크 장치를 만들고 구성하려면 root이거나 네트워크 관리 기능을 갖춘 권한이 필요하다. 일반 사용자 세션은 할 수 없으며, 이 제한은 설계 자체이지 검토하지 않은 설치 프로그램을 돌려 우회할 장애물이 아니다.
컨테이너 안에서는 경계가 두 배가 된다. 컨테이너에는 터널 장치에 대한 접근과 그것을 구성할 기능이 필요하며, 이를 부여하는 플래그는 Linux VPN 컨테이너가 쓰는 것과 같다. 평소 웹을 볼 수 있는 제한된 게스트도 인터페이스를 만들 수는 없는데, 웹 브라우징에는 그런 기능이 필요 없기 때문이다. 기능은 그것이 필요한 서비스에 주고 호스트의 모든 세션에 주지 않는다.
이름 충돌을 해결한 뒤 다시 시도한다
이미 존재하는 인터페이스가 자동으로 잔여물은 아니다. 다른 관리자가 그 이름을 소유하고 지금 사용 중일 수 있으므로 무엇이든 지우기 전에 살펴본다:
ip link show wg0
sudo wg show wg0
소유자가 활성 서비스라면 두 번째 장치를 만드는 대신 그 서비스를 구성한다. 정말로 오래된 것이라면 그것을 만든 도구로 제거하고, 그다음 문서화된 클라이언트나 유닛으로 인터페이스를 올려 구성과 장치가 함께 유지되게 한다.
생성이 성공하면, 다음 실패는 더 뒤 단계에 속한다, 장치가 존재한 뒤 실패를 보고하는 유닛은 한 번도 만들어진 적 없는 장치와 다른 문제다. 권한을 다시 바꾸기 전에 둘을 분리한다.