Is Docker really secure?

This article deals with the notion of security with Docker containers. While Docker has proved to be a boon for easing out deployment time and resources and significantly reduced compatibility problems, a lot needs to be discovered for securing the container environment.
Security concerned with Docker is not only limited to just securing the containers instantiated, but also to make sure that users who have container access are not able to interrupt with the host system at any cost.

Docker Security - Present Mindset

Most Docker users argue that Docker containers are secure as they are isolated and do not interrupt with the processes running on the host or on other containers. This argument is based on the fact that Docker uses the Linux namespaces and cgroups.

There are numerous ways in which Docker containers have exploited the security parameters. One such way is described in this post - Bypassing the Audit checks by Linux .

Before beginning, let’s throw some light on what auditing is.

Audit Feature in Linux

audit is an interesting security feature of the Linux kernel. Auditing helps the system administrators to trace every action on the Linux system by the means of logging. This trace is called an audit trail . We can track security-relevant events, record the events in a log file, and detect misuse of resources/data or unauthorized activities by inspecting the audit log files. Logging of events is generally done in a specific file called audit.log.

Audit does not provide additional security to your system, rather, it helps track any violations of system policies and enables you to take additional security measures to prevent them.

auditd is the Audit Daemon for Linux.

In a Ubuntu-based system, this package can be downloaded as such:

# apt install auditd

Install auditd

Now, let’s create a audit trail for /etc/shadow file. This is one of the most critical Linux files, as it saves the passwords of all Linux users. Though the passwords saved are hashed, it is essential to keep this file from getting compromised.

# auditctl -w /etc/shadow

This command inserts a ‘watch’ for the file /etc/shadow and would trace accesses or changes being done to the file.

Creating Audit Trails

Now, let’s try to modify this file - or just update the timestamp on it to experiment.

# touch /etc/shadow

To check the audit trail now, use ausearch command as such:

# ausearch -f /etc/shadow -i -ts recent

ausearch is a tool to query audit daemon logs. The option -f helps us to search for audit events for the filename specified. The option -i is used to resolve the UID into usernames. -ts option allows us to add timestamps to filter events. You can specify proper timestamps or just use keywords like today, now, recent, yesterday, this-week, etc.

Audit Trail produced when root 'touched' the /etc/shadow file

As you can see in the image, the uid and gid correspond to ‘root’. But, auid (Audit UID) shows ‘prashansa’. This is because I initially logged in as ‘prashansa’ user (not an administrative user) and then switched to root using ‘su - root’ command. Thus, the trail clearly depicts that initial process is owned by ‘prashansa’ user and /etc/shadow file is modified with the power of ‘root’ user.

We can also touch the file from ‘prashansa’ user and check the audit trails again.

Audit trails after prashansa user 'touched' /etc/shadow file

In this image, you can see that auid, uid and gid all point to ‘prashansa’ user.

How does this tracking occur?

There is a field called loginuid, stored in /proc/self/loginuid, that is part of the proc struct of every process on the system. This field can be set only once; after it is set, the kernel will not allow any process to reset it.

So, whichever user you become using su command, this id will remain same.

# cat /proc/self/loginuid

Below images clearly depict that loginuid of both root and prashansa is 1000.

loginuid of root

loginuid of prashansa user

Every process that is forked and executed from the initial login process automatically inherits this loginuid. This is how Linux kernel identifies that the person who logged was ‘prashansa’ user.

Now, let’s jump to Docker containers and see how they use this feature.

Docker Containers and Auditing

Let’s check what login id we get, when we run the same command inside a docker container. loginuid from inside fedora container

The default loginuid of all processes (before their loginuid is set) is 4294967295. Since the container is instantiated by the Docker daemon and the Docker daemon is a child of the init system, we see that systemd, Docker daemon, and the container processes all have the same loginuid, 4294967295.

How will this affect audit trail? Let’s check.

# docker run --privileged -v /etc/shadow:/etc/shadow fedora touch /etc/shadow

We have mounted our shadow file to docker container and touched it from the container. Let’s check the audit.

# ausearch -f /etc/shadow -i

Audit Trail is unset

Modify file contents from the container.

Before modifying anything, please save the original file contents to some other file to avoid the loss, since /etc/shadow is a very important file for our Linux system. Without this, we will be locked out of our systems.

# cat /etc/shadow > shadowdup
# docker run --privileged -v /etc/shadow:/etc/shadow fedora echo "hello world" >> /etc/shadow

Now, check the contents of file from host system.

# cat /etc/shadow

File contents changed

This activity also leaves no identity source behind, which is a major security flaw.

As the auid remains unset, a System Administrator can never find out who changed the concerned file. Note that no audit trail (no log - not even auid unset log) is added for mounting the file to the container as well.

Why does this happen?

This is because of the architecture which Docker follows, that is, Server-Client Model in which the Docker Daemon acts as the server and is responsible for launching containers, when requested by the client. The daemon process starts as a child of init (the parent of all processes) and hence inherits the loginuid. All containers, started as the child of the daemon, inherit the same uid.

Is this solvable?

Well, we obviously can not change the architecture of Docker to resolve this issue. We need some other alternative to record the activities done to the file system from inside the container. Currently, I am not proposing any solution for this but would surely do in future if I think of something.

Any Alternative to Docker which doesn’t have this Security Flaw?

Yes, Podman by Red Hat. It works on a fork/execute model and hence takes up the loginuid of the user. All podman containers take up the same loginuid and hence, it is easier to trace the defaulter.

Contributor

Prashansa Kulshrestha