Demo: Use systemd directive OpenFile= to let Podman inherit an already connected Unix socket.
The systemd directive OpenFile=
was introduced in systemd 253 (released 15 February 2023).
Problem: A container process does not have file permissions to access a UNIX socket.
Solution: Start the container via systemd-run --property OpenFile=... ...
so that systemd connects to the UNIX socket. The container process inherits the established socket.
For example, OpenFile=
makes it possible to fetch a web page with libcurl in a container, even when the container user does not have enough file permission to access the UNIX socket of the web server. It works because systemd will connect to the UNIX socket and then let Podman inherit the file descriptor of the established socket. The container process inherits the same file descriptor.
stateDiagram-v2
systemd: systemd connects to UNIX socket (specified by OpenFile=)
systemd --> podman: socket inherited via fork/exec
state "OCI runtime" as s2
podman --> conmon: socket inherited via double fork/exec
conmon --> s2: socket inherited via fork/exec
s2 --> container: socket inherited via exec
Test 3 gives a demonstration of this.
-
systemd 253
-
podman
You could for instance use Fedora 38 or later. An easy way to try it out is to use Fedora CoreOS (stream = next) which already contains Fedora 38.
- Create the file ~/Caddyfile with the file contents
{ } http://localhost { bind unix//sockdir/sock respond "Hello world " }
- Run
mkdir ~/sockdir
- Run
The command creates the Unix socket ~/sockdir/sock that has the file permissions 755.
podman run \ --detach \ --name caddy \ --replace \ --rm \ -v ~/Caddyfile:/etc/caddy/Caddyfile:Z \ -v ~/sockdir:/sockdir:Z \ docker.io/library/caddy
Fetch a web page with curl (running as the container user root)
podman run \
--rm \
-v ~/sockdir:/sockdir:Z \
registry.fedoraproject.org/fedora \
curl \
--no-progress-meter \
--unix-socket /sockdir/sock \
http://localhost
The command outputs
Hello world
and exits successfully.
Fetch a web page with curl (running as the container user nobody (UID 65534 and GID 65534).
podman run \
--rm \
--user 65534:65534 \
-v ~/sockdir:/sockdir:Z \
registry.fedoraproject.org/fedora \
curl \
--no-progress-meter \
--unix-socket /sockdir/sock \
http://localhost
The command fails with the error message
curl: (7) Couldn't connect to server
The UNIX socket ~/sockdir/sock has file permissions 755. The user nobody inside the container, thus only has Read (4) and Execute (1) permissions.
The error
curl: (7) Couldn't connect to server
can be avoided if we set less restrictive file permissions, for example by running chmod 777 ~/sockdir/sock
.
Is there a way to download the web page as the container user nobody without changing the file permissions of the Unix socket? Yes, by using the systemd directive OpenFile=
(see Test 3).
The curl example program externalsocket.c demonstrates how libcurl can use an already established socket when accessing a web server.
The file externalsocket.c was adapted to make use of a UNIX socket file descriptor that originates from OpenFile=
- Build a container from the modified externalsocket.c
git clone https://github.com/eriksjolund/curl.git cd curl git switch externalsocket_openfile podman build -t demo docs/examples
- Fetch the web page as container user nobody
The command outputs:
systemd-run \ --quiet \ --property OpenFile=$HOME/sockdir/sock:fdnametest \ --user \ --collect \ --pipe \ --wait \ podman \ run \ --rm \ --user 65534:65534 \ localhost/demo fdnametest http://localhost
and exits successfully.Hello world