My previous article demonstrated that a socket-activated container can use an activated socket to serve the internet even when the network is disabled through the option --network=none
for podman run
. This article takes this idea one step further by also restricting internet access for Podman and its helper programs such as conmon and the OCI runtime.
To follow along with the examples, you must have:
- Podman 3.4.0 or above
- runc 1.1.3 or crun 1.5 or above
- container-selinux 2.183.0 or above (if you're using SELinux)
When using Podman in a systemd service, the systemd directive RestrictAddressFamilies can be used to restrict Podman's access to sockets. This restriction concerns only the use of the system call socket()
, meaning that socket-activated sockets are unaffected by the directive.
[ Download now: Podman basics cheat sheet ]
Podman can still run containers that need internet access only through socket-activated sockets when systemd is configured to restrict Podman's ability to use the system call socket()
for the AF_INET and AF_INET6 socket families. Podman would then be blocked from pulling any container images, so the container image must be present beforehand.
Restrict a socket-activated echo server
You can probably see how RestrictAddressFamilies
with a simple echo server container supports socket activation.
If the --pull=never
option is added to podman run
, the echo server container continues to work even with the very restricted setting:
RestrictAddressFamilies=AF_UNIX AF_NETLINK
All use of the system call socket()
is then disallowed except for the AF_UNIX sockets and AF_NETLINK sockets.
If there were a security vulnerability in Podman, conmon, or the OCI runtime, this configuration limits the avenues an intruder has to attempt to launch attacks on other devices on the network.
Create the systemd unit files
Create the container:
$ podman pull \
-q ghcr.io/eriksjolund/socket-activate-echo
6f68cb020b4b04e7d124df6c1bc60547e44b987223ac93d00515cc1412a7bc9a
$ podman create --rm --name restricted-echo \
--network=none --pull=never ghcr.io/eriksjolund/socket-activate-echo
f1f8ecd129c33012dac0be81dfdbd2a269295d322fd1ffd818fe8672ee0238ee
Generate the systemd service unit:
$ mkdir -p ~/.config/systemd/user
$ podman generate systemd --name \
--new restricted-echo > ~/.config/systemd/user/restricted-echo.service
Add the following two lines in the [Service]
section:
$ sed -i '/\[Service\]/a \
RestrictAddressFamilies=AF_UNIX AF_NETLINK\
NoNewPrivileges=yes' ~/.config/systemd/user/restricted-echo.service
Add the following two lines in the [Unit]
section:
$ sed -i '/\[Unit\]/a \
After=podman-usernamespace.service\
Requires=podman-usernamespace.service' ~/.config/systemd/user/restricted-echo.service
Create the file ~/.config/systemd/user/restricted-echo.socket
and paste this into it:
[Unit]
Description=restricted echo server
[Socket]
ListenStream=127.0.0.1:9000
[Install]
WantedBy=sockets.target
Create the file ~/.config/systemd/user/podman-usernamespace.service
with these contents:
[Unit]
Description=podman-usernamespace.service
[Service]
Type=oneshot
Restart=on-failure
TimeoutStopSec=70
ExecStart=/usr/bin/podman unshare /bin/true
RemainAfterExit=yes
Test the echo server
After editing the unit files, reload systemd:
$ systemctl --user daemon-reload
Next, start the socket unit:
$ systemctl --user start restricted-echo.socket
Finally, test the echo server with the program socat
:
$ echo hello | socat - tcp4:127.0.0.1:9000
hello
The echo server works as expected! It replies with hello after receiving the text hello.
Podman is blocked from establishing new connections to the internet, but everything works as expected because Podman is configured to not attempt to pull the container image.
[ Thinking about security? Check out this guide to boosting hybrid cloud security and protecting your business. ]
Now modify the service unit so that Podman always pulls the container image:
$ grep -- --pull= ~/.config/systemd/user/restricted-echo.service
--pull=never ghcr.io/eriksjolund/socket-activate-echo
$ sed -i s/pull=never/pull=always/ ~/.config/systemd/user/restricted-echo.service
$ grep -- --pull= ~/.config/systemd/user/restricted-echo.service
--pull=always ghcr.io/eriksjolund/socket-activate-echo
After editing the unit file, systemd needs to reload its configuration:
$ systemctl --user daemon-reload
Stop the service:
$ systemctl --user stop restricted-echo.service
Test the echo server with the program socat
:
$ echo hello | socat - tcp4:127.0.0.1:9000
As expected, the service fails because Podman is blocked from establishing a connection to the container registry.
Use journalctl
to see the related error message:
$ journalctl --user -xe -u restricted-echo.service | grep -A2 "Trying to pull" | tail -3
Jul 16 08:26:10 asus podman[28272]: Trying to pull ghcr.io/eriksjolund/socket-activate-echo:latest...
Jul 16 08:26:10 asus podman[28272]: Error: initializing source docker://ghcr.io/eriksjolund/socket-activate-echo:latest: pinging container registry ghcr.io: Get "https://ghcr.io/v2/": dial tcp 140.82.121.34:443: socket: address family not supported by protocol
Jul 16 08:26:10 asus systemd[10686]: test.service: Main process exited, code=exited, status=125/n/a
The service and socket are marked as failed
:
$ systemctl --user is-failed restricted-echo.service
failed
$ systemctl --user is-failed restricted-echo.socket
failed
Revert the change and use --pull=never
instead:
$ sed -i s/pull=always/pull=never/ \
~/.config/systemd/user/restricted-echo.service
$ systemctl --user daemon-reload
$ systemctl --user reset-failed restricted-echo.service
$ systemctl --user reset-failed restricted-echo.socket
$ systemctl --user start restricted-echo.socket
Use a separate service for creating the user namespace
Consider a situation where systemd starts the systemd user services for a user directly after a reboot. Assume that lingering has been enabled for the user with loginctl enable-linger USERNAME
and that the user is not logged in. The Podman systemd user service that starts first detects that the Podman user namespace is missing and tries to create it. This normally succeeds, but when RestrictAddressFamilies
is used together with rootless Podman, it fails.
The reason is that using RestrictAddressFamilies
in an unprivileged systemd user service implies NoNewPrivileges=yes. This prevents /usr/bin/newuidmap
and /usr/bin/newgidmap
from running with elevated privileges. Podman executes newuidmap
and newgidmap
to set up user namespace. Both executables normally run with elevated privileges, as they need to perform operations not available to an unprivileged user. These capabilities are:
$ getcap /usr/bin/newuidmap
/usr/bin/newuidmap cap_setuid=ep
$ getcap /usr/bin/newgidmap
/usr/bin/newgidmap cap_setgid=ep
You just need to set up the user namespace once because the created user namespace is reused for all other invocations of Podman. You can make services using RestrictAddressFamilies
or NoNewPrivileges=yes
work by configuring them to start after a systemd user service that is responsible for setting up the user namespace.
For instance, the unit restricted-echo.service
depends on podman-usernamespace.service
:
$ grep podman-usernamespace.service ~/.config/systemd/user/restricted-echo.service
After=podman-usernamespace.service
Requires=podman-usernamespace.service
The service podman-usernamespace.service
is a Type=oneshot
service that executes podman unshare /bin/true
. This command is normally used for other things, but a side effect of the command is that it sets up the user namespace.
[ Improve your skills managing and using SELinux with this helpful guide. ]
Enable the socket unit and reboot:
$ systemctl --user enable restricted-echo.socket
$ sudo reboot
After the reboot, test the echo server with the program socat
:
$ echo hello | socat - tcp4:127.0.0.1:9000
hello
The echo server works as expected even after a reboot!
Note that using the systemd directive RestrictAddressFamilies
to restrict Podman is probably not strictly supported in Podman, as it's not mentioned in Podman documentation.
Wrap up
The systemd directive RestrictAddressFamilies
provides a way to restrict network access for Podman and its helper programs, while a socket-activated echo server container can still serve the internet. One use case for this is running a socket-activated web server container so that Podman and its helper programs run with few privileges. If they are compromised due to a security vulnerability, the intruder would gain few privileges, having fewer opportunities to use the compromise as a starting point for attacks on other devices.
À propos de l'auteur
Erik Sjölund enjoys learning and discovering new things, especially within container technologies. He holds a master's degree in Engineering Physics and has worked as a Linux sysadmin and software developer, especially in the field of life sciences.
Parcourir par canal
Automatisation
Les dernières nouveautés en matière d'automatisation informatique pour les technologies, les équipes et les environnements
Intelligence artificielle
Actualité sur les plateformes qui permettent aux clients d'exécuter des charges de travail d'IA sur tout type d'environnement
Cloud hybride ouvert
Découvrez comment créer un avenir flexible grâce au cloud hybride
Sécurité
Les dernières actualités sur la façon dont nous réduisons les risques dans tous les environnements et technologies
Edge computing
Actualité sur les plateformes qui simplifient les opérations en périphérie
Infrastructure
Les dernières nouveautés sur la plateforme Linux d'entreprise leader au monde
Applications
À l’intérieur de nos solutions aux défis d’application les plus difficiles
Programmes originaux
Histoires passionnantes de créateurs et de leaders de technologies d'entreprise
Produits
- Red Hat Enterprise Linux
- Red Hat OpenShift
- Red Hat Ansible Automation Platform
- Services cloud
- Voir tous les produits
Outils
- Formation et certification
- Mon compte
- Assistance client
- Ressources développeurs
- Rechercher un partenaire
- Red Hat Ecosystem Catalog
- Calculateur de valeur Red Hat
- Documentation
Essayer, acheter et vendre
Communication
- Contacter le service commercial
- Contactez notre service clientèle
- Contacter le service de formation
- Réseaux sociaux
À propos de Red Hat
Premier éditeur mondial de solutions Open Source pour les entreprises, nous fournissons des technologies Linux, cloud, de conteneurs et Kubernetes. Nous proposons des solutions stables qui aident les entreprises à jongler avec les divers environnements et plateformes, du cœur du datacenter à la périphérie du réseau.
Sélectionner une langue
Red Hat legal and privacy links
- À propos de Red Hat
- Carrières
- Événements
- Bureaux
- Contacter Red Hat
- Lire le blog Red Hat
- L'inclusion chez Red Hat
- Cool Stuff Store
- Red Hat Summit