📜 ⬆️ ⬇️

Security Cheat Sheets: Docker



Docker containers are the most popular containerization technology. Initially, it was used mainly for dev and test environments, and in time passed into production. Docker containers began to breed in a production environment like mushrooms after rain, but few of those who use this technology thought about how to safely publish Docker containers.

Based on OWASP , we have prepared a list of rules, the implementation of which will significantly protect your environment, built on Docker containers.

Rule 0

Host Machine and Docker should contain all current updates.


To protect against known vulnerabilities leading to a container environment out of the container’s host system, which usually ends with privilege escalation on the host system, installing all patches for the host OS, Docker Engine and Docker Machine is extremely important.
')
In addition, containers (unlike virtual machines) share a kernel with a host, so a kernel exploit running inside the container is directly executed in the host core. For example, an exploit of elevating privileges in the kernel (for example, Dirty COW) running inside a well-isolated container will lead to root access on the host.

Rule 1

Do not give access to the Docker daemon socket


Docker service (daemon) uses UNIX socket /var/run/docker.sock for incoming API connections. The owner of this resource must be the root user. And nothing else. Changing access rights to this socket is essentially the same as granting root access to the host system.

Also, you should not fumble the socket /var/run/docker.sock with containers, where you can do without it, because in this case, compromising the service in the container will lead to full control over the host system. If you have containers that use something like this:

-v /var/run/docker.sock://var/run/docker.sock 

or for docker-compose:

 volumes: - "/var/run/docker.sock:/var/run/docker.sock" 

It is urgent to change this.

And last - never, hear, never use a Docker TCP socket without the absolute certainty that you need it, especially without using additional protection methods (at least authorization). By default, the Docker TCP socket opens a port on the external interface 0.0.0.0:2375 (2376, in the case of HTTPs) and allows you to completely control the containers, and with it the host system.

Rule 2

Configure an unprivileged user inside the container


Setting up a container to use an unprivileged user is the best way to avoid an attack on privilege escalation. This can be done in various ways:

1. Using the “-u” option of the “docker run” command:

 docker run -u 4000 alpine 

2. During image build:

 FROM alpine RUN groupadd -r myuser && useradd -r -g myuser myuser <      root-, ,  > USER myuser 

3. Enable “user namespace” support in the Docker daemon:

 --userns-remap=default 

More on this in the official documentation .

In Kubernetes, the latter is configured in the Security Context via the runAsNonRoot option:

 kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... runAsNonRoot: true ... 

Rule 3

Limit container capabilities


In Linux, starting with kernel 2.2, a way to control the capabilities of privileged processes called Linux Kernel Capabilities (details by reference) has appeared.

Docker by default uses a pre-installed set of these kernel features. And allows you to change this set using the commands:

 --cap-drop —     --cap-add —     

The best security setting is to first disable all features (--cap-drop all), and then connect only the necessary ones. For example:

 docker run --cap-drop all --cap-add CHOWN alpine 

And the most important (!): Avoid launching containers with the —privileged flag !!!

In Kubernetes, the Linux Kernel Capabilities limit is configured in the Security Context via the options option:

 kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... capabilities: drop: - all add: - CHOWN ... 

Rule 4

Use the no-new-privileges flag


When launching a container it is useful to use the --security-opt = no-new-privileges flag which prevents elevation of privileges inside the container.

In Kubernetes, the Linux Kernel Capabilities restriction is configured in the Security Context through the option allowPrivilegeEscalation:

 kind: ... apiVersion: ... metadata: name: ... spec: ... containers: - name: ... image: .... securityContext: ... allowPrivilegeEscalation: false ... 

Rule 5

Disable interconnect interactions


By default Docker has inter-container interaction enabled, which means that all containers can interact with each other (using the docker0 network). This feature can be disabled by starting the Docker service with the –icc = false flag.

Rule 6

Use Linux security modules (Linux Security Module - seccomp, AppArmor, SELinux)


By default, Docker already uses profiles for Linux security modules. Therefore, never disable security profiles! The maximum that can be done with them is to tighten the rules.

The seccomp default profile is available here .

Docker also uses AppArmor for protection, and the Docker Engine itself generates a default profile for AppArmor when the container is started. In other words, instead of:

 $ docker run --rm -it hello-world 

starts:

 $ docker run --rm -it --security-opt apparmor=docker-default hello-world 

