Home » What makes Docker more secure than VMs or bare metal?

What makes Docker more secure than VMs or bare metal?


No, Docker containers are not more secure than a VM.

Quoting Daniel Shapira:

In 2017 alone, 434 linux kernel exploits were found, and as you have seen in this post, kernel exploits can be devastating for containerized environments. This is because containers share the same kernel as the host, thus trusting the built-in protection mechanisms alone isn’t sufficient.

1. Kernel exploits from a container

If someone exploits a kernel bug inside a container, they exploited it on the host OS. If this exploit allows for code execution, it will be executed on the host OS, not inside the container.

If this exploit allows for arbitrary memory access, the attacker can change or read any data for any other container.

On a VM, the process is longer: the attacker would have to exploit both the VM kernel, the hypervisor, and the host kernel (and this may not be the same as the VM kernel).

2. Resource starvation

As all the containers share the same kernel and the same resources, if the access to some resource is not constrained, one container can use it all up and starve the host OS and the other containers.

On a VM, the resources are defined by the hypervisor, so no VM can deny the host OS from any resource, as the hypervisor itself can be configured to make restricted use of resources.

3. Container breakout

If any user inside a container is able to escape the container using some exploit or misconfiguration, they will have access to all containers running on the host. That happens because the same user running the docker engine is the user running the containers. If any exploit executes code on the host, it will execute under the privileges of the docker engine, so it can access any container.

4. Data separation

On a docker container, there’re some resources that are not namespaced:

  • SELinux
  • Cgroups
  • file systems under /sys, /proc/sys,
  • /proc/sysrq-trigger, /proc/irq, /proc/bus
  • /dev/mem, /dev/sd* file system
  • Kernel Modules

If any attacker can exploit any of those elements, they will own the host OS.

A VM OS will not have direct access to any of those elements. It will talk to the hypervisor, and the hypervisor will make the appropriate system calls to the host OS. It will filter out invalid calls, adding a layer of security.

5. Raw Sockets

The default Docker Unix socket (/var/run/docker.sock) can be mounted by any container if not properly secured. If some container mounts this socket, it can shutdown, start or create new images.

If it’s properly configured and secured, you can achieve a high level of security with a docker container, but it will be less than a properly configured VM. No matter how much hardening tools are employed, a VM will always be more secure. Bare metal isolation is even more secure than a VM. Some bare metal implementations (IBM PR/SM for example) can guarantee that the partitions are as separated as if they were on separate hardware. As far as I know, there’s no way to escape a PR/SM virtualization.

Saying either a VM or Docker is more secure than the other is a massive over simplification.

VM provides hardware virtualization; the hypervisor emulates hardware so that the guest kernel thinks it is running on its own machine. This type of virtualization is easier to isolate from one another. If your primary concern for virtualization is isolation (you don’t really need the virtual machines to interact with each other), then VM is going to be significantly simpler to secure.

Docker provides kernel/operating system virtualization, and Docker uses the kernel namespaces to virtualize the kernel and the operating system so that the guest thinks it is running on its own instance of the operating system. Operating system virtualization provides significantly more flexibility on how you can secure the interconnection between your containers. If your primary concern for virtualization requires you to interconnect containers, then Docker provides the ability to define these sharing rules in ways that are impossible or too cumbersome with virtual machines.

With great flexibility comes great risks; it’s easier to misconfigure docker than VM, and the flexibility of docker resource sharing also creates more opportunities for both implementation and configuration bugs. However, if you manage to configure the sharing permissions properly and assuming there are no implementation bugs in Docker or the kernel, then Docker provides much more fine-grained sharing than hardware virtualization and may give you overall better security.

For example, socket sharing. With Docker, you can create a shared named socket between two containers easily by sharing the socket file, and you can define security permissions (using any existing security modules: traditional Unix permission, capabilities, SELinux, AppArmor, seccomp, etc.) between the socket endpoints so that the docker/kernel enforces which and how applications can access the socket endpoints. With a virtual machine, you can share a socket a bit more cumbersome by setting up a chain of sockets to pipe data going to the socket via TCP. However, the hypervisor has very limited visibility and no way to control access to the socket endpoints, because permissions to these socket end points are applied by the guest kernels.

Another example is folder sharing. With containers, you can share a folder by setting up a shared mount, and since the Docker/kernel enforces file permissions that is used by containers, the guest system can’t bypass that restrictions. With a VM, if you want to share folder you have to let one machine run a network file server or Samba server or FTP server, and the hypervisor have little visibility into the share and can’t enforce sharing permissions. The additional moving parts here (the file server), may also have its own vulnerabilities and misconfiguration issues to consider.

TL;DR: Use VM for isolation and containers for controlled sharing.

