Docker Security Best Practices

Docker is a popular technology for running applications in containers. When configured correctly, it can be more secure than running applications directly on a host. However, improper setup can lead to vulnerabilities and reduced security.

Check out these guidelines before deploying containers to your dedicated server or vps server and you will be able to avoid security problems in the future.

1. Always install the latest updates for hosts and containers

To avoid known vulnerabilities, such as container data leaks, it is important to regularly update the host system and Docker itself. Containers share the host’s kernel, and if the kernel is vulnerable, it poses a risk to the containers as well. For example, the Dirty COW vulnerability allows an attacker to gain root access to the host even if the container is isolated.

2. Do not expose the Docker daemon socket to external access

The Docker socket /var/run/docker.sock is the main way to interact with the Docker API, and it belongs to root. If someone gains access to this socket, they gain full control of the host. Therefore, do not expose the Docker socket to other containers or enable TCP sockets for the Docker daemon. This provides extra security for both the host and containers.

Example in Docker Compose:

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

3. Always specify a user for containers

Running containers with an unprivileged user is the best way to prevent privilege escalation attacks. You can do this by specifying a user when running the container or adding a user in the Dockerfile.

Example in Dockerfile:

FROM alpine
RUN groupadd -r myuser && useradd -r -g myuser myuser
USER myuser

4. Limit container capabilities

By default, Docker provides containers with a limited set of capabilities. You can remove unnecessary capabilities with --cap-drop or add required ones with --cap-add. Avoid using the --privileged flag, as it gives the container all Linux kernel capabilities, reducing security.

Example:

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

Do not run containers with the –privileged flag!

5. Control inter-container communication

By default, inter-container communication (ICC) is enabled, allowing containers to communicate with each other. Instead of disabling ICC with the –icc=false flag, create custom Docker networks and specify which containers should be connected to them. This allows you to control which containers can communicate with each other.

6. Limit container resources

To prevent DoS attacks, it is better to limit container resources. You can set limits on memory, CPU, restarts, file descriptors, and processes.

Example:

docker run --memory=500m --cpus=1 --ulimit nofile=1024:2048 alpine

7. Set container file system to read-only

Running containers with a read-only file system prevents changes inside the container. For applications that need to store data, use --tmpfs for temporary files.

Example:

docker run --read-only --tmpfs /tmp alpine

Example for Docker Compose:

services:
  alpine:
    image: alpine
    read_only: true

8. Use Docker Secrets for storing sensitive data

Docker Secrets is a secure way to store passwords, tokens, and other sensitive data. Instead of storing them in images or commands, use Docker Secrets.

Example of creating a secret:

docker secret create my_secret /path/to/super-secret-data.txt
docker service create --name web --secret my_secret nginx:latest

Docker Compose:

version: "3.8"
secrets:
  my_secret:
    file: ./super-secret-data.txt
services:
  web:
    image: nginx:latest
    secrets:
      - my_secret

By following these practices, you can improve the security of your containers and safely deploy services on a linux vps or in Kubernetes.