Mounting secrets from Secret Manager as volumes in Cloud Run is actually a way to avoid baking sensitive data directly into your container images.

Let’s see this in action. Imagine a simple Python Flask app that needs a database password. Instead of hardcoding it or putting it in an environment variable that might be visible in some logs, we’ll fetch it from Secret Manager and mount it as a file.

Here’s a main.py:

import os
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    try:
        # Secrets mounted as volumes are typically found in /secrets/<secret-name>
        with open('/secrets/db-password', 'r') as f:
            password = f.read().strip()
        return f'Hello! Your database password is: {password}'
    except FileNotFoundError:
        return 'Database password secret not found!'
    except Exception as e:
        return f'An error occurred: {str(e)}'

if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 8080)))

And here’s a Dockerfile to build this:

FROM python:3.9-slim

WORKDIR /app

COPY requirements.txt requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

COPY main.py main.py

CMD ["python", "main.py"]

requirements.txt just has Flask.

Now, the magic happens when we deploy this to Cloud Run. We don’t bake the password into the image. Instead, we tell Cloud Run to fetch it from Secret Manager and make it available as a file.

Here’s how you’d deploy it using gcloud:

First, create a secret in Secret Manager. Let’s say you have a secret named db-password with the value mySuperSecretDbPass123.

gcloud secrets create db-password --replication-policy="automatic"
echo -n "mySuperSecretDbPass123" | \
  gcloud secrets versions add db-password --data-file=-

Now, deploy the Cloud Run service, mounting this secret:

gcloud run deploy my-secret-app \
  --image gcr.io/your-project-id/my-secret-app:latest \
  --platform managed \
  --region us-central1 \
  --allow-unauthenticated \
  --add-secret /app/secrets/db-password=db-password:latest \
  --set-secrets=/app/secrets/db-password=db-password:latest

Notice the --add-secret and --set-secrets flags. The --add-secret flag is actually deprecated for this specific use case, and --set-secrets is the modern way. It tells Cloud Run: "Take the secret named db-password (version latest) from Secret Manager, and make it available as a file at /app/secrets/db-password inside the container." The path /app/secrets/ is a convention, but you can actually mount it anywhere. The key is that the final component of the path (db-password in this case) becomes the filename.

When your application starts, it can then read this secret from /app/secrets/db-password just like any other file.

The underlying mechanism is that Cloud Run provisions a small, ephemeral volume for each secret you mount. The content of the secret is written to a file within this volume, and then this volume is mounted at the specified path in your container’s filesystem. When the container exits, this volume is discarded. This provides a secure way to inject sensitive configuration without exposing it in environment variables or container images.

The real power here is that you can update the secret in Secret Manager, and then redeploy your Cloud Run service (even without changing your code, if your code is already set up to read from the file path). Cloud Run will then pull the new version of the secret and mount it.

A common misconception is that you need to grant the Cloud Run service account specific permissions to read the secret from Secret Manager. While this is true for fetching secrets via the Secret Manager API within your application code, when you use the --set-secrets flag during deployment, Cloud Run’s control plane handles the authorization and fetching of secrets on your behalf. The service account associated with your Cloud Run service does not need explicit permissions to access the secret via the API for this mounting mechanism to work. The deployment process itself ensures the secret’s content is available to the container.

The next thing you’ll likely want to explore is how to manage multiple secrets and how to handle different versions of secrets effectively.

Want structured learning?

Take the full Cloud-run course →