Podman Rootless Container and Rootful container

Rootless Container in Podman

Containers in podman can be started by the root user or by an unprivileged user.  Ability to run containers in a non root environment  is quite unique when compared to docker. In both cases, the container is started with its own user namespaces, having its own /etc/passwd and /etc/shadow files with in the container. Many containers run processes inside the container as root, but this is not recommended. To run containers as a different UID inside the container, we can use -u username  option while starting the container, or use container images that specify which user to use. Rootless containers are much more secure that rootfull containers. Rootless containers do not get an IP address, and cannot bind to a privileged port. Rootless containers will have limited access to the file system. When using a rootless container, the container is started by a non-privileged user, while processes within the container may still have root privileges. The processes which are running as root in a rootless container will not have any host access privileges. An alternative solution is to use a rootless container with a non-root user in the container, which is the most secure option

Container run options

In this article, we will explore different container run options and its behavior. Below is the possible combination of the same

  • A Root container, running a root process in the container, this is most unsecure
  • A Root container, running a non-root process in the container, this is little more secure than the above, but not as secure as below options
  • Rootless container, running a root process in the container
  • Rootless container, running a non-root process in the container

Root Container in Podman with Root process: Demo

  • Run a centos container using the podman run command. For running the container in root, we executed podman run command as root user
[root@localhost ~]# podman run -it centos sh
sh-4.4# whoami
root
  • It can be seen that, whoami command is returning root user, which shows the  container is running with root
  • Create a sleep process and view the process with ps aux 
sh-4.4# sleep 1000 &
[1] 7
sh-4.4# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 17:28 pts/0 00:00:00 sh
root 7 1 0 17:29 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
root 8 1 0 17:29 pts/0 00:00:00 ps -ef
  • Come out of the container using Ctrl+P and Ctrl+Q; Make sure, Ctrl+D or exit is not pressed
  • Once you are on the host machine, find the process sleep which was initiated by the container
  • It can be seen that the process is running as root user. This is because of the rootfull container
[root@localhost ~]# ps -ef|grep sleep
root 11456 11442 0 22:59 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000

Rootless Container in Podman with Root process: Demo

  • Run a centos container using the podman run. But to create a rootless container, we need to execute the command as a non-root user.
  • Below code snippet shows the container started as a non-root user "abhi"
[abhi@localhost ~]# podman run -it centos sh
sh-4.4# whoami
root
  • It can be seen that, whoami command is returning root user, which shows the container is running with root
  • Even though the container is started as a non-root user, the process or user inside the container will be root user or root owned process
  • Create a sleep process and view the process with ps aux 
sh-4.4# sleep 1000 &
[1] 7
sh-4.4# ps -ef
UID PID PPID C STIME TTY TIME CMD
root 1 0 0 17:28 pts/0 00:00:00 sh
root 7 1 0 17:29 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
root 8 1 0 17:29 pts/0 00:00:00 ps -ef
  • Come out of the container using Ctrl+P and Ctrl+Q; Make sure, Ctrl+D or exit is not pressed
  • Once you are on the host machine, find the process sleep which was initiated by the container
  • It can be seen that the process is running as abhi user which is a non-root user
[root@localhost ~]# ps -ef|grep sleep
abhi 11456 11442 0 22:59 pts/0 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
  • From the above exercise we can see that, the process sleep is running as a root user inside the container. But from host operating system point of view, it can be seen that the process sleep is running as non-root user
  • In conclusion, even if the process is running as root, it will be harmless to the host operating system, which makes this approach more secure

RootContainer in Podman with non-root process: Demo

  • We will run a root container (with root user) with a non-root process. We will run a centos podman, but we will specify a user id while creating the container
[root@localhost ~]# podman run -it -u 27 centos sh
sh-4.4$ whoami
27
  • From the above code snippet, it can be seen that the user is user with uid 27
  • We will create a sleep process and will view the processlist
sh-4.4$ sleep 1000 &
[1] 7
sh-4.4$ ps aux|grep sleep
27 7 0.0 0.0 23028 1384 pts/0 S 16:26 0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
27 9 0.0 0.0 9188 1084 pts/0 S+ 16:26 0:00 grep sleep
  • Come out of the container using Ctrl+P and Ctrl+Q; Make sure, Ctrl+D or exit is not pressed
  • Once you are on the host machine, find the process sleep which was initiated by the container
  • It can be seen that the process is running as user  with uid 27
 [root@localhost ~]# ps aux|grep sleep
27 20525 0.0 0.0 23028 1384 pts/0 S 21:56 0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 1000
root 20530 0.0 0.0 221936 1176 pts/1 S+ 21:56 0:00 grep --color=auto sleep

