root 를 주지 않고 OpenVPN 에 CAP_NET_ADMIN 부여하기
권한 없는 사용자로 시작하는 유닛도 올바른 기능 집합이 필요합니다. 유닛, 실행 중인 프로세스, exec 경계를 이 순서대로 확인하십시오.
서비스는 시작되지만 로그는 tun 장치를 열 수 없다고 불평하고 경로는 끝내 나타나지 않습니다. 자신의 셸에서 capsh --print 를 실행하면 cap_net_admin 가 바로 거기에 있어 실패가 불가능해 보입니다. 셸과 유닛 사이에서 다른 것은 권한 전이이며, 커널이 기능을 주려는 의지가 아닙니다. 아래 네 가지 점검을 순서대로 수행하고 차이를 설명하는 첫 점검에서 멈추십시오.
빠진 기능과 숨겨진 장치를 구분하십시오
로그 줄만 보면 두 실패는 같아 보입니다. CAP_NET_ADMIN 가 없는 프로세스는 터널 인터페이스를 만들거나 설정할 수 없고, 샌드박스가 /dev/net/tun 를 숨기는 프로세스는 애초에 열 수 없습니다. 기능을 더한다고 두 번째 경우가 고쳐지지 않습니다.
무엇이든 편집하기 전에 장치가 서비스의 이름 공간 안에 있는지 확인하십시오. PrivateDevices=yes 는 tun 노드를 완전히 제거하는 흔한 강화 줄이고, 제한적인 ProtectSystem 는 설정 경로를 권한 오류처럼 읽히는 방식으로 읽기 전용으로 만들 수 있습니다. 둘 다 터널을 언급하는 로그 줄을 만들기 때문에 기능이 비난을 받습니다. 먼저 노드가 있고 열 수 있는지 확인한 다음 넘어가십시오.
어떤 기능 집합을 보고 있는지 아십시오
Linux 는 허용·유효·상속·경계·앰비언트 집합을 유지하며, 비 root 사용자의 exec 를 견디는 것은 앰비언트 집합입니다. 바이너리의 파일 기능은 exec 시 허용 및 유효 권한을 넘길 수 있지만, 사슬 어디에서도 그 이전을 막지 않을 때만 가능합니다.
여기서 sudo 가 사람들을 오도합니다. sudo -u 를 통해 실행한 명령은 새 권한 전이를 시작하고 앰비언트 집합이 사라지므로, root 로 성공하는 같은 점검이 그곳에서는 실패합니다. 서비스 관리자도 또 다른 전이이며, 유닛이 그렇게 말하지 않으면 앰비언트를 아무것도 주지 않습니다.
기능은 래퍼가 아니라 유닛에서 부여하십시오
장치를 만들고 경로를 설치해야 하는 터널을 위한 최소 서비스 섹션은 다음과 같습니다.
[Unit]
Description=OpenVPN client, office profile
After=network-online.target
[Service]
Type=notify
User=openvpn
Group=openvpn
NoNewPrivileges=yes
AmbientCapabilities=CAP_NET_ADMIN
CapabilityBoundingSet=CAP_NET_ADMIN
ExecStart=/usr/sbin/openvpn --config /etc/openvpn/office.confAmbientCapabilities 는 프로세스가 시작되기 전에 권한을 앰비언트 집합에 넣고, CapabilityBoundingSet 는 프로세스가 그 목록 밖의 것을 보유하지 못하게 합니다. NoNewPrivileges=yes 는 setuid 나 파일 기능을 통한 권한 획득을 막고, 유닛이 명시적으로 부여한 기능은 그대로 적용됩니다. CAP_NET_BIND_SERVICE 는 서비스가 낮은 포트를 묶어야 할 때만 추가하고, 포럼 스레드가 그렇게 했다는 이유만으로 CAP_SYS_ADMIN 를 절대 추가하지 마십시오.
유닛이 바이너리를 sudo 로 감싼다면 래퍼를 제거하십시오. systemd 는 이미 User= 를 적용하며, 그 추가 계층이 앰비언트 집합을 비게 만든 가장 유력한 이유입니다.
유닛 파일이 아니라 실행 중인 프로세스로 검증하십시오
관리자가 실제로 무엇을 적용했는지 읽고, 그다음 그것이 만든 프로세스를 읽으십시오.
unit=openvpn-client@office
systemctl show -p User -p AmbientCapabilities "$unit"
systemctl show -p MainPID --value "$unit" | xargs -r getpcaps
grep -E '^Cap(Eff|Amb)' /proc/$(systemctl show -p MainPID --value "$unit")/status유닛이 기능을 나열하는데 CapEff 에 아직 없다면, 어떤 drop-in 이 설정을 덮어쓰거나 ExecStartPre 단계가 환경을 바꾸고 있습니다. 나중 파일이 조용히 이기므로 기본 파일이 권위 있다고 가정하기 전에 drop-in 디렉터리에서 유닛 이름을 찾으십시오. 유닛과 프로세스가 모두 기능을 보여 주는데 터널이 여전히 실패한다면, 경계 집합을 넓히는 대신 장치와 경로 점검으로 돌아가십시오. 넓히면 진짜 원인이 가려지고 서비스는 이전보다 더 많은 권한을 가진 채 남습니다.
시작 후 권한을 내려놓는 편을 택하십시오
OpenVPN 는 권한을 가지고 시작한 뒤 자체 user 및 group 옵션으로 권한 없는 계정으로 내려갈 수 있으며, persist-key 와 persist-tun 가 그 뒤에도 터널을 쓸 수 있게 유지합니다. 이런 배치는 프로세스가 권한을 쥐는 시간을 좁히며, 영구 기능을 가진 채 데몬 전체를 권한 없이 시작하는 것보다 자주 더 적합합니다.
대화형 root 셸에서는 동작하지만 부팅 시 실패하는 서비스는 보통 기능, 장치, 파일 권한 중 하나의 차이이므로, 어떤 모델을 고르든 유닛을 다시 시작하고 재부팅 후 같은 점검을 반복하십시오. 유닛 설정을 프로세스의 기능 출력 옆에 기록해 두어 다음 검토자가 패키지 업데이트나 drop-in 이 경계를 옮겼는지 볼 수 있게 하십시오.