Answers: <p>Compared to just adding the user to the docker group the second links solution is not any more secure.</p>
  
  <p>Note how that page still can launch with the <code>--privileged</code> flag, and that it is running unconfined.</p>
  
  <p><code>unconfined_u:unconfined_r:unconfined_t</code></p>
  
  <p>This means that the container can access all resources including the hosts disks and hardware.  It is security through obscurity, which is not security.  Anyone who knows how to use <code>mknod</code> or walk the /sys and /proc trees could easily compromise the host and all containers with zero logging.</p>
  
  <p>The reality is that docker shifts both complexity and the security boundaries.  All users who can launch container or hit the API need to be restricted to trusted users in that security context.</p>
  
  <p><code>--privileged</code> disables all apparmor and selinux policies which is actually far less secure than a native package.</p>
  
  <p>Namespaces are not a security function and depend on apparmor and selinux to enforce reasonable constraints.</p>
  
  <p>Docker notes this on this page.</p>
  
  <p><a href="https://docs.docker.com/engine/security/security/#control-groups" rel="nofollow noreferrer">https://docs.docker.com/engine/security/security/#control-groups</a></p>
  
  <p>'First of all, only trusted users should be allowed to control your Docker daemon.'</p>
  
  <p>The security functions of docker/kube are not administrative boundaries like classical unix permissions, they are tools to prevent non-privileged containers from breaking out.</p>
  
  <p>In a docker world the administrative boundary becomes the host, and the selection and segmentation required to isolate applications or users within that context needs to be applied at that boundary.</p>
  
  <p>The benefits of this shift in complexity and responsibility generally outweigh the risks if implemented with those changes in mind.</p>
  
  <p>TLDR</p>
  
  <p>Docker API user == Sudo ALL user</p>
  
  <p>Running a container with the --privlaged flag == running a web service as suid or as the root user.</p>
  
  <p><strong>Edited per the OP's request for additional information</strong></p>
  
  <p>The referenced issue with breakout int he OP's edit was an non <strong>uid0</strong> privilege escalation.</p>
  
  <p>Unfortunately, due to the need to perform root only actions Docker needs to enable some capabilities so that apt/dnf can install packages etc...</p>
  
  <p>This need does pose a risk if production workloads are run in this default configuration and one should adopt the security principle of least privilege for production workloads.</p>
  
  <p><code>--privileged</code> disables <em>apparmor/selinux</em> and opens up <em>capabilities</em></p>
  
  <p>I am using ubuntu but it may be useful to work through the following steps. First start a default container with <em>docker run -i --rm -t debian bash</em></p>
  
  <p>From the parent host find the PID for bash using <em>ps</em> and note that the process is owned <em>root</em>.  If you look in <code>/proc/$PID/status</code> you will see the contexts it is running under.</p>
  
  <pre><code># egrep '^Cap(Prm|Inh|Eff)' /proc/16026/status
   CapInh:    00000000a80425fb
   CapPrm:    00000000a80425fb
   CapEff:    00000000a80425fb
  </code></pre>
  
  <p>You will want to refer to <em>man 7 man capabilities</em> and <em>/usr/include/linux/capability.h</em> for better info but a summer is</p>
  
  <p>CapInh = The Inherited capabilities (what docker provided)
  CapPrm = The capabilities due to permissions (inside the container OS)
  CapEff = The effective capabilities</p>
  
  <p>You can decode these to human readable form by running:</p>
  
  <pre><code>$ capsh --decode=00000000a80425fb
  </code></pre>
  
  <p>Now do the same with <code>$ docker run -i --rm --privileged -t debian bash</code> and you will find that the effective capabilities are <code>0000003fffffffff</code></p>
  
  <p>Also just do a <code>dir /dev</code> in both VM's and you will see just how much access a privileged container has.</p>
  
  <p>By looking at <code>/etc/apparmor.d/docker</code> for apparmor systems or the lables in SElinux you will see the implications.</p>
  
  <p>Going back to the principle of least privileges, I would ensure that my docker container is running process as a unprivileged user and with as few enabled capabilities as possible.</p>
  
  <p>As an example, you can test this by running it first by dropping all caps.</p>
  
  <pre><code>$ docker run -i --rm -t --cap-drop=all -t debian bash
  </code></pre>
  
  <p>This can be validated through the <code>/proc/$PID/status</code> method above.</p>
  
  <pre><code>CapInh: 0000000000000000
  CapPrm: 0000000000000000
  CapEff: 0000000000000000
  </code></pre>
  
  <p>Note it is all zeros, from CapInh.  Then if I had to enable features for the application I would use <code>--cap-add</code> <em>after</em> the <code>--cap-drop=all</code></p>
  
  <p>Example, <code>--cap-drop=all</code> will break ping:</p>
  
  <pre><code># ping -c 1 www.google.com
  ping: Lacking privilege for raw socket.
  </code></pre>
  
  <p>So we can add the <code>cap_net_raw</code> cap. Docker expects the arguments with the <code>cap_</code> prefix removed so the command is <code>docker run -i --rm -t --cap-drop=all --cap-add=net_raw -t debian bash</code></p>
  
  <pre><code># ping -c 1 www.google.com
  PING www.google.com (216.58.216.164): 56 data bytes
  64 bytes from 216.58.216.164: icmp_seq=0 ttl=54 time=4.779 ms
  </code></pre>
  
  <p>But be very careful adding them as an example.</p>
  
  <p>cap_sys_module will allow a container to add or remove kernel modules from the parent host.</p>
  
  <p>cap_sys_rawio will open memory and <em>all</em> block devices to attack</p>
  
  <p>cap_sys_admin is super dangerous.</p>
  
  <p>So in this case I would see if you can make things run in this context.</p>
  
  <p>$ docker run -i --rm -t --cap-drop=all -u nobody:nogroup -t debian bash</p>
  
  <p>Hopefully the robustness of apparmor and selinux profiles improves over time, but if that is not enough for your security needs you can look in there too.</p>
  
  <p>Really, avoiding the <em>--privileged</em> flag and using principle of least privilege will make the most impact. Especially if you take advantage of the ephemeral nature of containers to keep packages up to date.</p>
  
  <p>If you need more Red Hat covers some basic seccomp options here.</p>
  
  <p><a href="https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/container_security_guide/linux_capabilities_and_seccomp" rel="nofollow noreferrer">https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/container_security_guide/linux_capabilities_and_seccomp</a></p>
  