Rootless Container with a non-root process: Demo

  • We will run a rootless container (with user abhi), but with a user id.  For running a rootless container, we will execute the podman run with non-root user and will specify user with which the container to run using -u  option
[abhi@localhost root]$ podman run -it -u 27 centos sh
sh-4.4$ whoami
27
  • The above code snippet shows the user id with which the container is running
  • Identify the the sleep 3000 process we started, it can be seen that it is running with the user id 27
sh-4.4$  sleep 3000 &
sh-4.4$ ps aux|grep sleep
27 7 0.0 0.0 23028 1312 pts/0 S 16:46 0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3000
27 9 0.0 0.0 9188 1092 pts/0 S+ 16:46 0:00 grep sleep
  • Come out of the container using Ctrl+P and Ctrl+Q; Make sure, Ctrl+D or exit is not pressed
  • Verify the process from the host machine, it can be see that the process sleep is running with a userid as 166562 which is a Mac User ID
[abhi@localhost root]$ ps aux|grep sleep
abhi 20352 0.0 0.0 23028 1284 pts/0 S 21:45 0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 2000
165562 20788 0.0 0.0 23028 1312 pts/0 S 22:16 0:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 3000
root 20798 0.0 0.0 217080 888 ? S 22:16 0:00 sleep 60
abhi 20801 0.0 0.0 221936 1168 pts/1 S+ 22:17 0:00 grep --color=auto sleep
  • Rootless container running a non process cannot map the process to a user id, which is why a user id is generated dynamically

Ip Address Allocation

  • If a container is running as non-root user, then the container will not be assigned with an IP Address
  • If a container is running as a root user, means if the container is rootfull container, then it will get an IP Address assigned
  • Below code snippet shows, the containers (rootless/rootfull) container which we have created for above exercises. It can be seen that the rootfull container is having IP Address assigned to it
[abhi@localhost root]$ podman inspect dc37a15820d3 -f "{{.NetworkSettings.IPAddress}}"

[root@localhost ~]# podman inspect 6bbd20d3dd7d -f "{{.NetworkSettings.IPAddress}}"
10.88.0.8

Podman Networking of Root containers

  • When a container is running with root privileges, we can see that a new device CNI will get created in the host machine.
  • If we list the interface of the host machine, where a container is running with root privileage, we can see the below output
[root@localhost ~]# ifconfig
cni-podman0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.88.0.1 netmask 255.255.0.0 broadcast 10.88.255.255
inet6 fe80::b46a:38ff:fe14:7cab prefixlen 64 scopeid 0x20<link>
ether b6:6a:38:14:7c:ab txqueuelen 1000 (Ethernet)
RX packets 132 bytes 8012 (7.8 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 84 bytes 7917 (7.7 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

enp0s8: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 10.0.3.15 netmask 255.255.255.0 broadcast 10.0.3.255
inet6 fe80::8ce4:efc4:6f09:6811 prefixlen 64 scopeid 0x
<trimmed>
vethcd4b5523: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet6 fe80::cc8a:98ff:fef1:c8ec prefixlen 64 scopeid 0x20<link>
ether ce:8a:98:f1:c8:ec txqueuelen 0 (Ethernet)
RX packets 45 bytes 3202 (3.1 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 197 bytes 17755 (17.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
  • It can be seen that a virtualization bridge cni-podman0 is created. This is required by the root container to use an IP address
  • It can be seen that a Veth interface is also added, it is like other side of the patch cable that is used by the IP address in the container.
  • From the above exercise, we got to know that our containers ip address is 10.88.0.8, and our cni-podman bridge address is 10.88.01. This bridge will  behaves like a net routes, which allows the container to talk to outside world
  • Compared to the root container, rootless container don't get an ip address, Hence their communication will happen via its port address

Visualization of Rootfull container Networking

  • Below block diagram shows the networking visualization of root container which is explained in the above section

podman rootless and rootfull containers

  • In the host machine, a new device called CNI ( common network interface ) will get created, in our case it is cni-podman0
  •  This CNI network will act as a networking bridge, and to one side of this bridge it will be connected to eth0, and to the other side we can see that it is connected with Vethx
  • Container will be bind to the Vethx, and will get an ip address from its internal network card. Because of the container will have no restriction binding to a privileged port

Visualization of Rootless container Networking

  • Below block diagram shows the networking of a rootless container on a host machine in a high level view

podman rootless and rootfull containers

  • On a host machine, the communication to external world happens via eth0 interface.
  • The rootless container, who doesn't have an ip address assigned to it, will have to bind to non-privileges ports and then will continue to use the eth0 interface
  • Rootless container, itself cannot bind to privileged ports. This can be considered as one of the disadvantages of rootless container

Read More

Container Architecture

Podman Official Docs

 

Search on LinuxDataHub

Leave a Comment