Also in the documentation is an example of the AppArmor profile for nginx, which is quite possible (necessary!) To use:

 #include <tunables/global> profile docker-nginx flags=(attach_disconnected,mediate_deleted) { #include <abstractions/base> network inet tcp, network inet udp, network inet icmp, deny network raw, deny network packet, file, umount, deny /bin/** wl, deny /boot/** wl, deny /dev/** wl, deny /etc/** wl, deny /home/** wl, deny /lib/** wl, deny /lib64/** wl, deny /media/** wl, deny /mnt/** wl, deny /opt/** wl, deny /proc/** wl, deny /root/** wl, deny /sbin/** wl, deny /srv/** wl, deny /tmp/** wl, deny /sys/** wl, deny /usr/** wl, audit /** w, /var/run/nginx.pid w, /usr/sbin/nginx ix, deny /bin/dash mrwklx, deny /bin/sh mrwklx, deny /usr/bin/top mrwklx, capability chown, capability dac_override, capability setuid, capability setgid, capability net_bind_service, deny @{PROC}/* w, # deny write for all files directly in /proc (not in a subdir) # deny write to files not in /proc/<number>/** or /proc/sys/** deny @{PROC}/{[^1-9],[^1-9][^0-9],[^1-9s][^0-9y][^0-9s],[^1-9][^0-9][^0-9][^0-9]*}/** w, deny @{PROC}/sys/[^k]** w, # deny /proc/sys except /proc/sys/k* (effectively /proc/sys/kernel) deny @{PROC}/sys/kernel/{?,??,[^s][^h][^m]**} w, # deny everything except shm* in /proc/sys/kernel/ deny @{PROC}/sysrq-trigger rwklx, deny @{PROC}/mem rwklx, deny @{PROC}/kmem rwklx, deny @{PROC}/kcore rwklx, deny mount, deny /sys/[^f]*/** wklx, deny /sys/f[^s]*/** wklx, deny /sys/fs/[^c]*/** wklx, deny /sys/fs/c[^g]*/** wklx, deny /sys/fs/cg[^r]*/** wklx, deny /sys/firmware/** rwklx, deny /sys/kernel/security/** rwklx, } 

Rule 7

Limit container resources


This rule is quite simple: in the name of preventing containers from devouring all server resources during the next DoS / DDoS attack, we can set memory usage limits for each container separately. You can limit: the amount of memory, CPU, the number of container restarts.

So let's go in order.

Memory

Option -m or --memory

The maximum amount of memory a container can use. The minimum value is 4m (4 megabytes).

Option --memory-swap

Option to configure swap (swap file). Configured slyly:


Hostess note: the free utility running inside the container does not show the actual value of the available swap for the container, but the number of the host swap.

Option --oom-kill-disable

Allows you to enable or disable OOM (Out of memory) killer.

Attention! You can turn off OOM Killer only with the --memory option specified, otherwise it may happen that when out-of-memory inside the container, the kernel starts killing host system processes.

The rest of the memory management options, such as - memory-swappiness, memory, reservation and kernel-memory, are more used to tune container performance.

CPU

Option --cpus

The option sets how many available processor resources a container can use. For example, if we have a host with two CPUs and we specify --cpus = "1.5", then the container is guaranteed to use one and a half processor.

Option --cpuset-cpus

Customizes the use of specific cores or CPUs. The value can be set with a hyphen or a comma. In the first case, the range of allowed nuclei will be indicated, in the second case - specific nuclei.

Number of container restarts

 --restart=on-failure:<number_of_restarts> 

This setting sets how many times Docker will attempt to restart the container if it unexpectedly crashes. The counter is reset if the state of the container has changed to “running”.

It is recommended to set a small positive number, for example, 5, which will allow you to avoid endless restarts of the service not working.

Rule 8

Use read-only file systems and volume


If the container does not have to write anything anywhere, then you need to use the read-only filesystem as much as possible. This greatly complicates the life of a potential offender.

An example of launching a container with a read-only file system:

 docker run --read-only alpine 

Example of connecting volume in read-only mode:

 docker run -v volume-name:/path/in/container:ro alpine 

Rule 9

Use container security analysis tools


It is necessary to use tools to detect containers with known vulnerabilities. There are not many of them yet, but they are:

• Free:


• Commercial:


And for Kubernetes, there are tools for identifying configuration errors:

Source: https://habr.com/ru/post/448704/


All Articles