Docker security fundamentals

In the previous sections, we looked into some Docker tools that you can use, such as TLS for communication, and using read-only containers to help ensure data isn't changed or manipulated. In this section, we will focus on some more options that are available from within the Docker ecosystem that can be used to help secure up your environments to another level. We will take a look at the kernel namespaces that provide another layer of abstraction by providing the running process to its own resources that appear only to the process itself and not to other processes that might be running. We will cover more about kernel namespaces in this section. We will then take a look at the control groups. Control groups, more commonly known as cgroups, give you the ability to limit the resources that a particular process has. We will then cover the Linux kernel capabilities. By that, we will look at the restrictions that are placed on containers, by default, when they are run using Docker. Lastly, we will take a look at the Docker daemon attack surface, risks that exist with the Docker daemon that you need to be aware of, and mitigation of these risks.

Kernel namespaces

Kernel namespaces provide a form of isolation for containers. Think of them as a container wrapped inside another container. Processes that are running in one container can't disrupt the processes running inside another container or let alone run on the Docker host that the container is operating on. The way this works is that each container gets its own network stacks to operate with. However, there are ways to link these containers together in order to be able to interact with each other; however, by default, they are isolated from each other. Kernel namespaces have been around for quite a while too, so they are a tried and true method of isolation protection. They were introduced in 2008 and at the time of writing this book, it's 2016. You can see that they will be eight years old, come this July. Therefore, when you issue the docker run command, you are benefiting from a lot of heavy lifting that is going on behind the scenes. This heavy lifting is creating its own network stack to operate on. This is also shielding off the container from other containers being able to manipulate the container's running processes or data.

Control groups

Control groups, or more commonly referred to as cgroups, are a Linux kernel feature that allows you to limit the resources that a container can use. While they limit the resources, they also ensure that each container gets the resources it needs as well as that no single container can take down the entire Docker host.

With control groups, you can limit the amount of CPU, memory, or disk I/O that a particular container gets. If we look at the docker run command's help, let's highlight the items that we can control. We will just be highlighting a few items that are particularly useful for the majority of users, but please review them to see if any others fit your environment, as follows:

$ docker run --help                                

Usage: docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

Run a command in a new container

  -a, --attach=[]                 Attach to STDIN, STDOUT or STDERR
  --add-host=[]                   Add a custom host-to-IP mapping (host:ip)
  --blkio-weight=0                Block IO (relative weight), between 10 and 1000
  --cpu-shares=0                  CPU shares (relative weight)
  --cap-add=[]                    Add Linux capabilities
  --cap-drop=[]                   Drop Linux capabilities
  --cgroup-parent=                Optional parent cgroup for the container
  --cidfile=                      Write the container ID to the file
  --cpu-period=0                  Limit CPU CFS (Completely Fair Scheduler) period
  --cpu-quota=0                   Limit CPU CFS (Completely Fair Scheduler) quota
  --cpuset-cpus=                  CPUs in which to allow execution (0-3, 0,1)
  --cpuset-mems=                  MEMs in which to allow execution (0-3, 0,1)
  -d, --detach=false              Run container in background and print container ID
  --device=[]                     Add a host device to the container
  --disable-content-trust=true    Skip image verification
  --dns=[]                        Set custom DNS servers
  --dns-opt=[]                    Set DNS options
  --dns-search=[]                 Set custom DNS search domains
  -e, --env=[]                    Set environment variables
  --entrypoint=                   Overwrite the default ENTRYPOINT of the image
  --env-file=[]                   Read in a file of environment variables
  --expose=[]                     Expose a port or a range of ports
  --group-add=[]                  Add additional groups to join
  -h, --hostname=                 Container host name
  --help=false                    Print usage
  -i, --interactive=false         Keep STDIN open even if not attached
  --ipc=                          IPC namespace to use
  --kernel-memory=                Kernel memory limit
  -l, --label=[]                  Set meta data on a container
  --label-file=[]                 Read in a line delimited file of labels
  --link=[]                       Add link to another container
  --log-driver=                   Logging driver for container
  --log-opt=[]                    Log driver options
  --lxc-conf=[]                   Add custom lxc options
  -m, --memory=                   Memory limit
  --mac-address=                  Container MAC address (e.g. 92:d0:c6:0a:29:33)
  --memory-reservation=           Memory soft limit
  --memory-swap=                  Total memory (memory + swap), '-1' to disable swap
  --memory-swappiness=-1          Tuning container memory swappiness (0 to 100)
  --name=                         Assign a name to the container
  --net=default                   Set the Network for the container
  --oom-kill-disable=false        Disable OOM Killer
  -P, --publish-all=false         Publish all exposed ports to random ports
  -p, --publish=[]                Publish a container's port(s) to the host
  --pid=                          PID namespace to use
  --privileged=false              Give extended privileges to this container
  --read-only=false               Mount the container's root filesystem as read only
  --restart=no                    Restart policy to apply when a container exits
  --rm=false                      Automatically remove the container when it exits
  --security-opt=[]               Security Options
  --sig-proxy=true                Proxy received signals to the process
  --stop-signal=SIGTERM           Signal to stop a container, SIGTERM by default
  -t, --tty=false                 Allocate a pseudo-TTY
  -u, --user=                     Username or UID (format: <name|uid>[:<group|gid>])
  --ulimit=[]                     Ulimit options
  --uts=                          UTS namespace to use
  -v, --volume=[]                 Bind mount a volume
  --volume-driver=                Optional volume driver for the container
  --volumes-from=[]               Mount volumes from the specified container(s)
  -w, --workdir=                  Working directory inside the container

As you can see from the preceding highlighted portions, these are just a few items that you can control on a per-container basis.

Linux kernel capabilities

Docker uses the kernel capabilities to place the restrictions that Docker places on the containers when they are launched or started. Limiting the root access is the ultimate agenda with these kernel capabilities. There are a few services that typically run as root, but can now be run without these permissions. Some of these include SSH, cron, and syslogd.

Overall, what this means is that you don't need root in the server sense you typically think of. You can run with a reduced capacity set. This means that your root user doesn't need the privilege it typically needs.

Some of the things that you might not need to enable anymore are shown in the following:

  • Performing mount operations
  • Using raw sockets, which will help to prevent spoofing of packets
  • Creating new devices
  • Changing the owner of files
  • Altering attributes

This helps due to the fact that if someone does compromise a container, then they can't escalate any more than what you are providing them. It will be much harder, if not impossible, to escalate their privileges from a running container to running Docker host. Due to such complexity, the attackers will probably look elsewhere than your Docker environments to try to attack. Docker also supports the addition and removal of capabilities, therefore, it's recommend to remove all the capabilities, except the ones that you intend to use. An example would be to use the –cap-add net_bind_service switch on your docker run command.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset