beginner10 minutesevnx v0.2.1+

Migrate to GCP Secret Manager

Generate gcloud CLI commands to store each .env variable as an individual secret in Google Cloud Secret Manager.

Migrate to GCP Secret Manager

evnx migrate --to gcp-secret-manager prints a gcloud secrets create block per variable, piping the value through stdin — the GCP-recommended pattern for creating secrets without exposing values in shell history.


What you need

  • gcloud CLI installed and authenticated (gcloud auth login)
  • A GCP project set (gcloud config set project YOUR_PROJECT)
  • The Secret Manager API enabled (gcloud services enable secretmanager.googleapis.com)

evnx does not need GCP credentials — it only generates commands.


What evnx generates

Unlike AWS (one JSON object), GCP Secret Manager stores one secret per variable. evnx prints a pipe block for each key:

Bash
echo -n "${DATABASE_URL}" | \
  gcloud secrets create DATABASE_URL \
    --data-file=- \
    --replication-policy=automatic

echo -n "${STRIPE_SECRET_KEY}" | \
  gcloud secrets create STRIPE_SECRET_KEY \
    --data-file=- \
    --replication-policy=automatic

The value is passed through --data-file=- (stdin), which avoids logging the secret value in shell history or process lists.

Alternative with evnx convert. For GCP, evnx offers a second path: evnx convert --to gcp-secrets upload.sh && bash upload.sh. Both produce equivalent gcloud commands. Use migrate when you want filtering and key transforms; use convert when you want a static shell script to commit or share.


Basic usage

Bash
evnx migrate --to gcp-secret-manager

gcp is accepted as a shorthand:

Bash
evnx migrate --to gcp

Step-by-step walkthrough

Enable the API and authenticate

Bash
gcloud services enable secretmanager.googleapis.com
gcloud auth login
gcloud config set project YOUR_PROJECT_ID

Validate your .env

Bash
evnx validate --strict

Preview the migration

Bash
evnx migrate --to gcp --dry-run
☁️ GCP Secret Manager migration

Dry-run — would upload to GCP Secret Manager:
  Secrets : 12

Filter what you need

Bash
evnx migrate \
  --to gcp \
  --exclude "*_LOCAL,*_TEST" \
  --dry-run

Generate and run the commands

Pipe to a script, review it, then execute:

Bash
evnx migrate \
  --to gcp \
  --exclude "*_LOCAL,*_TEST" \
  > gcp-upload.sh

cat gcp-upload.sh    # inspect
bash gcp-upload.sh   # run

Or run directly from a .env with values already exported:

Bash
set -a && source .env && set +a
evnx migrate --to gcp --exclude "*_LOCAL" | bash

Grant access to your service accounts

Each secret must be granted to the service account your application runs as:

Bash
gcloud secrets add-iam-policy-binding DATABASE_URL \
  --member="serviceAccount:myapp@PROJECT.iam.gserviceaccount.com" \
  --role="roles/secretmanager.secretAccessor"

Updating existing secrets

The generated gcloud secrets create command fails if a secret already exists. To update a version instead:

Bash
# Add a new version to an existing secret
echo -n "${DATABASE_URL}" | \
  gcloud secrets versions add DATABASE_URL --data-file=-

evnx does not currently detect existing GCP secrets or generate versions add commands. Run evnx migrate --to gcp --dry-run to see the list, then decide manually whether to create or update.


Replication policy

evnx uses --replication-policy=automatic in all generated commands, which lets GCP choose the storage regions. For a specific region:

Bash
# Edit the generated script to replace --replication-policy=automatic with:
--replication-policy=user-managed \
--locations=us-central1

Reading secrets in your application

GCP-native applications can use the Secret Manager client library:

Python
from google.cloud import secretmanager

client = secretmanager.SecretManagerServiceClient()
name = "projects/PROJECT_ID/secrets/DATABASE_URL/versions/latest"
response = client.access_secret_version(request={"name": name})
DATABASE_URL = response.payload.data.decode("UTF-8")

Or in Cloud Run / GKE, mount secrets as environment variables via the --set-secrets flag or a pod spec — no code changes needed.


Minimum IAM permissions

For creating secrets (migration time):

RoleWhen
roles/secretmanager.adminCreating new secrets
roles/secretmanager.secretVersionAdderAdding versions to existing secrets

For reading secrets (application runtime):

RoleScope
roles/secretmanager.secretAccessorGrant per secret or at project level

Next steps