Article Categories
- All Categories
-
Data Structure
-
Networking
-
RDBMS
-
Operating System
-
Java
-
MS Excel
-
iOS
-
HTML
-
CSS
-
Android
-
Python
-
C Programming
-
C++
-
C#
-
MongoDB
-
MySQL
-
Javascript
-
PHP
-
Economics & Finance
How to add Credentials to Docker ADD command?
Introduction
Security has always been a great threat to mankind. In IT the security of credentials is a tedious task. Here, we are going to discuss various methods to add the credentials to the docker container. Also, the most useful and secure methods are mentioned.
Methods
Adding credentials can be done in a lot of different ways. Some of the types are mentioned below. Each method has its place in the industry. Some are just rejected by the developers due to security issues and some works very well in the case of credential security.
Using the Build arguments in Dockerfile.
Using Environment variables in Dockerfile.
Using Docker Secrets.
Using build arguments
Passing credentials using build arguments is not preferred. This could be a security issue. One of the use cases of the build argument is mentioned below with an example.
Step 1 : Create a Dockerfile and a python program file.
This Dockerfile is going to create a python runtime on the ubuntu base image.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token comment">#declare the build arguments that can be used before FROM in the # Dockerfile.</span> <span class="token instruction"><span class="token keyword">ARG</span> UBUNTU_VERSION=latest</span> <span class="token comment">#use ubuntu as the base image.</span> <span class="token instruction"><span class="token keyword">FROM</span> ubuntu:<span class="token variable">$UBUNTU_VERSION</span></span> <span class="token comment">#declare the build arguments that will be used after FROM command in #Dockerfile.</span> <span class="token instruction"><span class="token keyword">ARG</span> PYTHON_VERSION=2</span> <span class="token comment">#install the python on the ubuntu image</span> <span class="token instruction"><span class="token keyword">RUN</span> apt-get update -y && apt-get upgrade -y && apt-get install python<span class="token variable">$PYTHON_VERSION</span> -y</span> <span class="token comment">#set the working directory.</span> <span class="token instruction"><span class="token keyword">WORKDIR</span> /python/</span> <span class="token comment">#copy the python program to the Docker image.</span> <span class="token instruction"><span class="token keyword">COPY</span> program.py .</span> <span class="token comment">#run this python program whenever this image is used to create a container.</span> <span class="token instruction"><span class="token keyword">CMD</span> python3 program.py</span> </div>
Now create a python file named "program.py".
Output
print("********************Hello from TUTORIALSPOINT*********************")
Step 2 : Build the image
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker build --build-arg PYTHON_VERSION=3 -t busy_python . </div>
Output
Sending build context to Docker daemon 3.584kB
Step 1/7 : ARG UBUNTU_VERSION=latest
Step 2/7 : FROM ubuntu:${UBUNTU_VERSION}
---> 6b7dfa7e8fdb
Step 3/7 : ARG PYTHON_VERSION=2
---> Running in be6541523070
Removing intermediate container be6541523070
---> e3bef06439e8
Step 4/7 : RUN apt-get update -y && apt-get upgrade -y && apt-get install
python$PYTHON_VERSION -y
---> Running in e3ff50442993
Step 5/7 : WORKDIR /python/
---> Running in a147f39ec056
Removing intermediate container a147f39ec056
---> 166cfe1d9514
Step 6/7 : COPY program.py .
---> b09acbeb8f38
Step 7/7 : CMD python3 program.py
---> Running in eec7ec3982de
Removing intermediate container eec7ec3982de
---> 47dbde8eca00
Successfully built 47dbde8eca00
Successfully tagged busy_python:latest
Step 3 : Run the image
Now we will run this image and see if python says hello.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker run busy_python </div>
Output
********************Hello from TUTORIALSPOINT*********************
Hence the build arguments worked.
The disadvantages of Build Arguments
This has security-related issues. The argument?s values can be seen by anyone who has access to the docker history.
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker history busy_python:latest IMAGE CREATED CREATED BY SIZE COMMENT 47dbde8eca00 12 minutes ago /bin/sh -c #(nop) CMD ["/bin/sh" "-c" "pyth? 0B b09acbeb8f38 12 minutes ago /bin/sh -c #(nop) COPY file:a268373fa65eae71? 75B 166cfe1d9514 12 minutes ago /bin/sh -c #(nop) WORKDIR /python/0B 1bdd202b9d86 12 minutes ago |1 PYTHON_VERSION=3 /bin/sh -c apt-getupdat? 70.1MB e3bef06439e8 13 minutes ago /bin/sh -c #(nop) ARG PYTHON_VERSION=20B 6b7dfa7e8fdb 11 days ago /bin/sh -c #(nop) CMD ["bash"] 0B <missing> 11 days ago /bin/sh -c #(nop) ADD file:481dd2da6de715252? 77.8MB </div>
Hence this is not a secure method for credentials.
Using Environment Variables
The build arguments are only available till the build of the image. The environment variables are also available to the image and the container after the build. That is the main difference between build arguments and environment variables.
Here we will use environment variables to pass the credentials to the MySQL database.
Step 1 : Create a Dockerfile
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token comment">#use the mysql as the base image</span> <span class="token instruction"><span class="token keyword">FROM</span> mysql</span> <span class="token comment">#set the required root password</span> <span class="token instruction"><span class="token keyword">ENV</span> MYSQL_ROOT_PASSWORD mypassword@root</span> </div>
Step 2 : Build the image
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$docker build -t mysql_test . </div>
Output
Sending build context to Docker daemon 2.048kB Step 1/2 : FROM mysql ---> 7484689f290f Step 2/2 : ENV MYSQL_ROOT_PASSWORD mypassword ---> Running in 80d7ad7561d4 Removing intermediate container 80d7ad7561d4 ---> a5168465919b Successfully built a5168465919b Successfully tagged mysql_test:latest
Step 3 : Run the image without passing the credentials as that has been already set in the Dockerfile.
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$docker run -d --name cont mysql_test 943d02de21c555618ae9eb4b416faccf00d989020c565a1336afb4743cb6b7b1 </div>
Step 4 : Get inside the MySQL container and use the credentials to start the database.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker exec -it cont /bin/bash </div>
Now start accessing the database.
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;"><span class="token comment"># mysql -h 172.17.0.2 -P 3306 -u root -pmypassword</span> </div>
Output
mysql: [Warning] Using a password on the command line interface can be insecure. Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 8 Server version: 8.0.31 MySQL Community Server - GPL Copyright (c) 2000, 2022, Oracle and/or its affiliates. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. mysql>
Disadvantages
Here MYSQL also gave us a warning about using the password on the command line. This is unsafe to use the password directly on the command line. Also, we should not use the password in the Dockerfile which could be seen using the inspect command in the docker.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker inspect -f "{{ .Config.Env }}" cont
</div>
Output
[PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin GOSU_VERSION=1.14 MYSQL_MAJOR=8.0 MYSQL_VERSION=8.0.31-1.el8 MYSQL_SHELL_VERSION=8.0.31-1.el8 MYSQL_ROOT_PASSWORD=mypassword]
Hence the password is visible.
Using Docker Secrets
If an image is created on your local system and shared with someone else or even published on the Docker Hub. The main aim of Docker Secrets is that the credentials used while creating the image should not be accessible to the user of the image.
In this example, we will create a service container and provide a secret file. Then, commit the container to form an image for later use. Now, run a container using this image and check if the secret message is present or not.
Step 1 : Create a Docker Secret
First, we need to initialize the Docker Swarm manager.
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$docker swarm init </div>
If your Docker Swarm does not start due to IP resolution use --advertiseaddr=ip_of_the_machine and --listen-addr=0.0.0.0
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker swarm init --advertise-addr <ip_of_machine> --listen-addr 0.0.0.0 </div>
Output
Swarm initialized: current node (eksm5jqv8sn8jlr8fwq31n6ht) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1- 1okpgh4spk3nab0mjjzk3c2nx3a68p3l1ww06bx8fu20nvpr0j90vxfk3dsyqvw3s1edzr5k4ou 192.168.43.97:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Now, create Docker Secret using the below command.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$echo 'secret credentials for TUTORIALSPOINT database' | docker secret create ttrlpnt_secret_file - </div>
Output
qmry8v6wsihjuizgtg292ozau
To get complete details about the Docker secret file, use the below command.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker secret ls </div>
Output
ID NAME DRIVER CREATED UPDATED qmry8v6wsihjuizgtg292ozau ttrlpnt_secret_file 2 hours ago 2 hours ago
This means our Docker Secret is ready to be used.
Step 2 : Create a service
We will create a mysql service that will take the above-created Docker Secret as the root password.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker service create --name=ttrlpnt_mysql --secret source=ttrlpnt_secret_file,target=ttrlpnt_secret_file -e MYSQL_ROOT_PASSWORD_FILE="/run/secrets/ttrlpnt_secret_file" mysql:latest </div>
Output
image mysql:latest could not be accessed on a registry to record its digest. Each node will access mysql:latest independently, possibly leading to different nodes running different versions of the image. n7651xa5porbsf4l948vwa33c overall progress: 1 out of 1 tasks 1/1: running [==================================================>] verify: Service converged
Check if the service is running.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker ps </div>
Output
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 27fcefc610c8 mysql:latest "docker-entrypoint.s?" 35 seconds ago Up 31 seconds 3306/tcp, 33060/tcp ttrlpnt_mysql.1.bzkxffaovta8mj5q33ap7z1tl
Step 3: Exec inside the container
Now, we will get inside the container and get the content of the secret file stored in it i.e. the root password.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker exec ttrlpnt_mysql.1.bzkxffaovta8mj5q33ap7z1tl bash -c 'cat /run/secrets/ttrlpnt_secret_file' </div>
Output
secret credentials for TUTORIALSPOINT database
Hence the secret file is present.
Step 4 : Check if the committed image file has the secret data
Create an image from this container.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker commit ttrlpnt_mysql.1.bzkxffaovta8mj5q33ap7z1tl secret_mysql:v1 </div>
Output
sha256:d5fcdc6c3b093485146dfd8e89b2f8be133090bc4ecf3995f4ce409dec30c523
Now inspect the image and check if we get the password for the root.
Example
<div class="code-mirror language-docker" contenteditable="plaintext-only" spellcheck="false" style="outline: none; overflow-wrap: break-word; overflow-y: auto; white-space: pre-wrap;">$ docker inspect -f "{{ .Config.Env }}" secret_mysql:v1
</div>
Output
[MYSQL_ROOT_PASSWORD_FILE=/run/secrets/ttrlpnt_secret_file PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin GOSU_VERSION=1.14 MYSQL_MAJOR=8.0 MYSQL_VERSION=8.0.31-1.el8 MYSQL_SHELL_VERSION=8.0.31-1.el8]
Hence only the path is mentioned and the credentials are secure.
Conclusion
In this article. We learned various ways to pass the credentials to the Docker containers. The security issues related to them are also discussed and solutions are also provided. Using Docker Secrets is one of the most useful and secure ways to give your logins.
