How to provide secrets to a container at build time.
A guide for using environment variables to provide secrets to a Docker container in a GitLab runner to deploy to Kubernetes.
This quick guide provides insight into providing production secret variables to a Docker container containing production code. This procedure is automated in the GitLab runner that contains the secrets in the environment variables and deploys the container to a Kubernetes cluster. However, the deploying part of the solution is omitted.
In the example used for this article, Django is used as a web framework. Using an environment variable as a secret in the settings.py can be done like:
SECRET_SETTING = os.environ["SECRET_ENV_VAR"]
For this setup to work, the environment variable must be set beforehand. If using bash this is done like:
However, the used deployment architecture is using Docker containers to start a production environment and therefore the environment variable must be defined in a Dockerfile used to build the image.
ARG and ENV keywords are considered for that use-case in a Dockerfile. It is important to understand that ARG provides environment variables that are accessible at the time when a container is built but are not available when the container is used after. And ENV provides quite the opposite and provides environment variables after when the built container is used.
As we are using the container to run migrations during the build stage and to run the server later in the Kubernetes, both keywords should be used as recommended here. First, an ARG keyword is used to define the variable at build time and later the value of the ARG variable is passed to the ENV variable so that it can also be accessed after when a container is run. An example of the Dockerfile that uses secret variables and :
If an ARG is defined in a Dockerfile, a default value can be provided. However, for our use case we want to set the value when building and pass the ARG values when building using the — build-arg flag. Example of providing ARG values while building a Dockerfile:
docker build --build-arg SECRET_ENV_VAR_BUILD=$SECRET_ENV_VAR -t registry/name:tag .
When running it in a GitLAb runner this is just one step in the deployment pipeline and is run on a runner. The implementation provided here uses an environment variable of the GitLab runner to get the secret like $SECRET_ENV_VAR. That means this variable should be set in the GitLab control panel to be accessed by the runner. It can be set here by the maintainers of the project:
The examples in this article only use one secret variable which is really unrealistic. In reality, there are a couple of secret variables for different components like databases, email server passwords …
If everything is set up correctly with the deployment pipeline and Kubernetes as well, the source code should not contain any secret variables as those are added when building the project in the GitLab project. This usually presents a more secure implementation as the attack surface of the architecture shrinks considerably if the code can be compromised.