Answers: CC BY-SA 3.0
Answers: 2017-09-08T07:42:48.317Z
Answers: Thank you for you detailled reponse, it certainly helps to be explicit about the boundaries. I figured as much, that it is a bad idea to let an untrusted user access the docker daemon, as shown by that linked article. I added an EDIT to the question to clarify the direction I am going in a bit more. Can you add a few words on that?
Answers: AnoE
Answers: CC BY-SA 3.0
Answers: 2017-09-09T22:30:02.337Z
Answers: Related to the "breakout" that was an issue where non-root users could gain root access. 
  
  Root is still root, I will edit my response with more info as there is not enough space in comments.
Answers: gdahlm
Answers: CC BY-SA 3.0
Answers: 2017-09-08T04:07:11.573Z
Answers: 2017-09-09T23:31:53.950Z
Answers: 2017-09-09T23:31:53.950Z
Answers: gdahlm
Body: <p>Inspired by <a href="https://devops.stackexchange.com/questions/1943/what-are-best-and-comprehensive-practices-to-consider-when-running-docker-in-pro">What are best and comprehensive practices to consider when running docker in production?</a> , I stumbled over  <a href="http://www.projectatomic.io/blog/2015/08/why-we-dont-let-non-root-users-run-docker-in-centos-fedora-or-rhel/" rel="noreferrer">Why we don't let non-root users run Docker...</a></p>
  
  <p>They came up with  <code>docker run -ti --privileged -v /:/host fedora chroot /host</code> , which puts your unprivileged (but <code>docker</code>-grouped) user in a root shell on the host (not in the container).</p>
  
  <p>No need to mention, that is rather bad news for production systems.</p>
  
  <p>What can be done to avoid this or similar things? I assume the docker daemon cannot be run as a non-root user (or else that would likely be the default way to start it)? One solution that comes to mind is not putting unprivileged users in the <code>docker</code>group and only allowing specific docker command lines via <code>sudoers</code>. But is that enough?</p>
  
  <p>Do we know how hard it is to break out of the container and gain a host <code>root</code> shell like in the example given, if the image is ran as usual (i.e. <code>docker run --rm -it myimage</code>)? I am not even talking about some attack via the service running in the container, but by, say, a specially prepared image.</p>
  
  <p>EDIT: to clarify, I am specifically interested in this attack scenario:</p>
  
  <ul>
  <li>Untrusted software developer delivers a ready-to-run image.</li>
  <li>Trusted user runs that image on a production system in a normal fashion (i.e., <code>docker --rm -it myimage</code>), without <code>--privileged</code>.
  
  <ul>
  <li>Possibly with sub-scenarios of <code>-u unprivileged_u</code> or not.</li>
  </ul></li>
  <li>Does the untrusted person that created the image have a reasonable chance to break out of the docker container runtime? I.e., more than with, say, classical <code>chroot</code> or classical permission elevation?</li>
  </ul>
  
  <p>EDIT2: My research shows only a single real breakout incident which was fixed with Docker Engine 0.12, and then again in 1.0.1. Also, all things I found that are critical about this mention the erstwhile TCP/IP interface of the docker daemon, which was changed to the Unix socket for a long time now. Is there anything else, or would you say that there is no problem as long as the person typing/running the actual <code>docker</code> command is good?</p>
  
