Using docker swarm secrets in PSS®X production¶
If you want to use Docker containers in production, chances are you’ll want to store your credentials in a secure way.
Docker also includes a more extensive secrets solution, accessed via the docker secret
command group, but it only works with services deployed to a Swarm cluster.
Swarm secrets are managed by your cluster and will be securely replicated to each node within it. Secrets are guaranteed to be highly available, like the other cluster-level data created by the swarm.
Secrets are encrypted during transit and storage. They’re held in memory, so they’re not persisted on individual nodes or container filesystems. Additionally, nodes only receive the secrets required by the containers they’re running, further minimizing the risk of exposure.
Creating a Swarm¶
Because docker secrets only work in Swarm mode, you’ll need access to a swarm before you can try it. Run the following command to create a new single-node swarm on your current machine:
docker swarm init
Creating Secrets¶
Once you’ve created a swarm, you can use docker secrets to start managing your secrets. First create a local file that holds your secret value:
"yourStrong(!)Password" | Set-Content -Path mssql_sa.pwd -Encoding Ascii -Force -NoNewline
echo "yourStrong(!)Password" > mssql_sa.pwd
Next, create the Docker secret object. The command takes two arguments: the secret’s name, and the path to the file that contains its value:
docker secret create MSSQL_SA_PASSWORD mssql_sa.pwd -
docker secret create MSSQL_SA_PASSWORD mssql_sa.pwd -
One another possible way to store secrets with Vault.
To store a secret;
"yourStrong(!)Password" | vault write secret/mssql_sa -
echo "yourStrong(!)Password" | vault write secret/mssql_sa -
To retrieve a secret and put it into your Docker swarm:
vault read -field=value secret/mssql_sa | docker secret create MSSQL_SA_PASSWORD -
echo "yourStrong(!)Password" | vault write secret/mssql_sa -
Referencing docker swarm secrets in compose files¶
You can reuse Swarm secrets in services managed by Docker Compose. Create the secret using docker secret create
, then reference it within the services
section of your docker-compose.yml
file by setting the external
field to true
:
services:
sqlserver:
...
environment:
- MSSQL_SA_PASSWORD_FILE=/run/secrets/MSSQL_SA_PASSWORD
secrets:
- MSSQL_SA_PASSWORD
secrets:
MSSQL_SA_PASSWORD:
external: true
When you set external: true
in your Compose file, it tells Docker that the secret doesn’t need to be created by the Compose file itself. Instead, it should already exist and be available when the Compose is run. If the secret isn’t there, it will result in an error.
The long syntax provides more granularity in how the secret is created within the service's containers.
source:
The name of the secret as it exists on the platform.target:
The name of the file to be mounted in/run/secrets/
in the service's task container, or absolute path of the file if an alternate location is required. Defaults tosource
if not specified.uid
andgid
: The numeric UID or GID that owns the file within/run/secrets/
in the service's task containers. Default value is USER running container.mode:
The permissions for the file to be mounted in/run/secrets/
in the service's task containers, in octal notation. The default value is world-readable permissions (mode0444
). The writable bit must be ignored if set. The executable bit may be set.
The following example sets the name of the Default__Ssl__CertPassphrase
secret file to Redis__Connections__Ssl__CertPassphrase
within the container, sets the mode to 0440
(group-readable), and sets the user and group to 103
.
services:
sqlserver:
...
environment:
...
secrets:
- source: Default__Ssl__CertPassphrase
target: Redis__Connections__Ssl__CertPassphrase
uid: "103"
gid: "103"
mode: "0440"
secrets:
Default__Ssl__CertPassphrase:
external: true
Using docker secrets in PSS®X backing services¶
Now, you will probably want to reference secrets from your environment variables (e.g: MSSQL_SA_PASSWORD), but that is unfortunately NOT supported yet.
Secrets are accessible from the containers that have access to them by using the file path /run/secrets/MSSQL_SA_PASSWORD
, so what you can do, is add another environment variable to your docker-compose, having a custom name (appending _FILE for example)
services:
sqlserver:
...
environment:
- MSSQL_SA_PASSWORD_FILE=/run/secrets/MSSQL_SA_PASSWORD # This will be directed to => `MSSQL_SA_PASSWORD` environment variable with help of bash script.
And in your container entrypoint, call the following function for each environment variable you have set up
This will export the value stored in the secret to the correct environment variable. In this case MSSQL_SA_PASSWORD
exported as environment variable.
#!/usr/bin/env bash
# By setting an environment variable matching *_FILE to a file path, the prefixed environment
# variable will be overridden with the value specified in that file
echo "Configure environment variables of the mssql..."
mssql_env_vars=(
MSSQL_SA_PASSWORD
)
for env_var in "${mssql_env_vars[@]}"; do
file_env_var="${env_var}_FILE"
if [[ -n "${!file_env_var:-}" ]]; then
if [[ -r "${!file_env_var:-}" ]]; then
export "${env_var}=$(< "${!file_env_var}")"
unset "${file_env_var}"
else
warn "Skipping export of '${env_var}'. '${!file_env_var:-}' is not readable."
fi
fi
done
unset mssql_env_vars
echo "Starting sql server..."
/opt/mssql/bin/sqlservr
All PSS®X backing services automatically map to environment variables with the _FILE
suffix.
Using docker secrets in PSS®X .net core application configuration files¶
In ASP.NET Core application the configuration is based on key-value pairs established by configuration provider. Configuration providers read configuration data into key-value pairs from a variety of configuration source like settings files, environment variables, etc.
This is how a configuration file is added to an application:
...
builder.Host
.ConfigureAppConfiguration((context, config) =>
{
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
config.AddEnvironmentVariables();
};
...
and this is how a configuration may look like for a connection string looks like:
"ConnectionStrings": {
"Default": "pssx-sql-server;User Id=sa;Password=myPassword;Initial Catalog=pssx-app;MultipleActiveResultSets=true;TrustServerCertificate=True",
"Hangfire": "pssx-sql-server;User Id=sa;Password=myPassword;Initial Catalog=pssx-hangfire;MultipleActiveResultSets=true;TrustServerCertificate=True"
}
In the above example the password is stored in plain text and unencrypted and this is not safe.
Now we need to read docker secrets files and pull them into the .net core configuration. This can be easily achieved with the Docker Secrets.NET Core configuration provider for PSSX.