podman: rootless container: permissions for container user
In nginx
podman container nginx
user is used to run nginx
server.
On the host machine ls -alh
:
drwxrwx--- 2 myuser myuser 4.0K Aug 10 22:23 .
drwxrwx--- 3 myuser myuser 4.0K Aug 10 22:59 ..
-rw-rw---- 1 myuser myuser 46 Aug 10 22:24 .htpasswd
The same folder inside container ls -alh
:
drwxrwx--- 2 root root 4.0K Aug 10 22:23 .
drwxr-xr-x 1 root root 4.0K Aug 10 11:05 ..
-rw-rw---- 1 root root 46 Aug 10 22:24 .htpasswd
nginx
user inside container can't access .htpasswd
because of o-rwx
.
Question: what is the commonly used pattern to handle this kind of cases in rootless container universally? Maybe it is possible to create group (used later as file-group owner) which gathers all ranges from subuid
/subgid
for particular host user - but how to achieve this?
Solution 1:
By using the command-line option --uidmap
you can specify how the myuser UID and the myuser sub UIDs are mapped into the container.
(See the man page for podman run
).
The command-line option --gidmap
works in the same way but for GIDs instead of UIDs.
Let's look up the UID and GID for the user nginx in the container image docker.io/library/nginx
$ podman run --rm docker.io/library/nginx grep nginx /etc/passwd
nginx:x:101:101:nginx user,,,:/nonexistent:/bin/false
$
Result:
- UID: 101
- GID: 101
The numbers are later used when setting two shell variables
$ container_uid=101
$ container_gid=101
(The shell variables container_uid and container_gid don't have any meaning outside this post. They are just introduced to make the answer easier to read)
Take a look in the files /etc/subuid and /etc/subgid on the host
The user myuser has these sub UIDs and sub GIDs.
$ grep myuser /etc/subuid
myuser:231072:65536
$ grep myuser /etc/subgid
myuser:231072:65536
$
Result:
myuser has 65536 sub UIDs and 65536 sub GIDs.
The numbers are later used when setting two shell variables
$ subuid_size=65536
$ subgid_size=65536
(The shell variables subuid_size and subgid_size don't have any meaning outside this post. They are just introduced to make the answer easier to read)
Instead of looking up subuid_size and subgid_size in /etc/subuid and /etc/subgid, a more general method is to run the commands
subuid_size=$(( $(podman info --format "{{ range .Host.IDMappings.UIDMap }}+{{.Size }}{{end }}" ) - 1 ))
subgid_size=$(( $(podman info --format "{{ range .Host.IDMappings.GIDMap }}+{{.Size }}{{end }}" ) - 1 ))
The advantage is that this also works when the file /etc/nsswitch.conf is used instead of /etc/subuid and /etc/subgid. (See man subuid
)
Demo 1: map the user myuser on the host to the user root inside the container
There is no need to specify --uidmap
nor --gidmap
because this is the standard mapping.
Create the world writable directory demo1
$ mkdir demo1
$ chmod 777 demo1
$
Create a new file, running as root inside the container:
$ podman run --rm \
-v ./demo1:/dir:Z \
docker.io/library/nginx touch /dir/created_by_root
$
Create a new file, running as nginx inside the container:
$ podman run --rm \
--user 101:101 \
-v ./demo1:/dir:Z \
docker.io/library/nginx touch /dir/created_by_nginx
$
List the files on the host
$ ls -l demo1
total 0
-rw-r--r--. 1 231172 231172 0 Aug 27 20:24 created_by_nginx
-rw-r--r--. 1 myuser myuser 0 Aug 27 20:22 created_by_root
$
Result: The file created_by_root is owned by myuser:myuser
Demo 2: map the user myuser on the host to the user nginx inside the container
Create the world writable directory demo2
$ mkdir demo2
$ chmod 777 demo2
$
Create a new file, running as root inside the container:
$ subuid_size=65536
$ subgid_size=65536
$ container_uid=101
$ container_gid=101
$ podman run --rm \
--uidmap=0:1:$container_uid \
--uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \
--uidmap=$container_uid:0:1 \
--gidmap=0:1:$container_gid \
--gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \
--gidmap=$container_gid:0:1 \
-v ./demo2:/dir:Z \
docker.io/library/nginx touch /dir/created_by_root
$
Create a new file, running as nginx inside the container.
$ subuid_size=65536
$ subgid_size=65536
$ container_uid=101
$ container_gid=101
$ podman run --rm \
--user $container_uid:$container_gid \
--uidmap=0:1:$container_uid \
--uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \
--uidmap=$container_uid:0:1 \
--gidmap=0:1:$container_gid \
--gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \
--gidmap=$container_gid:0:1 \
-v ./demo2:/dir:Z \
docker.io/library/nginx touch /dir/created_by_nginx
$
List the files on the host
$ ls -l demo2
total 0
-rw-r--r--. 1 myuser myuser 0 Aug 27 20:26 created_by_nginx
-rw-r--r--. 1 231072 231072 0 Aug 27 20:25 created_by_root
$
Result: The file created_by_nginx is owned by myuser:myuser
Conclusion
Use --uidmap
and --gidmap
in the same way as in Demo 2.