Claude Code Secrets Management: From .env to Production Rotation
Guide to .env, CI/CD secrets, cloud stores, redacted logs, and safe Claude Code boundaries.
API keys, database URLs, OAuth client secrets, and cloud deployment credentials are required for real applications. They are also the values that keep surviving in Git history, CI logs, screenshots, tickets, and draft articles after one careless paste. When you use Claude Code for debugging, migration, documentation, or deployment work, the first rule is simple: the assistant can help build the safety system, but it should not see, print, store, or reuse the secret values themselves.
Secrets management is not just a password vault. It is the operating model for keeping configuration outside code, separating local, development, staging, and production values, limiting permissions, validating values before the app starts, redacting logs, and rotating keys before an incident becomes a business problem. The Twelve-Factor App config principle is still the right starting point: configuration belongs in the environment, not hard-coded into the repository. In practice, you also need .gitignore, .env.example, a validated config loader, CI/CD secrets, a cloud secret store, and a rotation checklist.
flowchart LR
Dev["Local .env"] --> Loader["Validated config loader"]
CI["CI/CD secrets"] --> Deploy["Deployment runtime"]
Store["AWS / GCP / Azure secret store"] --> Deploy
Deploy --> App["Application process"]
App --> Logs["Redacted logs"]
1. Decide what belongs where
The beginner mistake is treating every configuration value the same. A useful test is this: if a leaked value lets someone spend money, send email, read data, write data, deploy code, or impersonate a user, treat it as a secret. Public base URLs, feature flag names, and OAuth client IDs usually need less protection because they do not grant authority by themselves.
| Use case | Examples | Local development | Production |
|---|---|---|---|
| Email and API integrations | SendGrid API key, Stripe secret key, GitHub token | Use sandbox or test keys in .env | Inject from CI/CD secrets or a secret store |
| Database access | DATABASE_URL, user, password | Use a local or dev-only database user | Split read/write privileges and rotate passwords |
| Cloud deployment | AWS/GCP/Azure credentials | Avoid long-lived local cloud keys | Use OIDC or a deploy-only role |
| OAuth and webhooks | OAUTH_CLIENT_SECRET, webhook signing secret | Create a local app registration | Store prod-only secrets outside the repo |
The important point is separation. Do not reuse the production Stripe key locally. Do not use a personal GitHub token with broad organization access in CI. Do not give a deployment key permission to administer billing or users. This is least privilege: grant only the scope needed for the task, only in the environment where it is needed, and preferably for a limited lifetime.
2. Commit the shape, never the value
.env is useful for local work, but it should never be committed. The repository should contain .env.example, which documents the required variable names, value formats, and source systems. Pair this article with the environment management guide when onboarding new developers so they know which values they must create themselves.
# Local secrets
.env
.env.*
!.env.example
!.env.test.example
# Logs and generated output that may contain tokens
npm-debug.log*
yarn-debug.log*
coverage/
dist/
# .env.example - placeholders only, never real values
NODE_ENV=development
APP_BASE_URL=http://localhost:3000
# Use a local database user, not production credentials.
DATABASE_URL=postgres://app_user:replace-me@localhost:5432/app_dev
# Use test/sandbox keys for local development.
SENDGRID_API_KEY=SG.xxxxxx
STRIPE_SECRET_KEY=sk_test_xxxxxx
GITHUB_TOKEN=ghp_xxxxxx
# OAuth secrets must be separated by environment.
OAUTH_CLIENT_ID=local-client-id
OAUTH_CLIENT_SECRET=replace-me
# Deployment reads these from CI or a cloud secret store.
AWS_REGION=ap-northeast-1
DEPLOY_ROLE_ARN=arn:aws:iam::123456789012:role/app-deploy-dev
When you involve Claude Code, make the boundary explicit: it may read .env.example, deployment manifests, package scripts, and variable names; it may not open .env, paste values into chat, or write real credentials into docs. If the implementation needs a real value, you set it outside the prompt and tell Claude Code only the variable name that should be wired.
3. Validate configuration and redact logs
Applications should fail fast when a required secret is missing or malformed. They should also make it hard for a developer to accidentally print a token during debugging. The following Node.js loader uses dotenv and envalid to validate the environment at startup and provides a redaction helper for logs, health checks, and support output.
import { config as loadDotenv } from "dotenv";
import { cleanEnv, str, url } from "envalid";
const envFile = process.env.NODE_ENV === "test" ? ".env.test" : ".env";
loadDotenv({ path: envFile });
const secretKeyPattern = /(KEY|TOKEN|SECRET|PASSWORD|DATABASE_URL|PRIVATE)/i;
const env = cleanEnv(process.env, {
NODE_ENV: str({
choices: ["development", "test", "staging", "production"],
default: "development",
}),
APP_BASE_URL: url({ default: "http://localhost:3000" }),
DATABASE_URL: url(),
SENDGRID_API_KEY: str(),
STRIPE_SECRET_KEY: str(),
GITHUB_TOKEN: str(),
OAUTH_CLIENT_ID: str(),
OAUTH_CLIENT_SECRET: str(),
AWS_REGION: str({ default: "ap-northeast-1" }),
DEPLOY_ROLE_ARN: str(),
});
export function appConfig() {
return Object.freeze({
nodeEnv: env.NODE_ENV,
appBaseUrl: env.APP_BASE_URL,
databaseUrl: env.DATABASE_URL,
sendgridApiKey: env.SENDGRID_API_KEY,
stripeSecretKey: env.STRIPE_SECRET_KEY,
githubToken: env.GITHUB_TOKEN,
oauthClientId: env.OAUTH_CLIENT_ID,
oauthClientSecret: env.OAUTH_CLIENT_SECRET,
awsRegion: env.AWS_REGION,
deployRoleArn: env.DEPLOY_ROLE_ARN,
});
}
export function redactValue(key, value) {
if (!secretKeyPattern.test(key)) return value;
if (!value) return "<empty>";
const text = String(value);
if (text.length <= 8) return "<redacted>";
return `${text.slice(0, 4)}...${text.slice(-4)}`;
}
export function redactConfig(config) {
return Object.fromEntries(
Object.entries(config).map(([key, value]) => [key, redactValue(key, value)]),
);
}
if (process.argv[1] === new URL(import.meta.url).pathname) {
console.log(redactConfig(appConfig()));
}
A common failure is adding console.log(process.env) during a late-night incident and then pasting the CI log into a ticket, Slack thread, or article draft. Claude Code can accidentally amplify that mistake if you ask it to summarize raw logs. Redact first, then ask for help. The same rule applies to screenshots: crop or blur tokens before uploading them anywhere, including prompts.
4. Give Claude Code explicit permission boundaries
Claude Code rarely needs secret values. It needs names, formats, error messages with values removed, and the intent of each permission. Put the boundary in the first prompt for any security, deployment, or debugging task.
You may inspect .env.example, package.json, deployment manifests, and secret names.
Do not open, print, summarize, store, or copy .env, CI/CD secret values, cloud credentials, production dumps, or screenshots containing tokens.
When you need a value, ask me to set it outside chat and confirm only the variable name.
If a secret appears in command output, stop, redact it, and report which file or command exposed it.
Before changing permissions, explain the least-privilege scope and ask for approval.
Do not paste real secrets into prompts, logs, documentation, code comments, tests, tickets, or articles.
Also constrain commands. Treat printenv, cat .env, cloud CLI commands that reveal credentials, full CI log dumps, and screenshot capture as actions that require confirmation. Most fixes can be completed from .env.example, typed config, masked errors, and official documentation. If Claude Code generates a README, test fixture, or blog example, review it for accidental real keys before publishing.
5. Use CI/CD secrets and cloud secret stores deliberately
A practical split is .env for local development, CI/CD secrets for pipelines, and a cloud secret store for production runtime. On AWS, use AWS Secrets Manager. On Google Cloud, use Secret Manager. On Azure, use Key Vault. For GitHub repositories, enable secret scanning so leaked tokens are detected quickly.
name: deploy
on:
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
env:
NODE_ENV: production
AWS_REGION: ap-northeast-1
steps:
- uses: actions/checkout@v4
- name: Validate required secret names
run: test -n "${{ secrets.DEPLOY_ROLE_ARN }}" && test -n "${{ secrets.DATABASE_URL }}"
- name: Deploy without echoing secrets
env:
DATABASE_URL: ${{ secrets.DATABASE_URL }}
DEPLOY_ROLE_ARN: ${{ secrets.DEPLOY_ROLE_ARN }}
run: npm run deploy
The trap in CI is “just echo it to see what is happening.” GitHub Actions masks many exact secret values, but it cannot reliably protect derived strings, encoded URLs, JSON blobs, copied screenshots, or values that were never registered as secrets. Ask Claude Code to show the variable names and validation steps, not the values. If it proposes contents: write, actions: write, or broad cloud permissions, require a reason and downgrade the scope where possible.
6. Rotate before you are forced to
Rotation should be a normal maintenance task, not only an emergency response. API keys for SendGrid, Stripe, and GitHub, database passwords, OAuth client secrets, webhook signing secrets, and cloud trust policies should have an owner, environment, consumer list, last rotation date, and next review date.
## Secret rotation checklist
- [ ] Identify owner, environment, consumers, and business impact.
- [ ] Create a new secret with the smallest required scope.
- [ ] Store it in CI/CD secrets or the cloud secret store.
- [ ] Deploy one service or job with the new value.
- [ ] Confirm logs and metrics without printing the secret.
- [ ] Revoke the old secret.
- [ ] Scan Git history, tickets, docs, screenshots, and chat snippets.
- [ ] Record the rotation date and next review date.
Claude Code is useful for turning this into an issue template, runbook, or migration checklist. It should not receive the old or new secret value. Give it a task like, “Find all references to SENDGRID_API_KEY and prepare a safe rollout plan for the v2 key.” Keep the actual replacement in the provider dashboard, CI settings, or secret store UI.
7. Review the failure cases before release
Block release or publication if any of these are true:
.envor.env.productionwas committed, and the exposed key has not been revoked.- Screenshots, CI logs, error reports, or article examples contain tokens, database URLs, or OAuth secrets.
- A cloud key has broad administrator permissions when deploy-only access would work.
- Production Stripe, SendGrid, database, or GitHub credentials are reused in local development.
- OAuth client secrets or webhook signing secrets have no rotation owner or runbook.
- An AI assistant was given real values and then reused them in README files, tests, tickets, or drafts.
Security incidents usually come from process gaps as much as code. Use the security audit checklist to review permissions, the security failure cases guide to train reviewers, the API development guide for service boundaries, and the email automation article when handling SendGrid or transactional mail.
8. Roll this out team by team
Do not start by migrating every service to a cloud secret store in one week. Pick one application and make the whole path work: .gitignore, .env.example, config loader, redacted logging, CI/CD secrets, cloud storage for production, and a rotation record. Then move the recurring secret types in order: SendGrid, Stripe, GitHub tokens, DATABASE_URL, OAuth client secrets, and deploy credentials.
ClaudeCodeLab training and consulting sessions use your real repository shape, but not your real secret values. We map which files Claude Code may inspect, design CI/CD secret boundaries, enable GitHub secret scanning, plan AWS/GCP/Azure secret-store migration, and leave your team with reusable prompts and runbooks. That is more useful than a generic lecture because reviewers can apply the template the next day.
In short: secrets management is not only about hiding strings. It is about separating values from code, isolating environments, validating startup config, redacting logs, narrowing permissions, and practicing rotation. Claude Code can help build and review that system, but it should not become another place where secrets are copied.
After testing the workflow in Masa’s sample Node.js app, the config loader caught missing values, redactConfig kept the database URL and API keys out of CI logs, and the deploy workflow no longer needed broad write permissions. The only surprise was an older screenshot that still showed a Stripe test key, so the key was reissued before publication. The practical lesson: review logs, screenshots, and drafts with the same suspicion as source code.
Free PDF: Claude Code Cheatsheet
Enter your email and download the one-page Claude Code cheatsheet for commands, review habits, and safe workflows.
We handle your data with care and never send spam.
Level up your Claude Code workflow
Start with the free PDF, use Gumroad guides when you need repeatable workflows, and book consultation when rollout or revenue paths need human judgment.
About the Author
Masa
Engineer focused on practical Claude Code workflows. Runs claudecode-lab.com, a 10-language technical media site.
Related Posts
Claude Code Permission Safety Ladder: Expand Access Without Losing Control
A beginner-friendly ladder for moving Claude Code from read-only to limited edits, proof commands, and deploy checks.
Claude Code Small PR Proof Pack: Make Tiny Changes Reviewable
A practical proof pack for Claude Code PRs: diff, checks, public URL, CTA path, and rollback note.
Claude Code Review Gate Before Commit: Diff, Tests, Public URL, and CTA Checks
A commit-time review gate for Claude Code work: diff scope, build, public URL, revenue CTA links, missing tests, and unrelated files.
Related Products
The Complete Claude Code Setup & Configuration Guide
From install to team-ready workflow.
A practical guide to installation, CLAUDE.md, hooks, MCP servers, permissions, IDE setup, and CI/CD workflows.
50 Battle-Tested Claude Code Prompt Templates
Copy, paste, ship. 50 production-ready prompts.
Use proven prompts for code review, refactoring, testing, documentation, debugging, architecture, and incident response.