我正在尝试在 podman 非特权容器中运行 openvpn 服务器。
Openvpn 需要能够管理网络接口(即创建 tun 接口,为其分配 IP 地址,启动它)。在我的系统(arch linux)上,openvpn-server.service
我注意到CapabilityBoundingSet
这让我尝试并创建自己的服务,而不是运行 openvpn,而是运行podman run
.
首先我创建了我的 openvpn 容器,下面是 Dockerfile(为方便起见,我使用 archlinux 作为基础):
FROM archlinux
RUN pacman -Sy --noconfirm openvpn
然后我构建这个容器(登录为my_unprivileged_user
)
podman build \
--force-rm \
--no-cache \
--rm \
--device=/dev/net/tun \
-t openvpn .
然后我创建了my_custom_openvpn.service
:
Description=OpenVPN in Podman container
After=syslog.target network-online.target
Wants=network-online.target
[Service]
User=my_unprivileged_user
Group=my_unprivileged_group
WorkingDirectory=/etc/openvpn
ExecStart=/usr/bin/podman run --rm --name openvpn -v ./server:/server --device /dev/net/tun --network "host" --cap-add CAP_IPC_LOCK,CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SETGID,CAP_SETUID,CAP_SYS_CHROOT,CAP_DAC_OVERRIDE,CAP_AUDIT_WRITE localhost/openvpn:latest /usr/bin/openvpn --config /server/my_config.conf
ExecStop=/usr/bin/podman stop -t 0 openvpn
Capabilities=CAP_IPC_LOCK CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_DAC_OVERRIDE CAP_AUDIT_WRITE
DeviceAllow=/dev/null rw
DeviceAllow=/dev/net/tun rw
#ProtectSystem=true
#ProtectHome=true
RestartSec=5s
Restart=on-failure
TimeoutSec=5s
[Install]
WantedBy=multi-user.target
所以我认为 systemd 会将功能传递给 podman,而后者又会将它们进一步向下传递给 openvpn。
但是 openvpn 无法开始抱怨它无法创建 tun0 接口。即使我像这样自己创建 tun0,我openvpn --mktun --dev tun0
也会收到另一个错误,即 openvpn 无法设置此 tun0 接口。
我想也许我需要setcap
在容器内做,所以我podman exec
进入它并在下面执行:
setcap CAP_IPC_LOCK,CAP_NET_ADMIN,CAP_NET_BIND_SERVICE,CAP_NET_RAW,CAP_SETGID,CAP_SETUID,CAP_SYS_CHROOT,CAP_DAC_OVERRIDE,CAP_AUDIT_WRITE=+ep /usr/bin/openvpn
但这并没有帮助。我不断收到此错误:
Tue Jan 28 13:34:31 2020 /usr/bin/ip link set dev tun0 up mtu 1500
RTNETLINK answers: Operation not permitted
也许尝试使用这样的功能没有意义?
我设法通过在容器内用总是返回 0 的 bash 脚本替换来让 openvpn 工作。
ip
我认为 openvpn 尝试做的唯一事情就是设置tun0
然后为其分配 IP 地址并启动它。我决定从容器外部(以 root 身份)手动执行此操作,因此 openvpn 不必这样做。我在这里描述了 openvpn wiki 上的过程