Strengthening your Docker Container Security with 10 best practices
Ensuring a Safe and Secure Environment for Your Containers with this 10 best practices.
Docker is a popular tool used for containerization of applications. While Docker has many advantages, security remains a concern for many organizations.
In this article, we will discuss Docker security best practices to help you ensure the security of your Docker containers and the applications running inside them.
Use the latest version of Docker
It is critical to use the most recent version of Docker to ensure the security, stability, and features of your Docker environment. There are often security updates, bug fixes, and performance enhancements with each new version of Docker that help keep your containers and host system secure and reliable.
Furthermore, new Docker versions may contain new features and capabilities that might improve the functioning of your Docker system. You can assure that your environment is up to date and that you can obtain help from Docker if you use the most recent version of Docker.
Overall, it is advised that you upgrade to the most recent version of Docker on a frequent basis to guarantee that your Docker environment is performing optimally.
Limit container privileges
For security reasons, container rights must be restricted. When you start a Docker container, it runs as a process on the host system and has access to all of the host system’s resources. Limiting the container’s permissions reduces the risk of attackers gaining access to the host system or other containers.
You can, for example, use the user
argument to provide a non-root user to run the container, or the cap-drop
flag to remove particular Linux privileges that the container does not require.
# generate clean, final image for end users
FROM alpine:3.11.3
# Create a non-root user with a home directory
RUN adduser -D non_root_user
# Set the working directory to the home directory of the non-root user
WORKDIR /home/non_root_user
# Copy everything into non_root_user
COPY --from=builder /app/cmd .
# Set the ownership and permissions of the echo binary
RUN chown non_root_user:non_root_user /home/non_root_user/cmd && \
chmod 500 /home/non_root_user/cmd
# Switch to the non-root user
USER non_root_user
Explanation : The docker file creates a non-root user called
non_root_user
, sets the working directory to the home directory of thenon_root_user
user, copies thecmd
binary into the container, and sets the ownership and permissions of thecmd
binary.See sample code : https://github.com/pcpratheesh/docker-with-non-root-user-sample
Use a secure base image
Using a secure base image is essential because it instills trust and dependability in your Docker environment. A secure base image is one that has been tested for vulnerabilities and built with security in mind.
You may limit the risk of security vulnerabilities and guarantee that your containers are built on a stable and trustworthy foundation by choosing a secure base image. A secure base image may include security patches, hardened settings, and security and compliance best practices.
Also can save time and effort in building and maintaining a secure Docker environment, as many security considerations are already taken care of by the base image.
FROM golang:1.17-alpine AS builder
# Set the working directory
WORKDIR /app
# Copy go mod and sum files
COPY go.mod go.sum ./
# Install dependencies
RUN go mod download
# Copy the application code
COPY . .
# Build the application
RUN go build -o app
# Use a secure base image for the runtime environment
FROM scratch
# Copy the application binary from the builder image
COPY --from=builder /app/app .
# Run the application
CMD ["./app"]
Explanation : After building the application, we are using a minimal and secure
scratch
base image for the runtime environment. This image does not include any OS or package manager, which helps minimize the attack surface of the container.
Remove unnecessary packages
Every package deployed in a Docker image enhances the container’s attack surface. If a package contains known security flaws, it might be exploited to obtain access to the underlying host system. We may lower the chance of security breaches by eliminating unneeded packages from the container’s attack surface.
It can also be reduce the size of image and it would include shorter deployment time, reduced storage costs, and better network transfer rates.
Here is a sample
# Use an official Golang runtime as a parent image at stage 1
FROM golang:1.17-alpine AS build
# Set the working directory to /app
WORKDIR /app
# Copying current directory contents into the container at /app
COPY . .
# Install any necessary dependencies
RUN apk add --no-cache git
# download the golang dependancies
RUN go mod download
# Build the app
RUN go build -o app .
# Use a minimal Alpine-based image as a parent image
FROM alpine:3.14
# Copy the binary from the previous stage
COPY --from=build /app/app /app/app
# Remove unwanted packages
RUN apk del git
# Set the working directory to /app
WORKDIR /app
# Run the binary
CMD ["./app"]
Explanation : The Dockerfile sets the parent image to the official Golang runtime image and installs any necessary dependencies. It then builds the application and stores it in a binary file called
app
. In the second stage it only copies what we want to run the application(the binary).The benefit of multi-stage builds is that they can help reduce the size of your Docker images. By using multiple stages, you can eliminate any unnecessary files and packages that were required for building your application but are not needed at runtime. This can result in smaller images that are faster to download and deploy.
Use Docker Secrets
It allows us to store sensitive information securely and give it to your containers as environment variables or files. You may keep critical information distinct from your application code and configuration files with Docker Secrets, lowering the risk of exposure. The confidential data is encrypted in transit and at rest, and access is restricted to those who require it.
create secret in docker
docker secret create my_first_secret my_first_secret.txt
And then you can use os package to read the secrets
my_first_secret = os.GetEnv("MY_FIRST_SECRET")
or we could define the secrets
section of the docker-compose.yml
file.
version: '3.7'
services:
app:
build: .
secrets:
- db_user
- db_password
- db_host
ports:
- "8080:8080"
volumes:
mysecrets:
external: true
secrets:
db_user:
file: secrets/db_user.txt
db_password:
file: secrets/db_password.txt
db_host:
file: secrets/db_host.txt
There are several methods in which we can implement the secrets depending on the specific use case and requirements of the application.
With
Docker-compose
,Docker Swarm
,External Key-Value store
and Config management tools such asAnsible
,Puppet
.See sample code : https://github.com/pcpratheesh/docker-with-secret-sample
Use container orchestration tools
The use of container orchestration tools may significantly improve the security of Docker deployments. These solutions simplify managing the operation of containerized applications over several hosts, resulting in increased security via features such as container isolation, load balancing, and automatic scaling.
Container orchestration tools like Kubernetes, Docker Swarm provide a centralized control plane for managing containers, which allows for easy implementation of security policies and best practices.
Here are some popular container orchestration tools
Keeping container Up to date
Keeping your container up to date is critical to its security. Security flaws in new versions of container images and applications can be found and patched. If you are running an out-of-date container, you are vulnerable to attackers who can exploit known flaws in your software.
To keep your container up to date, regularly check for and apply updates to your container images and the software running inside them. Use automated tools to monitor for new vulnerabilities and apply patches as needed.
Monitor the Containers
Monitoring your containers is an essential aspect of maintaining the security. Docker provides a built-in container monitoring tool called Docker Stats, which allows you to view various statistics.
Monitoring your containers regularly using various monitoring tools can help you detect potential security risks, vulnerabilities, or performance issues, and take appropriate action to mitigate them before they cause any harm.
Here are some popular container monitoring tools
Use container registries
Docker images should be stored in secure container registries like Docker Hub
, Google Container Registry
, or Amazon Elastic Container Registry
(ECR)
.
When you use a registry, you can manage and control the images you use for your containers, making sure they are up-to-date, secure, and coming from a trusted source
Use container hardening techniques
Techniques like image signing, container immutability, and runtime protection can be used to harden containers against attacks.
One of the container hardening is to limit the number of network ports that are exposed to the container. By limiting the exposed ports to only those that are required for the container’s functionality, you can reduce the attack surface of your environment. You should also avoid running containers as the root user and to use container firewall to containers network traffic.
In conclusion, leveraging Docker security best practices is essential for maintaining a secure container environment. This includes utilizing encryption and authentication measures to protect data in transit as well as minimizing user access privileges to only those necessary for their roles within the organization.
Additionally, it is important to perform regular backups of container images along with their associated configurations so changes can quickly be reverted if necessary without losing vital information during an incident response scenario.
I hope this article helps. Thank you so much for reading. :)
Learn more :