While working on my current side project, I read about the recommendation to pass secrets to Docker containers using Docker secrets. Until now, I have been passing API keys, passwords, and other sensitive information as environment variables. So I thought this would be a good opportunity to learn about Docker secrets and how to use them.
What are Docker Secrets?
Use Docker secrets to securely pass sensitive information to your containers. Secrets are stored in encrypted form and are only available at runtime to services that have been granted access to them.
This reminds me of how hosted services like Supabase or Vercel handle secrets. You define the secret in advance and then reference it in your configuration. But instead of being stored in an environment variable, they are available as a file in the container (e.g. /run/secrets/my_secret
).
Availability
This feature is only available in Docker Swarm or with Docker Compose.
Reading Secrets
You can read secrets from a file in your application code. For example, in a Bun application, you can read the secret from a file like this:
As you can see in the example above, the location of the secret is typically still defined as an environment variable. For example, the official Postgres Docker image uses the env variable POSTGRES_PASSWORD_FILE
to define the location of the password file. This is just a best practice and other official images follow this suggestion as well.
So in my current side project I use the same approach and pass the location of the secret file to both my application and the Postgres container at runtime.
Development
Since you are not typically running your application out of a Docker container in development, you need to make sure you pass secrets yourself. Either put a file in your project root, or provide the secret as an environment variable to be used preferentially if no secrets path is provided.
Trim Your Secrets
As you may have noticed in the example above, I trim the secret before using it. This actually cost me a lot of headaches because I kept getting authentication errors with the database while implementing this feature.
In my case, I was using Docker Compose to run my application and the Postgres database. I kept the password file right next to the docker-compose.yml
and referenced it like this:
Note that this docker-compose.yml
is truncated for brevity.
There were no newlines or other invisible characters in the file. There are still none to this day… But I kept getting authentication errors. After a lot of debugging, console.log
ing, and just trying random things, I finally tried trimming the secret before using it.
And it worked! 🥳
My wife was sitting next to me on the couch when I finally got it to work, and she got pretty scared when I started screaming in excitement. Sorry, honey! 🫣
Conclusion
Docker secrets are a great way to pass sensitive information to your containers. You can use it with Docker Compose or Docker Swarm. Just make sure you trim the secret before using it. 😜