Security Analysis of Docker Containers in Build Process
The Rise of DevOps and Micro-Services Architecture
The concept of DevOps has gained significant popularity in recent years, with a great emphasis on the relationship between Development and Operations teams. DevOps is a combination of Dev (Development) and Ops (Operations), where Dev is responsible for development, and Ops is responsible for deployment online. Before the arrival of Docker, companies needed to build a database environment from scratch. With the arrival of Docker, companies can now build their own database environment on a number of open-source base images.
Most DevOps Sets in CI Pipeline Set Docker
Most DevOps environments are set up in Continuous Integration (CI) pipelines with Docker, which means that any build environment will use Docker containers. These build environments need to accept user-supplied code that is untrusted and executable, so it is very meaningful to explore how these codes can be securely contained.
Security Risks in Build Environment
In this article, we will explore how small misconfigurations can lead to serious security risks in the build environment. We will not describe the inherent flaws in Heroku, Docker, or AWS CodeBuild, but rather focus on the vulnerabilities found in multi-tenant environments with Docker containers.
Normal Operation and Special Circumstances
Although Docker container technology provides a very stable security default setting, in special circumstances, small misconfigurations can lead to serious security risks. The build environment can have a special architecture, such as:
- A fully managed generation service that can compile source code, run tests, and deploy software packages, available on AWS CodeBuild.
- A Docker build Docker container service.
- Docker containers can create a Docker-in-Docker (Dind) environment, where two attackers need to escape the container.
Attack Surface Minimization
Using CodeBuild can further minimize the attack surface, as you have to provide a disposable container to AWS, and the tenant will not interact with each other in the build process.
Attacker’s Perspective
The first thing to do in most build or pipeline processes is to create a CI that contains the code you want to build and deploy, which is stored in a Git repository. These codes are then packed and transferred to the build environment, and finally applied to the Docker build process. By looking at the building service, you can usually configure the container in two ways: by Dockerfile or config.yml.
Config-ci.yml
Prior to the further build process begins, the file will be converted to Dockerfile during the build process. If you have Dockerfile environment explicitly specified to use, you can change the config-ci.yml to the following content:
version: '3'
services:
web:
build: .
ports:
- "80:80"
depends_on:
- worker
worker:
build: .
depends_on:
- web
Dockerfile
The Dockerfile is used to build the Docker image. The content of the Dockerfile is as follows:
FROM python:3.9-slim
# Set working directory to /app
WORKDIR /app
# Copy requirements file
COPY requirements.txt .
# Install dependencies
RUN pip install -r requirements.txt
# Copy application code
COPY . .
# Expose port 80
EXPOSE 80
# Run command when container starts
CMD ["python", "app.py"]
Pre-Build Process Attack
Before entering the building Docker, the first thought is to try and interrupt the build process, or try to file from CodeBuild environment linked to the context of my Docker built in. Since I have control of the content file config-ci.yml, more specifically, I control is the “relative path Dockerfile to be used,” so I can try to use an old-fashioned method of attack - directory traversal attacks.
Error Message
Once the build process begins, I will immediately get the following error message:
Error: Cannot find Dockerfile in the current directory.
Attack the Build Process
Let us return to the actual build process, to see what can be attacked? Since the build process occurs in a Dind Docker container, the container is a disposable CodeBuild running instance. To seek further attacks, the docker build process will run all the commands in a disposable Docker container.
Docker Containers
Docker containers are put together packaged applications and environments, it is a building, multiple release. For example, after you finished the previous program development, testing and operation and maintenance personnel who need to deploy, by docker only one run command.
Attack the Build Process to Identify Vulnerabilities
The greatest benefit is standardized docker interactive applications, while supporting a number of different platforms and multiple different cloud service providers, as long as the machine can hold docker, can undifferentiated run the program. Every step Docker actually constructed a new Docker container, which can be seen from the output of the build process.
Dind
Dind need to run their own Docker daemon. However, as a result Dind way is to use a host system docker example (dockerd instance), to allow the host and the background image sharing Docker, and benefit from all caches in Docker.
Security Vulnerabilities
The Docker usually build process will not be able to interact with the daemon Docker, however, in this case, but they can interact. Keen observer might notice, TCP port dockerd daemon is by --host = tcp: //0.0.0.0: 2375 be mapped.
Docker Network Functions
Unless otherwise noted, all containers will be placed in the same default Docker network. This means that each container are able to communicate with other containers, without obstruction. Now, I build a temporary container (the container executing user code) been able to send a request to the network hosting its Dind container.
Implementation Dockerfiles Attack
To test Dockerfiles attack, I can offer the following Dockerfile to build the system, so that I can interact with access to the container being built. This Dockerfile will install some dependencies, namely docker and netcat.
Reverse Shell
The Dockerfile will create a reverse shell when building and running. When the building happens, I will receive a reverse connection. Now remote interactive access, I can check whether access to the Docker daemon.
Stack Processing Carried Out
At this point, I have a shell, but it is a disposable container building, the effect is not great. In addition, I can also access Docker daemon. So I thought, put the two together what will happen? For this reason, I introduced a second Dockerfile, it creates a reverse shell when building and running.
New Reverse Shell
Now, a new reverse shell will be connected to the 4446 attack on the port system. So I will be in a new container, and direct access to the underlying CodeBuild host’s file system and network.
Mitigation Measures
In this case, the repair is very simple, never Docker daemon to bind to all interfaces. Delete --host = tcp package from the script: //0.0.0.0: 2375 lines can also fix this vulnerability. In addition, you do not need to bind to a TCP port, because the unix socket has passed --host = unix: ///var/run/docker.sock map.
Conclusion
Although the container strategy provides a good mechanism to allow you to run untrusted code to create a secure environment without the need for additional virtual process. However, as the safety of these vessels and their configuration. By default, they are very safe, but only a small configuration error can make the entire security environment collapse.