Docker is a great technology that simplifies the development and deployment of distributed applications. While building dockerized applications, security must be considered at multiple levels. Because containers share the host kernel (no separate hypervisor), Docker security is implemented primarily in software and requires careful configuration.
A Docker container in a nutshell has the following:
- Kernel shared with the host.
- Linux namespaces provide isolation for Processes (
pid), IPC (ipc), Storage (mnt), Network (net), and Users (user). - Linux cgroups provide resource limiting and accounting for CPU, memory, and I/O bandwidth.
- Unique filesystem (
rootfs) isolated from host and managed by Docker as layers. For example,/etc/resolv.confin a container is independent from the host's/etc/resolv.conf. - All libraries and configuration files required for the containerized application are self-contained in the container filesystem.
Below are prominent security areas to consider: kernel hardening, application capabilities, and additional best practices.
1. Kernel hardening
- Containers share the host kernel. Harden the host kernel to reduce attack surface. Enable SELinux (
CONFIG_SECURITY_SELINUX) and run SELinux inenforcingmode where possible. - Use seccomp to restrict syscalls available to container processes. Docker (since 1.10) supports default seccomp profiles (a
default.jsonof allowed syscalls). Tailor a custom seccomp profile by tracing the application's syscalls (for example, withstrace) and allowing only the required calls. - Example: run a container with a custom seccomp profile:
docker run --rm -it --security-opt seccomp=custom_profile.json custom_app
2. Application capabilities
Linux capabilities let you split the all-powerful root privilege into specific privileges. Docker containers start with a limited set of capabilities. Inspect the capabilities your process runs with and drop anything not required.
Example: start a centos container and inspect capabilities
# Start a shell inside a container
docker run -i -t centos /bin/bash
# (inside the container) find capabilities for the PID 1 process (bash)
getpcaps 1
# or use pscap (libcap-ng-utils) to list capabilities
pscap -a
Typical capability output might look like:
cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap+eip
Best practice: start by dropping all capabilities and then add back only the minimum required:
docker run --rm -it --cap-drop=ALL --cap-add=NET_BIND_SERVICE custom_app
3. Other security best practices
- Use trusted images: Pull images from trusted registries and minimize reliance on generic distro images for production. Prefer hardened, minimal base images or build your own from a secure build pipeline.
- Run as non-root user: Containers default to root unless you change the UID. Use the Docker
-uoption or define a non-root user in the Dockerfile (USER) to avoid running apps as root. - User namespaces: Use user namespaces so that root inside a container maps to an unprivileged UID on the host. This reduces damage if a container breakout occurs, especially for containers that write to host volumes.
- Isolate privileged services: If an app truly needs host-level privileges (for example, an SSH server), run it in a dedicated bastion VM or a highly isolated container, not mixed with general-purpose application containers.
- /dev, /proc and /sys: The
/devnamespace should be constrained to only expose required devices. Docker already mounts/procand/sysin a restricted way; avoid adding extra host mounts unless necessary. - Avoid SUID binaries: Don’t include SUID binaries in container images; use capabilities instead if a specific privilege is needed.
- Network exposure: Carefully consider which ports you publish. If a port must be blocked at runtime, use host-level firewall rules (iptables/nftables).
- Resource limiting: Use cgroup options when launching containers to limit memory, swap, and CPU:
# Limit swap memory to 400M docker run --memory-swap=400M custom_app # Constrain container to logical CPU 0 docker run --cpuset-cpus=0 custom_app
Following these guidelines helps run Docker containers in a safer environment and significantly reduces application attack vectors.