Comments: CC BY-SA 3.0
Comments: 2017-09-08T16:04:06.080Z
Comments: Worth reading and far too long to summarize in an answer: https://www.blackhat.com/docs/eu-15/materials/eu-15-Bettini-Vulnerability-Exploitation-In-Docker-Container-Environments-wp.pdf
Comments: Tensibai
Comments: CC BY-SA 3.0
Comments: 2017-09-08T16:46:10.467Z
Comments: Interesting read, and thank you for that, @Tensibai, but really nothing new - in summary it says that *controlling* the `docker` command opens up `root` access on the host (but this is specifically not what this question is about), and it contains references to old security issues from 2015.
Comments: AnoE
Comments: CC BY-SA 3.0
Comments: 2017-09-08T16:49:27.770Z
Comments: Indeed nothing new, I did thought it gives a little more feedback around. I've another one specific to containers evasion but I have to check the date and interest before sharing it (and ensure I can share it also)
Comments: Tensibai
Comments: CC BY-SA 3.0
Comments: 2017-09-08T16:50:44.000Z
Comments: I sure am interested in anything - if I sound unhappy about the ressource, it's just because it doesn't further this question in particular. Your effort is certainly appreciated. @Tensibai
Comments: AnoE
Comments: CC BY-SA 3.0
Comments: 2017-09-08T16:54:12.257Z
Comments: You didn't sound unhappy, I didn't said clearly it was only related btw. No problem
Comments: Tensibai
Tags: <security>
Title: Running the docker daemon without root
UserDisplayName: AnoE
ThreadText: # Running the docker daemon without root
  
  (Asked by: username_0 on 2017-09-07)
  
  Inspired by [What are best and comprehensive practices to consider when running docker in production?](https://devops.stackexchange.com/questions/1943/what-are-best-and-comprehensive-practices-to-consider-when-running-docker-in-pro) , I stumbled over [Why we don't let non-root users run Docker...](http://www.projectatomic.io/blog/2015/08/why-we-dont-let-non-root-users-run-docker-in-centos-fedora-or-rhel/)
  
  They came up with `docker run -ti --privileged -v /:/host fedora chroot /host` , which puts your unprivileged (but `docker`-grouped) user in a root shell on the host (not in the container).
  
  No need to mention, that is rather bad news for production systems.
  
  What can be done to avoid this or similar things? I assume the docker daemon cannot be run as a non-root user (or else that would likely be the default way to start it)? One solution that comes to mind is not putting unprivileged users in the `docker`group and only allowing specific docker command lines via `sudoers`. But is that enough?
  
  Do we know how hard it is to break out of the container and gain a host `root` shell like in the example given, if the image is ran as usual (i.e. `docker run --rm -it myimage`)? I am not even talking about some attack via the service running in the container, but by, say, a specially prepared image.
  
  EDIT: to clarify, I am specifically interested in this attack scenario:
  
  * Untrusted software developer delivers a ready-to-run image.
  * Trusted user runs that image on a production system in a normal fashion (i.e., `docker --rm -it myimage`), without `--privileged`.
    + Possibly with sub-scenarios of `-u unprivileged_u` or not.
  * Does the untrusted person that created the image have a reasonable chance to break out of the docker container runtime? I.e., more than with, say, classical `chroot` or classical permission elevation?
  
  EDIT2: My research shows only a single real breakout incident which was fixed with Docker Engine 0.12, and then again in 1.0.1. Also, all things I found that are critical about this mention the erstwhile TCP/IP interface of the docker daemon, which was changed to the Unix socket for a long time now. Is there anything else, or would you say that there is no problem as long as the person typing/running the actual `docker` command is good?
  
  **Tags:** security
  
  > **Comments:**
  > **username_1**: Worth reading and far too long to summarize in an answer: https://www.blackhat.com/docs/eu-15/materials/eu-15-Bettini-Vulnerability-Exploitation-In-Docker-Container-Environments-wp.pdf  
  > **username_0**: Interesting read, and thank you for that, @username_1, but really nothing new - in summary it says that *controlling* the `docker` command opens up `root` access on the host (but this is specifically not what this question is about), and it contains references to old security issues from 2015.  
  > **username_1**: Indeed nothing new, I did thought it gives a little more feedback around. I've another one specific to containers evasion but I have to check the date and interest before sharing it (and ensure I can share it also)  
  > **username_0**: I sure am interested in anything - if I sound unhappy about the ressource, it's just because it doesn't further this question in particular. Your effort is certainly appreciated. @username_1  
  > **username_1**: You didn't sound unhappy, I didn't said clearly it was only related btw. No problem  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_2 on 2017-09-08. Score: 7 | Accepted answer
  
  Compared to just adding the user to the docker group the second links solution is not any more secure.
  
  Note how that page still can launch with the `--privileged` flag, and that it is running unconfined.
  
  `unconfined_u:unconfined_r:unconfined_t`
  
  This means that the container can access all resources including the hosts disks and hardware. It is security through obscurity, which is not security. Anyone who knows how to use `mknod` or walk the /sys and /proc trees could easily compromise the host and all containers with zero logging.
  
  The reality is that docker shifts both complexity and the security boundaries. All users who can launch container or hit the API need to be restricted to trusted users in that security context.
  
  `--privileged` disables all apparmor and selinux policies which is actually far less secure than a native package.
  
  Namespaces are not a security function and depend on apparmor and selinux to enforce reasonable constraints.
  
  Docker notes this on this page.
  
  <https://docs.docker.com/engine/security/security/#control-groups>
  
  'First of all, only trusted users should be allowed to control your Docker daemon.'
  
  The security functions of docker/kube are not administrative boundaries like classical unix permissions, they are tools to prevent non-privileged containers from breaking out.
  
  In a docker world the administrative boundary becomes the host, and the selection and segmentation required to isolate applications or users within that context needs to be applied at that boundary.
  
  The benefits of this shift in complexity and responsibility generally outweigh the risks if implemented with those changes in mind.
  
  TLDR
  
  Docker API user == Sudo ALL user
  
  Running a container with the --privlaged flag == running a web service as suid or as the root user.
  
  **Edited per the OP's request for additional information**
  
  The referenced issue with breakout int he OP's edit was an non **uid0** privilege escalation.
  
  Unfortunately, due to the need to perform root only actions Docker needs to enable some capabilities so that apt/dnf can install packages etc...
  
  This need does pose a risk if production workloads are run in this default configuration and one should adopt the security principle of least privilege for production workloads.
  
  `--privileged` disables *apparmor/selinux* and opens up *capabilities*
  
  I am using ubuntu but it may be useful to work through the following steps. First start a default container with *docker run -i --rm -t debian bash*
  
  From the parent host find the PID for bash using *ps* and note that the process is owned *root*. If you look in `/proc/$PID/status` you will see the contexts it is running under.
  
  ```
  # egrep '^Cap(Prm|Inh|Eff)' /proc/16026/status
   CapInh:    00000000a80425fb
   CapPrm:    00000000a80425fb
   CapEff:    00000000a80425fb
  
  ```
  
  You will want to refer to *man 7 man capabilities* and */usr/include/linux/capability.h* for better info but a summer is
  
  CapInh = The Inherited capabilities (what docker provided)
  CapPrm = The capabilities due to permissions (inside the container OS)
  CapEff = The effective capabilities
  
  You can decode these to human readable form by running:
  
  ```
  $ capsh --decode=00000000a80425fb
  
  ```
  
  Now do the same with `$ docker run -i --rm --privileged -t debian bash` and you will find that the effective capabilities are `0000003fffffffff`
  
  Also just do a `dir /dev` in both VM's and you will see just how much access a privileged container has.
  
  By looking at `/etc/apparmor.d/docker` for apparmor systems or the lables in SElinux you will see the implications.
  
  Going back to the principle of least privileges, I would ensure that my docker container is running process as a unprivileged user and with as few enabled capabilities as possible.
  
  As an example, you can test this by running it first by dropping all caps.
  
  ```
  $ docker run -i --rm -t --cap-drop=all -t debian bash
  
  ```
  
  This can be validated through the `/proc/$PID/status` method above.
  
  ```
  CapInh: 0000000000000000
  CapPrm: 0000000000000000
  CapEff: 0000000000000000
  
  ```
  
  Note it is all zeros, from CapInh. Then if I had to enable features for the application I would use `--cap-add` *after* the `--cap-drop=all`
  
  Example, `--cap-drop=all` will break ping:
  
  ```
  # ping -c 1 www.google.com
  ping: Lacking privilege for raw socket.
  
  ```
  
  So we can add the `cap_net_raw` cap. Docker expects the arguments with the `cap_` prefix removed so the command is `docker run -i --rm -t --cap-drop=all --cap-add=net_raw -t debian bash`
  
  ```
  # ping -c 1 www.google.com
  PING www.google.com (216.58.216.164): 56 data bytes
  64 bytes from 216.58.216.164: icmp_seq=0 ttl=54 time=4.779 ms
  
  ```
  
  But be very careful adding them as an example.
  
  cap\_sys\_module will allow a container to add or remove kernel modules from the parent host.
  
  cap\_sys\_rawio will open memory and *all* block devices to attack
  
  cap\_sys\_admin is super dangerous.
  
  So in this case I would see if you can make things run in this context.
  
  $ docker run -i --rm -t --cap-drop=all -u nobody:nogroup -t debian bash
  
  Hopefully the robustness of apparmor and selinux profiles improves over time, but if that is not enough for your security needs you can look in there too.
  
  Really, avoiding the *--privileged* flag and using principle of least privilege will make the most impact. Especially if you take advantage of the ephemeral nature of containers to keep packages up to date.
  
  If you need more Red Hat covers some basic seccomp options here.
  
  <https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux_atomic_host/7/html/container_security_guide/linux_capabilities_and_seccomp>
  
  > **Comments:**
  > **username_0**: Thank you for you detailled reponse, it certainly helps to be explicit about the boundaries. I figured as much, that it is a bad idea to let an untrusted user access the docker daemon, as shown by that linked article. I added an EDIT to the question to clarify the direction I am going in a bit more. Can you add a few words on that?  
  > **username_2**: Related to the "breakout" that was an issue where non-root users could gain root access.   Root is still root, I will edit my response with more info as there is not enough space in comments.  
  
  ---
  
  