└── README.md
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 | Within today’s growing cloud-based IT market, there is a strong demand for virtualisation technologies. Unfortunately most virtualisation solutions are not flexible enough to meet developer requirements and the overhead implied by the use of full virtualisation solutions becomes a burden on the scalability of the infrastructure.
11 |
12 | Docker reduces that overhead by allowing developers and system administrators to seamlessly deploy containers for applications and services required for business operations. However, because Docker leverages the same kernel as the host system to reduce the need for resources, containers can be exposed to significant security risks if not adequately configured.
13 |
14 | The following itemised list suggests hardening actions that can be undertaken to improve the security posture of the containers within their respective environment. It should be noted that proposed solutions only apply to deployment of Linux Docker containers on Linux-based hosts, using the most recent release of Docker at the time of this writing (1.4.0, commit 4595d4f
, dating 11/12/14).
15 |
16 | Part of the content below is based on publications from Jérôme Petazzoni [1] and Daniel J Walsh [2]. This document aims at adding on to their recommendations and how they can specifically be implemented within Docker.
17 |
18 | Note: Most of suggested command line options can be stored and used in a similar manner inside a Dockerfile for automated image building.
19 |
20 |
21 |
22 |
23 | Item |
24 | Deployment |
25 |
26 |
27 | Docker Images |
28 | Docker 1.3 now supports cryptographic signatures [3] to ascertain the origin and integrity of official repository images. This feature is however still a work in progress as Docker will issue a warning but not prevent the image from actually running. Furthermore, it does not apply to non-official images.
29 |
30 |
31 | In general, ensure that images are only retrieved from trusted repositories and that the --insecure-registry=[] command line option is never used. |
32 |
33 |
34 | Network Namespaces [4] |
35 | By default, the Docker REST API used to control containers exposed via the system Docker daemon is only accessible locally via a Unix domain socket.
36 |
37 |
38 | Running Docker on a TCP port (i.e. forcing the bind address using the -H option when launching the Docker daemon) will allow anyone with access to that port to gain access to the container, potentially gaining root access on the host as well in some scenarios where the local user belongs to the docker group [5].
39 |
40 |
41 | When allowing access to the daemon over TCP, ensure that communications are adequately encrypted using SSL [6] and access controls effectively prevent unauthorised parties from interacting with it.
42 |
43 |
44 | Kernel firewall iptables rules can be applied to docker0 , the standard network bridge interface for Docker, to enforce those controls.
45 |
46 |
47 | For instance, the source IP range of a Docker container can be restricted from talking with the outside world using the following iptables filter [7].
48 | iptables -t filter -A FORWARD -s <source_ip_range> -j REJECT --reject-with icmp-admin-prohibited
|
49 |
50 |
51 | Logging & Auditing |
52 | Collect and archive security logs relating to Docker for auditing and monitoring purposes.
53 |
54 |
55 | Accessing log files outside of the container, from the host [8], can be performed using the following command:
56 | docker run -v /dev/log:/dev/log <container_name> /bin/sh
57 |
58 |
59 | Using the Docker command built-in:
60 | docker logs ...
61 | (-f to follow log output)
62 |
63 |
64 | Log files can also be exported for persistent storage into a tarball using:
65 | docker export ... |
66 |
67 |
68 | SELinux or AppArmor |
69 | Linux kernel security modules such as Security-Enhanced Linux (SELinux) and AppArmor can be configured, via access control security policies, to implement mandatory access controls (MAC) confining processes to a limited set of system resources or privileges.
70 |
71 |
72 | SELinux can be enabled in the container using setenforce 1, if it was previously installed and configured. The SELinux support for the Docker daemon is disabled by default and needs to be enabled using --selinux-enabled .
73 |
74 |
75 | Introduced in Docker version 1.3 [9], label confinement for the container can be configured using the newly added --security-opt argument to load SELinux or AppArmor policies, as shown in the Docker run reference excerpt below.
76 |
77 |
78 | --security-opt="label:user:USER" : Set the label user for the container
79 | --security-opt="label:role:ROLE" : Set the label role for the container
80 | --security-opt="label:type:TYPE" : Set the label type for the container
81 | --security-opt="label:level:LEVEL" : Set the label level for the container
82 | --security-opt="apparmor:PROFILE" : Set the apparmor profile to be applied to the container
83 |
84 |
85 | Example:
86 | docker run --security-opt=label:level:s0:c100,c200 -i -t centos bash |
87 |
88 |
89 | Daemon Privileges |
90 | Do not use the --privileged command line option. This would otherwise allow the container to access all devices on the host and would in addition provide the container with specific a LSM (i.e SELinux or AppArmor) configuration that would give it the same level of access as processes running on the host.
91 |
92 |
93 | Avoiding the use of --privileged helps reduce the attack surface and potential of host compromise. This however does not mean that the daemon will run without root privileges which is still currently required in the latest release.
94 |
95 |
96 | The ability to launch the daemon and containers should only be given to trusted user.
97 |
98 |
99 | Minimize privileges enforced inside the container by leveraging the -u option.
100 | Example:
101 | docker run -u <username> -it <container_name> /bin/bash
102 |
103 | Any user part of the docker group could eventually get root on the host from the container |
104 |
105 |
106 | cgroups [10] |
107 | In order to prevent Denial of Service (DoS) attacks via system resource exhaustion, a number of resource restrictions can be applied using specific command line arguments.
108 |
109 |
110 | CPU usage:
111 | docker run -it --rm --cpuset=0,1 -c 2 ...
112 |
113 |
114 | Memory usage:
115 | docker run -it --rm -m 128m ...
116 |
117 |
118 | Storage usage:
119 | docker -d --storage-opt dm.basesize=5G
120 |
121 |
122 | Disk I/O:
123 | Currently not supported by Docker. BlockIO* properties exposed via systemd can be leveraged to control disk usage quotas on supported operating systems. |
124 |
125 |
126 | SUID/GUID binaries |
127 | SUID and GUID binaries can prove dangerous when vulnerable to attacks leading to arbitrary code execution (e.g. buffer overflows), as they will be running under the context of the process’s file owner or group.
128 |
129 |
130 | When possible, prohibit SUID and SGID from taking effect by reducing the capabilities given to containers using specific command line arguments.
131 | docker run -it --rm --cap-drop SETUID --cap-drop SETGID ...
132 |
133 |
134 | Alternatively, consider removing SUID capabilities from the system by mounting filesystem with the nosuid attribute.
135 |
136 |
137 | One last option could be to remove unwanted SUID and GUID binaries from the system altogether. These types of binaries can be found on a Linux system by running the following commands:
138 | find / -perm -4000 -exec ls -l {} \; 2>/dev/null
139 | find / -perm -2000 -exec ls -l {} \; 2>/dev/null
140 |
141 |
142 | The SUID and GUID file permissions can then be removed using commands similar to the following [11]:
143 | sudo chmod u-s filename
144 | sudo chmod -R g-s directory |
145 |
146 |
147 | Devices control group (/dev/*) |
148 | If required, mount devices using the built-in --device option (do not use -v with the --privileged argument).
149 |
150 |
151 | Granular permissions can be assigned to each device using a third set of options :rwm to override read , write , and mknod permissions respectively (default includes all permissions).
152 |
153 |
154 | Example (for using sound card with read-only permission):
155 | docker run --device=/dev/snd:/dev/snd:r ...
156 |
157 |
158 | This feature was introduced in version 1.2 [12]. |
159 |
160 |
161 | Services and Applications |
162 | To reduce the potential for lateral movement if a Docker container was to be compromised, consider isolating sensitive services (e.g. run SSH service on bastion host or in a VM).
163 |
164 |
165 | Furthermore, do not run untrusted applications with root privileges within containers. |
166 |
167 |
168 | Mount Points |
169 | This is handled automatically by Docker when using the native container library (i.e. libcontainer).
170 |
171 |
172 | However, when using the LXC container library, sensitive mount points should ideally be manually mounted with read-only permissions, including:
173 |
174 | /sys
175 | /proc/sys
176 | /proc/sysrq-trigger
177 | /proc/irq
178 | /proc/bus
179 |
180 | Mount permissions should later be removed to prevent remounting. |
181 |
182 |
183 | Linux Kernel |
184 | Ensure kernel is up-to-date using update utility provided by the system (e.g. apt-get, yum, etc). Out-dated kernels are more likely to be vulnerable to publicly disclosed vulnerabilities.
185 |
186 |
187 | Use strengthened a kernel with GRSEC or PAX, that for example provide increased security against memory corruption bugs. |
188 |
189 |
190 | User Namespaces |
191 | Docker does not support user namespaces but is a feature currently under development [13]. UID mapping is currently supported by the LXC driver but not in the native libcontainer library.
192 |
193 |
194 | This feature would allow the Docker daemon to run as an unprivileged user on the host but appear as running as root within containers. While using the LXC driver this can by using the -lxc-conf option, as shown in the example Docker run command below.
195 | docker run -lxc-conf="lxc.id_map = u 0 100000 65536" -lxc-conf="lxc.id_map = g 0 100000 65536" ...
196 |
197 |
198 | The specified arguments in the above command will instruct Docker to map UIDs and GIDs 100000 through 65536 on the host to UIDs and GIDs 0 through 65536 to a specific user account, defined at system level on the host in a configuration similar to: [14]
199 | /etc/subgid:<username>:100000:65536
200 | /etc/subuid:<username>:100000:65536
201 | |
202 |
203 |
204 | libseccomp (and seccomp-bpf extension) |
205 | The libseccomp library allows restricting the use of Linux kernel’s syscall procedures based on a white-list approach. Syscall procedures not vital to system operation should ideally be disabled to prevent abuse or misuse within a compromised container.
206 |
207 |
208 | This feature is currently a work in progress (available in LXC driver, not in libcontainer which is now default).
209 |
210 |
211 | To restart the Docker daemon to use the LXC driver use [15]:
212 | docker -d -e lxc
213 |
214 |
215 | Instructions on how to generate a seccomp configuration are on the Docker GitHub repository within the 'contrib' [16] folder. This can later be used to create a LXC based Docker container using the following command:
216 | docker run --lxc-conf="lxc.seccomp=$file" <rest of arguments> |
217 |
218 |
219 | capabilities(7) |
220 | Drop linux capabilities to a minimum whenever possible.
221 | Docker default capabilities include: chown , dac_override , fowner , kill , setgid , setuid , setpcap , net_bind_service , net_raw , sys_chroot , mknod , setfcap , and audit_write .
222 |
223 |
224 | Can be controlled when launching a container from command line with --cap-add=[] or --cap-drop=[] .
225 |
226 |
227 | Example:
228 | docker run --cap-drop setuid --cap-drop setgid -ti <container_name> /bin/sh
229 |
230 |
231 | This feature was introduced in Docker version 1.2 [17] |
232 |
233 |
234 | Multi-tenancy Environments |
235 | Due to the shared nature of Docker containers’ kernel, separation of duty in multi-tenancy environments cannot be achieved securely. It is recommended that containers be run on hosts that have no other purposes and are not used for sensitive operations. Consider moving all services into containers controlled by Docker.
236 |
237 |
238 | When possible, keep inter-container communications to a minimum by setting the Docker daemon to use --icc=false and specify -link with docker run when necessary, or --export=port to expose a port from the container without publishing it on the host.
239 |
240 |
241 | Map groups of mutually-trusted containers to separate machines [18]. |
242 |
243 |
244 | Full Virtualisation |
245 | Use a full virtualisation solution to contain Docker, such as KVM. This will prevent escalation from the container to the host if a kernel vulnerability is exploited inside the Docker image.
246 |
247 |
248 | Docker images can be nested to provide this KVM virtualisation layer as shown in the Docker-in-Docker utility [19]. |
249 |
250 |
251 | Security Audits |
252 | Perform regular security audits of your host system and containers to identify mis-configuration or vulnerabilities that could expose your system to compromise. |
253 |
254 |
255 |
256 |