I used to hardcode my password in my demos and code samples. I know it's not a good practice, but it's just for demo purposes, it cannot be that dramatic, right? I know there are proper ways to manage sensitive information, but this is only temporary! And it must be complicated to remove all the passwords from a deployment... It turns out, IT IS NOT difficult at all, and that will prevent serious threats.
In this post, I will share how to remove all passwords from a docker-compose file using environment variables. It's quick to setup and easy to remember. For production deployment, it's better to use secrets, because environment variables will be visible in logs. That said, for demos and debugging and testing, it's nice to see those values. The code will be available on GitHub. This deployment was used for my talks during Azure Developers .NET Days: Auto-Generate and Host Data API Builder on Azure Static Web Apps and The most minimal API code of all... noneThe Before Picture
For this deployment, I used a docker-compose file to deploy an SQL Server in a first container and Data API Builder (DAB) in a second one. When the database container starts, I run a script to create the database tables and populate them.
services:
dab:
image: "mcr.microsoft.com/azure-databases/data-api-builder:latest"
container_name: trekapi
restart: on-failure
volumes:
- "./startrek.json:/App/dab-config.json"
ports:
- "5000:5000"
depends_on:
- sqlDatabase
sqlDatabase:
image: mcr.microsoft.com/mssql/server
container_name: trekdb
hostname: sqltrek
environment:
ACCEPT_EULA: "Y"
MSSQL_SA_PASSWORD: "1rootP@ssword"
ports:
- "1433:1433"
volumes:
- ./startrek.sql:/startrek.sql
entrypoint:
- /bin/bash
- -c
- |
/opt/mssql/bin/sqlservr & sleep 30
/opt/mssql-tools/bin/sqlcmd -U sa -P "1rootP@ssword" -d master -i /startrek.sql
sleep infinity
As we can see, the password is in clear text twice, in the configuration of the database container and in the parameter for sqlcmd when populating the database. Same thing for the DAB configuration file. Here the data-source node where the password is in clear text in the connection string.
"data-source": {
"database-type": "mssql",
"connection-string": "Server=localhost;Database=trek;User ID=sa;Password=myPassword!;",
"options": {
"set-session-context": false
}
}
First Pass: Environment Variables
The easiest password instance to remove was in the sqlcmd command. When defining the container, an environment variable was used... Why not use it! To refer to an environment variable in a docker-compose file, you use the syntax $$VAR_NAME
. I used the name of the environment variable MSSQL_SA_PASSWORD
to replace the hardcoded password.
/opt/mssql-tools/bin/sqlcmd -U sa -P $$MSSQL_SA_PASSWORD -d master -i /startrek.sql
Second Pass: .env File
That's great but the value is still hardcoded when we assign the environment variable. Here comes the environment file. They are text files that holds the values in key-value paired style. The file is not committed to the repository, and it's used to store sensitive information. The file is read by the docker-compose and the values are injected. Here is the final docker-compose file:
services:
dab:
image: "mcr.microsoft.com/azure-databases/data-api-builder:latest"
container_name: trekapi
restart: on-failure
env_file:
- .env
environment:
MY_CONN_STRING: "Server=host.docker.internal;Initial Catalog=trek;User ID=sa;Password=${SA_PWD};TrustServerCertificate=True"
volumes:
- "./startrek.json:/App/dab-config.json"
ports:
- "5000:5000"
depends_on:
- sqlDatabase
sqlDatabase:
image: mcr.microsoft.com/mssql/server
container_name: trekdb
hostname: sqltrek
environment:
ACCEPT_EULA: "Y"
MSSQL_SA_PASSWORD: ${SA_PWD}
env_file:
- .env
ports:
- "1433:1433"
volumes:
- ./startrek.sql:/startrek.sql
entrypoint:
- /bin/bash
- -c
- |
/opt/mssql/bin/sqlservr & sleep 30
/opt/mssql-tools/bin/sqlcmd -U sa -P $$MSSQL_SA_PASSWORD -d master -i /startrek.sql
sleep infinity
Note the env_file
directive in the services definition. The file .env
is the name of the file used. The ${SA_PWD}
tells docker compose to look for SA_PWD
in the .env
file. Here is what the file looks like:
SA_PWD=This!s@very$trongP@ssw0rd
Conclusion
Simple and quick. There are no reasons to still have the password in clear text in the docker compose files anymore. Even for a quick demo! Of course for a production deployment there are stronger ways to manage sensitive information, but for a demo it's perfect and it's secure.
During Microsoft Build Keynote on day 2, Julia Liuson and John Lambert talked about how trade actors are not only looking for the big fishes, but also looking at simple demos and old pieces of code, looking for passwords, keys and sensitive information.