Understanding Docker Secret Mounts

A comprehensive guide to using Docker secret mounts correctly, avoiding common mistakes, and implementing secure practices for handling sensitive data in containers.

Nadeesha Cabral on 10-12-2024

One of the most common mistakes developers make is accidentally exposing secrets in their Docker images. Consider this problematic example:

# DON'T DO THIS

ARG NPM_TOKEN
ENV NPM_TOKEN=$NPM_TOKEN
RUN echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc

This approach seems convenient but is fundamentally flawed because:

  • The secret becomes part of the image layer history
  • Anyone with access to the image can extract the secret
  • The secret persists even after being "removed"

The Right Way: Using Secret Mounts

Docker provides a secure way to handle secrets during build time using secret mounts. Here's the correct approach:

# DO THIS INSTEAD

RUN --mount=type=secret,id=npm_token \
 NPM_TOKEN=$(cat /run/secrets/npm_token) \
 echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" > .npmrc

Key Characteristics of Secret Mounts

  1. Temporary Access

    • Secrets are only available during the specific build step
    • They're not persisted in the final image or layer history
  2. Filesystem Mounting

    • Secrets are mounted at /run/secrets/<secret_name>
    • Each secret gets its own file in this directory
  3. Build-time Only

    • Secrets mounted this way are only available during build time
    • They're automatically cleaned up after the build step completes

Using Secrets in Docker Compose

For runtime secrets in a Docker Compose environment, you can define them in your compose file:

services:
  myapp:
    image: myapp:latest
    secrets: - my_secret
    build:
      context: .
secrets: - npm_token
secrets:
  my_secret:
    file: ./my_secret.txt
  npm_token:
    environment: NPM_TOKEN

How to use multi-stage builds with secrets

  1. Use Build-time Secrets for Dependencies

Imagine that you have a private npm package that you need to install for a docker container that you need to distribute. However, you don't want the consumers of the docker container to have access to the npm token. Baking that into the image via an ARG or ENV instruction is a bad idea. Instead, you can use a multi-stage build to install the npm package and then remove the secret.

# Example for private npm packages

RUN --mount=type=secret,id=npm_token \
 npm config set //registry.npmjs.org/:\_authToken=$(cat /run/secrets/npm_token) && \
 npm install && \
 npm config rm //registry.npmjs.org/:\_authToken
  1. Multi-stage Builds with Secrets
FROM node:alpine AS builder
RUN --mount=type=secret,id=npm_token \

# Use secret for building

FROM node:alpine

# Final image has no trace of secrets

COPY --from=builder /app/dist ./dist

Subscribe to our newsletter for high signal updates from the cross section of AI agents, LLMs, and distributed systems.

Maximum one email per week.

Subscribe to Newsletter