257 | | 1. install podman (https://podman.io/getting-started/installation) |
258 | | 2. Create Dockerfile (as target unprivileged user) |
259 | | |
260 | | {{{ |
261 | | FROM archlinux |
262 | | RUN pacman -Sy --noconfirm openvpn |
263 | | }}} |
264 | | |
265 | | 3. Build image (as target unprivileged user) |
266 | | |
267 | | {{{ |
268 | | podman build -t openvpn . |
269 | | }}} |
270 | | |
271 | | 4. Create systemd openvpn.service file (as root) |
272 | | |
273 | | {{{ |
| 257 | 1. Install podman (https://podman.io/getting-started/installation) |
| 258 | |
| 259 | 2. Create unprivileged user |
| 260 | |
| 261 | {{{ |
| 262 | useradd -m openvpn |
| 263 | # Automatically start-up systemd user instances |
| 264 | loginctl enable-linger openvpn |
| 265 | }}} |
| 266 | |
| 267 | 3. Create directories where configuration, certificates and entrypoint script will be stored |
| 268 | |
| 269 | {{{ |
| 270 | mkdir -p /opt/openvpn/server/{ssl,status,ccd} |
| 271 | }}} |
| 272 | |
| 273 | 4. Make systemd-networkd to create tun0 which will be required by openvpn in later step |
| 274 | |
| 275 | {{{ |
| 276 | cat > /etc/systemd/network/21_openvpn.tun0.netdev<<EOF |
| 277 | [NetDev] |
| 278 | Name=tun0 |
| 279 | Kind=tun |
| 280 | |
| 281 | [Tun] |
| 282 | User=openvpn |
| 283 | Group=openvpn |
| 284 | EOF |
| 285 | |
| 286 | cat > /etc/systemd/network/22_openvpn.tun0.network<<EOF |
| 287 | [Match] |
| 288 | Name=tun0 |
| 289 | |
| 290 | [Network] |
| 291 | Address=10.254.254.1/24 |
| 292 | |
| 293 | #KeepConfiguration=yes |
| 294 | #BindCarrier=yes |
| 295 | #CriticalConnection=yes |
| 296 | |
| 297 | ConfigureWithoutCarrier=yes |
| 298 | IgnoreCarrierLoss=yes |
| 299 | IPForward=yes |
| 300 | |
| 301 | [Link] |
| 302 | MTUBytes=1500 |
| 303 | EOF |
| 304 | |
| 305 | systemctl restart systemd-networkd |
| 306 | }}} |
| 307 | |
| 308 | 5. Use easy-rsa to create your CA authority and all required certificates, at the end of this step you should create ca.crt, ta.key, dh.pem, crl.pem, your_server.key, your_server.crt - copy everything to /opt/openvpn/server/ssl |
| 309 | |
| 310 | 6. Create /opt/openvpn/server/server.conf - at least following keys should match (below is not a complete conf file, only key options are mentioned) |
| 311 | |
| 312 | {{{ |
| 313 | dev tun0 |
| 314 | ca /server/ssl/ca.crt |
| 315 | cert /server/ssl/your_server.crt |
| 316 | key /server/ssl/easy-rsa/pki/private/your_server.key |
| 317 | crl-verify /server/ssl/crl.pem |
| 318 | dh /server/ssl/dh.pem |
| 319 | tls-auth /server/ssl/ta.key 0 |
| 320 | server 10.254.254.0 255.255.255.0 |
| 321 | }}} |
| 322 | |
| 323 | 7. Ensure /opt/openvpn is owned by and can be read only by openvpn:openvpn |
| 324 | |
| 325 | 8. Create systemd openvpn.service file (as root) |
| 326 | |
| 327 | {{{ |
| 328 | cat > /etc/systemd/system/openvpn.service<<EOF |
280 | | User=target_unprivileged_user |
281 | | Group=target_unprivileged_group |
282 | | ExecStart=/usr/bin/podman run --rm -v /home/target_unprivileged_user/ovpn_config_files/:/ovpn_config_files -p 56787:56787 --device /dev/net/tun --device /dev/null --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 /ovpn_config_files/openvpn_server.conf |
283 | | ExecStop=/usr/bin/podman stop -t 0 localhost/openvpn:latest |
284 | | 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 |
| 335 | User=openvpn |
| 336 | Group=openvpn |
| 337 | DeviceAllow=/dev/null rw |
| 338 | DeviceAllow=/dev/net/tun rw |
| 339 | AmbientCapabilities=CAP_MKNOD 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 |
| 340 | WorkingDirectory=/opt/openvpn |
| 341 | ExecStart=/usr/bin/podman run --rm --name openvpn -v /opt/openvpn/server:/server --network="host" -p 37898:37898 --device /dev/net/tun --device /dev/null --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 archlinux:latest /usr/bin/bash /server/entrypoint.sh |
| 342 | ExecStop=/usr/bin/podman stop -t 0 openvpn |
| 343 | ProtectSystem=true |
290 | | }}} |
291 | | |
292 | | 5. Drop configuration (openvpn-server.conf) and other required files under /home/target_unprivileged_user/ovpn_config_files, configuration file should have paths relative to podman container (/ovpn_config_files, not /home/target_unprivileged_user/ovpn_config_files); Also note port exposed within systemd service is 56787 (either keep this in mind when writing your configuration file or change systemd service file) |
293 | | |
294 | | 6. Make sure systemd for openvpn user is always started and kept (otherwise podman won't start) |
295 | | {{{ |
296 | | loginctl enable-linger openvpn |
297 | | }}} |
298 | | |
299 | | 7. Start the service (as root) - this will result in podman container running as target_unprivileged_user, openvpn port exposed and openvpn available to receive connections |
| 350 | EOF |
| 351 | }}} |
| 352 | |
| 353 | 9. Create /opt/openvpn/server/entrypoint.sh |
| 354 | |
| 355 | {{{ |
| 356 | cat > /opt/openvpn/server/entrypoint.sh<<EOF |
| 357 | #!/bin/bash |
| 358 | |
| 359 | pacman -Sy --noconfirm openvpn net-tools nano |
| 360 | |
| 361 | # we have done all required network configuration so openvpn does not have to |
| 362 | cp -p /usr/bin/ip /usr/bin/ip.bak |
| 363 | echo "#!/bin/bash" > /usr/bin/ip |
| 364 | echo 'echo "$@" >> /tmp/ip_res' >> /usr/bin/ip |
| 365 | echo "exit 0" >> /usr/bin/ip |
| 366 | chmod ugo+x /usr/bin/ip |
| 367 | |
| 368 | openvpn --cd /server --config /server/server.conf |
| 369 | |
| 370 | EOF |
| 371 | |
| 372 | chmod ugo+x /opt/openvpn/server/entrypoint.sh |
| 373 | }}} |
| 374 | |
| 375 | 10. Start the service (as root) - this will result in podman container running as openvpn user |