As you correctly stated, Docker uses “Operating-system-level virtualization”. You can think of this (if you are a *nix fan) as a fancy form of chroot.

By harnessing features and functionality built into the OS, Docker acts as a director for containers. The software’s view of the OS is dictated by Docker.

The same kernel is used across all containers. So for instance, if I was able to cause a kernel panic in one container (think “Blue Screen of Death”), all other containers are affected.

Configuration seems to be much more critical than with hardware based solutions. Everything is in the same shared space effectively. Imagine putting a wild predator beside it’s natural food source. If you didn’t put a strong enough enclosure surrounding the predator, or forgot to shut the gate every time you left it’s enclosure, you can likely imagine what would happen.

While certainly a lightweight solution, I certainly wouldn’t run any unknown code along side that of trusted code.

Malicious code would have to determine a way to escalate it’s privileges to a root/Administrator level in order to escape the container in any meaningful way.

In a virtual machine, the hypervisor would be attacked, not the kernel. This may prove more secure as there is a higher level of isolation between “containers” but introduces higher overhead for management.

From my understanding, there’s nothing that makes Docker more secure than “bare metal” or hardware based solutions. I would be inclined to say that Docker is less secure. In terms of 1 container per a piece of software, that can prove a different story.

If you are unsure of real world examples, I would take a look at OpenVZ. It uses OS level virtualization in a similar style just as Docker does, but with a modified kernel.

Related Solutions

Pin-board effect with CSS [closed]

You can use JavaScript to accomplish this but it can't be done with CSS floats alone. A library like jQuery masonry will do it well. The reason? The specs on floats. In particular #5 which says, "The outer top of a floating box may not be higher than the outer...

Calculate the sum with minimum usage of numbers

Here's a hint: 23 : 11 + 11+ 1 ( 3 magic numbers) 120: 110+ 10 (2 magic numbers) The highest digit in the target number is the answer, since you need exactly k magic numbers (all having 1 in the relevant position) in order for the sum to contain the digit k. So...

Why not drop the “auto” keyword? [duplicate]

Your proposal would be rejected on the basis of backward compatibility alone. But let's say for the sake of argument that the standards committee like your idea. You don't take into account the numerous ways you can initialize a variable widget w; // (a) widget...

Recursive to iterative using a systematic method [closed]

So, to restate the question. We have a function f, in our case fac. def fac(n): if n==0: return 1 else: return n*fac(n-1) It is implemented recursively. We want to implement a function facOpt that does the same thing but iteratively. fac is written almost in...

How can I match values in one file to ranges from another?

if the data file sizes are not huge, there is a simpler way $ join input1 input2 | awk '$5<$4 && $3<$5 {print $2, $5-$3+1}' B100002 32 B100043 15 B123465 3 This Perl code seems to solve your problem It is a common idiom: to load the entire...

Javascript difference between “=” and “===” [duplicate]

You need to use == or === for equality checking. = is the assignment operator. You can read about assignment operators here on MDN. As a quick reference as you are learning JS: = assignment operator == equal to === equal value and equal type != not equal !==...

Compiler complains about misplaced else [closed]

Your compiler complains about an misplaced else because, well, there is an else without a preceding if: // ... for (j=1; j<n-i; j++) { if(a[j]<=a[j+1]) { // ... } // END OF IF } // END OF FOR else { continue; } // ... The else in your code does not follow...

Bootstrap – custom alerts with progress bar

/* !important are just used to overide the bootstrap css in the snippet */ .alertContainer { border-radius: 0 !important; border-width: 0 !important; padding: 0 !important; height: auto !important; position: absolute !important; bottom: 15px !important; left:...

How to Garbage Collect an external Javascript load?

Yes, s.onload = null is useful and will garbage collect! As of 2019, it is not possible to explicitly or programmatically trigger garbage collection in JavaScript. That means it collects when it wants. Although there is cases where setting to null may do a GC...

Math programming with python

At first, what you are looking for is the modulo operator and the function math.floor() Modulo from wikipedia: In computing, the modulo operation finds the remainder after division of one number by another (sometimes called modulus). for example: 12%12=0...

Android slide over letters to create a word [closed]

Here some advice you can use: First for each cell you can create an object that represents the state of that cell: class Cell { char mChar; int row,column; boolean isSelected; } then you can create a 2D array of your cells Cell[][] mTable = ... For views you...

Sum two integers in Java

You reused the x and y variable names (hence the variable x is already defined in method main error), and forgot to assign the ints read from the Scanner to the x and y variables. Besides, there's no need to create two Scanner objects. public static void...

Extend three classes that implements an interface in Java

Using this simplified implementation of the library, using method() instead of M(): interface IFC { void method(); } class A implements IFC { public void method() { System.out.println("method in A"); }; } As akuzminykh mentions in their comment You'd write a...