LXD는 장치 노드를 추가하여 호스트의 문자 장치를 컨테이너에 노출하며, 게스트가 직접 만들도록 가르치는 것이 아닙니다. 컨테이너에 /dev/net/tun 이 없으면 호스트에는 장치가 있어도 게스트가 열지 못할 수 있습니다. unix-char 항목은 이 경로의 관리자 측 절반이며, 권한 있는 컨테이너보다 의도적으로 좁습니다. 그래서 호스트 노드와 컨테이너 노드는 따로 확인할 가치가 있습니다.

방식은 짧아서 놓치지 않습니다: LXD는 호스트 경로를 해석하고, 인스턴스 안에 대응하는 노드를 만들고, 장치를 컨테이너의 장치 cgroup에 추가합니다. 그다음 게스트 프로세스는 노드를 무엇이든 쓰기 위해 자체 권한과 능력을 필요로 합니다.

unix-char 항목이 실제로 바꾸는 것

unix-char 장치는 호스트의 문자 장치 하나를 컨테이너 안의 선택한 경로에 노출하라고 LXD에 지시합니다. 항목에는 중요한 세 부분이 있습니다: 관리자가 쓰는 장치 레이블, 호스트의 source 경로, 게스트가 보는 path 입니다. 장치 자체를 설명하는 것은 마지막 두 가지뿐입니다. 둘 중 하나를 잘못 입력하면 클라이언트가 절대 열지 않는 위치에 노드가 생깁니다.

호스트에서 장치는 보통 /dev/net/tun 입니다. 컨테이너 안에서는 같은 경로를 유지하거나 다른 경로를 고를 수 있지만, 경로는 VPN 클라이언트가 기대하는 것과 일치해야 합니다. /dev/net/tun 을 유지하면, 대부분의 클라이언트가 묻지 않고 그 경로를 열기 때문에 두 번째 구성 문제를 피할 수 있습니다.

관리자는 인스턴스가 시작할 때 또는 장치가 핫플러그될 때 항목을 적용합니다. 게스트에 드라이버를 복사하지 않고 터널 인터페이스를 만들지도 않습니다. 노드를 보이게 하고 컨테이너의 장치 제어 그룹을 통해 접근을 허용합니다.

장치는 게스트 안이 아니라 인스턴스에 선언하십시오

LXD 관리 컨텍스트에서 항목을 추가하고 인스턴스와 나중에 알아볼 레이블을 지정합니다. vpnbox 이라는 컨테이너라면 명령은 다음과 같습니다:

lxc config device add vpnbox tun unix-char source=/dev/net/tun path=/dev/net/tun
lxc config device show vpnbox

레이블 tun 은 인스턴스 구성에 국한됩니다. 인터페이스 이름이 아니며 게스트의 무엇과도 일치할 필요가 없습니다. 프로필이 이미 같은 장치를 제공한다면 두 번째 항목은 중복이 아니라 충돌을 만드므로, 먼저 유효한 구성을 확인하십시오.

컨테이너 안의 파일을 편집하는 것은 잘못된 계층입니다. 시작 스크립트의 mknod 은 권한 있는 컨테이너에서 동작하는 것처럼 보이다가 재생성 시 사라지거나 권한이 적은 컨테이너에서 실패할 수 있습니다. 인스턴스의 장치 집합은 관리자가 소유하므로 노드도 관리자가 소유하게 두십시오.

소유권과 모드를 게스트 프로세스에 맞추십시오

unix-char 항목은 컨테이너 안 노드에 uid, gid, mode 을 설정할 수 있습니다. 모든 사용자에게 장치를 열거나 컨테이너를 권한 모드로 바꾸는 대신, VPN 클라이언트를 실행하는 계정에 맞추는 데 사용하십시오.

가시성은 권한과 같지 않습니다. root 소유이고 모드 600인 노드는 비권한 사용자로 실행되는 서비스에 보이지만 그 서비스가 열 수는 없습니다. 먼저 게스트 계정을 확인하고, 그다음 소유권을 그 계정으로 설정하며, 모드는 클라이언트에 필요한 것보다 넓게 두지 마십시오.

프로세스에는 터널 인터페이스를 구성할 능력 도 필요하며, 보통 컨테이너의 네트워크 이름 공간에서 CAP_NET_ADMIN 입니다. 장치를 전달해도 그 능력이 생기지 않고, 능력을 부여해도 장치가 생기지 않습니다—둘은 독립된 요구 사항입니다.

항목이 주지 않는 것을 아십시오

보이는 노드가 동작하는 VPN은 아닙니다. 클라이언트 패키지를 여전히 설치해야 하고, 프로필은 여전히 유효해야 하며, 서비스는 여전히 시작해야 합니다. 인증, 경로, DNS는 계속 클라이언트의 일이며, 그곳의 실패는 장치 항목이 틀렸다는 증거가 아닙니다.

systemd가 또 다른 제한을 더할 수 있습니다. DeviceAllow 이나 강화된 장치 정책이 있는 유닛은 컨테이너 관리자가 제공한 노드에 대한 접근을 거부할 수 있습니다. 노드는 있으나 서비스가 권한 오류를 보고할 때 유닛의 장치 정책을 확인하고, 컨테이너를 넓히는 대신 그 정책을 바꾸십시오.

핫플러그는 선택 사항이며 명시적입니다. required=false 이 있는 항목은 소스 경로가 필요하고 호스트 장치가 바뀌면 나타나거나 사라질 수 있습니다. 그런 수명 주기는 들락날락하는 하드웨어에 맞지만, VPN이 부팅 시 필요로 하는 TUN 장치에는 선택적 항목이 전제 조건이 생기기 전에 서비스를 시작하게 둘 수 있습니다.

가시성, 열기, 인터페이스 순서로 확인하십시오

먼저 의도한 컨테이너 안의 노드를 확인합니다. 경로, 주 번호와 부 번호, 소유권은 호스트 장치와 추가한 항목에 맞아야 합니다. 노드가 없으면 관리자가 항목을 적용하지 않았거나 다른 인스턴스에 적용한 것입니다.

lxc exec vpnbox -- ls -l /dev/net/tun
lxc exec vpnbox -- sh -c 'test -c /dev/net/tun && echo char-device-ok'

다음으로 서비스 계정이 열 수 있는지 확인합니다. 그 계정으로 하는 짧은 시험은 소유권 문제와 서비스 문제를 분리합니다. 마지막으로 클라이언트를 시작하고 터널 인터페이스가 나타나는지 확인합니다—앞의 두 단계가 통과해도 클라이언트 프로필이나 능력이 아직 틀릴 수 있으므로 전체 경로를 증명하는 것은 그 세 번째 단계뿐입니다.

변경이 승인되면 인스턴스, 장치 레이블, 호스트 소스, 게스트 경로, 소유 계정을 기록하십시오. 그 다섯 값이 나중의 재생성, 마이그레이션 또는 프로필 변경이 보존해야 하는 것이며, 문맥 없는 권한 오류보다 훨씬 비교하기 쉽습니다.

관련 글