On Linux, Docker leverages most of the common Linux security and workload isolation technologies. These include:
- control groups (cgroups)
- mandatory access control (MAC) systems
Docker Swarm Mode is secure by default.
Docker Content Trust lets you sign your images and verify the integrity and publish of images you consume.
Image security scanning analyses images, detects known vulnerabilities, and provides detailed reports.
Docker secrets are stored in the encrypted cluster store, encrypted in-flight when delivered to containers, stored in in-memory filesystems when in use, and operate a least-privilege model.
Kernel namespaces slice up an operating system so it looks and feels like multiple isolated operating systems. This is why you can run multiple web servers on the same OS without experiencing port conflicts.
Each network namespace gets its own IP address and full range of ports.
You can run multiple applications, each requiring their own version of a shared library or configuration file. To do this, you run each application inside its own mount namespace. This works because each mount namespace can have its own isolated copy of any directory on the system (e.g. /etc, /var, /dev).
Docker on Linux currently utilizes the following kernel namespaces:
- Process ID (pid)
- Network (net)
- Filesystem/mount (mnt)
- Inter-process Communication (ipc)
- User (user)
- UTS (uts)
Docker containers are an organized collection of namespaces.
Every container has its own
uts, and potentially
user namespace. A container is an organized collection of these namespaces.
Process ID Namespace
Docker uses the
pid namespace to provide isolated process trees for each container. Every container gets its own PID 1. PID namespaces also mean that one container cannot see or access the process tree of other containers. Nor can it see or access the process tree of the host on which it’s running.
Docker uses the
net namespace to provide each container with its own isolate network stack. This stack includes:
- IP addresses
- port ranges
- routing tables
Every container gets its own eth0 interface with its own unique IP and range of ports.
Every container gets its own unique isolate root (/) filesystem. This means every container can have its own /etc, /var, /dev constructs. Processes inside a container cannot access the
mnt (mount) namespace of the Linux host or other containers.
Inter-process Communication Namespace
Docker uses the
ipc namespace for shared memory access within a container. It also isolates the container from shared memory outside the container.
Docker lets you use
user namespaces to map users inside a container to different users on the Linux host. A common example is mapping a container’s root user to a non-root user on the Linux host.
Control groups are about setting limits.
Containers are isolated from each other, but all share a common set of OS resources, such as CPU, RAM, network bandwidth, and disk I/O. Cgroups let us set limits on each of these resources so a single container can’t consume everything and cause a denial of service (DoS) attack.
It’s a bad idea to run containers as root. However, non-root users are almost powerless.
The Linux root user is a long list of capabilities. Docker works with capabilities so you can run containers as root, but strips out all the capabilities you don’t need.
This is an example of implementing least privilege.
Docker uses seccomp, in filter mode, to limit the syscalls a container can make to the host’s kernel.
All new containers get a default seccomp profile, configured with sensible defaults. You can customize these profiles, and also pass a flag to Docker so containers can be started without a seccomp profile.
SELinux, or Security-Enhanced Linux, is a part of the Linux security kernel that acts as a protective agent on servers. In the Linux kernel, SELinux relies on mandatory access controls (MAC) that restrict users to rules and policies set by the system administrator. SELinux acts under the least-privilege model.
The interaction between SELinux policy and Docker is focused on two concerns:
- protection of the host
- protection of containers from one another.
AppArmor is a Linux security model that protects an operating system and its applications from security threats. Docker expects to find an AppArmor policy loaded and enforced.
Docker automatically generates a default profile for containers named
docker-default. The Docker binary generates this profile in
tmpfs and then loads it into the kernel.
When you run a container, it uses the docker-default policy unless you override it with the security-opt option. For example, the following explicitly specifies the default policy:
docker run --rm -it --security-opt apparmor=docker-default hello-world
Securing Docker Swarm
By default, Swarm Mode includes:
- Cryptographic node IDs
- TLS for mutual authentication
- Secure join tokens
- CA configuration with automatic certificate rotation
- Encrypted cluster store (config DB)
- Encrypted networks
When you initialize a Swarm with a manager and workers:
- node1 is configured as the first manager of the swarm and also as the - root certificate authority (CA).
- the swarm itself is given a cryptographic clusterID.
- node1 has issued itself with a client certificate that identifies it as a manager in the swarm.
- certificate rotation is configured with the default value of 90 days.
- a cluster config database is configured and encrypted.
- a set of secure tokens is created so new managers and workers can join the swarm.
To rotate tokens:
docker swarm join-token --rotate manager
Existing managers don’t need updating, but you’ll need to the new token to add new managers.
Join tokens are stored in the cluster store, which is encrypted by default.
TLS and Mutual Authentication
Every manager and worker that joins the swarm is issued a client certificate. This certificate is used for mutual authentication. It identifies the node, the Swarm it’s a member of, and the role the node performs in the Swarm.
You can configure the certificate rotation period with the following command:
docker swarm update --cert-expiry 720h
The Cluster Store
The cluster store is the brains of the swarm and where cluster config and state are stored. If you’re not running in swarm mode, there are many technologies and security features you’ll be unable to use.
The store is based on
etcd and is automatically configured to replicate itself to all managers in the swarm. It is also encrypted by default.
Signing and Verifying Images with Docker Content Trust
Docker Content Trust (DCT) makes it simple to verify the integrity and publisher of images you pull and run. DCT allows developers to sign images when they’re pushed to Docker Hub and other registries. DCT can also be used to provide context, e.g. whether an image has been signed for use in a particular environment (prod or dev).
You need a cryptographic key-pair to sign images:
docker trust key generate <key-name>
DCT uses three keys:
- Root/offline key
- Repository/tagging key
- Timestamp key
The root key is crucial! Don’t lose it, else you’ll need to contact Docker Support to reset it. The root key belongs to one person or organization.
The repository key is associated with an image repository. The last key (the timestamp) denotes image freshness.
To sign an image:
docker trust sign <username/image:tag>
To inspect the signed image:
docker trust inspect <username/image:tag>
To revoke a signature from an image:
docker trust revoke <username/image:tag>
You can force a Docker host to always sign and verify image push and pull operations by exporting the
DOCKER_CONTENT_TRUST environment variable with a value of
Once the above environment variable is set, when you push an image, you’ll be prompted to create root and repository keys.
DOCKER_CONTENT_TRUST set to
1, all images pulled or pushed must be signed, unless they are official or verified images.
You could override DCT with
docker image pull --disable-content-trust <image-name> but you’d be unable to run the image as a container.
0 to disable it.
Transport Layer Security (TLS)
TLS ensures authenticity of the registry endpoint and that traffic to/from the registry is encrypted.
You use TLS (HTTPS) to protect the Docker daemon socket. If you need Docker to be reachable safely through HTTP rather than SSH, you can enable TLS be specifying the
tlsverify flag and pointing Docker’s
tlscacert flag to a trusted CA certificate.
To configure the Docker engine to use a registry that is not configured with TLS certificates from a trusted CA, pass the
--insecure-registry flag to the dockerd daemon at runtime. Also, place the certificate in
/etc/docker/certs.d/dtr.example com/ca.crt on all cluster nodes. These two steps will save you from receiving the error
’x509: certificate signed by unknown authority`.
For the exam, always remember the difference between DCT and TLS. The exam tries to confuse you about them.
Mutually Authenticated Transport Layer Security (MTLS)
- Both participants in communication exchange certificates and all communication is authenticated and encrypted.
- When a swarm is initialized, a root certificate authority (CA) is created, which is used to generate certificates for all nodes as they join the cluster.
- Worker and manager tokens are generated using the CA and are used to join new nodes to the cluster.
- Used for all cluster-level communication between swarm nodes.
- Enabled by default, you don’t need to do anything to set it up.
Role-Based Access Control (RBAC)
RBAC is performed by creating grants. The grant consists of:
- Subject (person or team)
- Collection (resources)
- Role (privileges)
The subject is the team, or one of more users, who will access a certain collection/resource with granular roles/privileges.
You can make the grant and its components using the UCP or the command line.
RBAC works the same way in Docker and Kubernetes.
- Create users
- Create a collection (you can include or exclude children/grandchildren)
- Create a role
- Create a grant
A grant defines who (subject) has how much access (role) to a set of resources (collection). Each grant is a 1:1:1 mapping of subject, role, and collection.
For example the masters team has all to all secret operations in the kubeadmins collection.
- encrypted at rest
- encrypted in-flight
- mounted in containers to in-memory filesystems
- operate under least-privilege model
The default location of secrets inside a Docker container is
Secrets are not available to standalone containers, only to Swarm services.
To create a secret, use the following command format:
echo "This is an external secret" | docker secret create my_external_secret -
Don’t miss that dash at the end!
To list secrets, use:
docker secret ls
Secrets are not available to standalone containers.
Using Secrets with Services
You can attach secrets to services by specifying the
--secret flag to the
docker service create command.
To add or remove secrets to or from an existing service, use:
docker service update --secret-add <secret-name> docker service update --secret-rm <secret-name>
Using Secrets with Stacks
You need to use at least version 3.1 for secrets.
Here’s an example:
version: '3.1' services: psql: image: postgres secrets: - psql_user - psql_password secrets: psql_user: file: ./psql_user.txt psql_password: external: true
psql_user secret is created from a file, while
psql_password is an existing secret.
Removing a Stack also removes the secrets.