In a production environment, one way to strengthen Docker containers is to make them immutable, that is, read-only. Other ways to run containers securely include minimizing the attack surface and applying Linux security processes, standard Linux security processes and specific processes for container environments to be applied.
Passing in the --read-only tag when starting the container can run it in read-only mode. This prevents any process from writing to the file system. Any action attempting to write will result in an error. Running this immutable infrastructure also aligns with best practices for other software deployment pipelines.
Although immutability can prevent any malicious scripts from being executed, changes caused by vulnerabilities exposed by other software running in the container can be prohibited. But in a real production environment, is this model suitable for applications? For example, the log files to be generated and the applications to be used in the database need writability.
A possible solution to writing logs could be to use a centralized logging system, such as Elasticsearch/Logstash/Kibana (ELK), so that all logs are collected in a central node, possibly in another container, and are not directly accessible to the user. Another alternative is to export the logs outside the container by using the --log-driver tag when starting the container. For applications that require write permissions to temporary directories like /tmp, one solution is to load a temporary file system for these directories in the container.
End users cannot access the database directly, so the risk is low. However, this does not rule out the possibility of attack unless the application facing the user is strengthened.
In the case where it is inevitable that there is a writable file system, Docker provides auditing and changing rollback capabilities. The file system in the Docker container is a stack of layers. When a new container is created, a new layer is added at the top that can be written. The Docker storage driver hides these details and delivers it to users as a normal file system. Writes to running containers will be written to this new layer. This is often referred to as copy-on-Write (COW).
Configuration drift or expected configuration changes are easily detected in Docker containers. The "docker diff" command can display changes to the file system - whether the change operation is a file addition, deletion, or modification.
In addition to running a read-only container where possible, we also make the following suggestions to ensure the safety of containers in production environments:
- Run a minimal image like Alpine Linux, designed based on security thinking. It has a grsecurity unofficial ported patch on its kernel. Gsecurity is a set of security enhancements to the Linux kernel, which includes permission control and eliminating the possibility of vulnerability-based memory crashes by minimizing those methods that can cause the system to be attacked.
- Limit the use of CPU, RAM and other resources to prevent DoS attacks.
- Configure thread and process restrictions in the operating system.
- Adopt standard Linux kernel hardening programs such as sysctl.
- Only one application is run in each container. This is recommended because it reduces the attack surface, i.e. for a given container, the number of possible vulnerabilities depends only on the application running on that container.