Secrets Management skill for Codex

No plaintext keys, rotation you have rehearsed. Codex inventories where credentials live without printing them, picks a store that fits the platform (cloud secret manager, Vault or OpenBao, SOPS in Git), and wires workloads to read only their own secrets through an identity they already have. Rotation uses overlapping credentials so nothing breaks, and a leaked key is revoked before anyone touches Git history.

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- secrets-management

Installs to ~/.agents/skills/secrets-management/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $secrets-management, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Moves application secrets out of code, env files and CI variables into a managed store - HashiCorp Vault or OpenBao, SOPS with age keys in Git, AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, External Secrets Operator for Kubernetes - and sets up least-privilege access, dynamic credentials and zero-downtime rotation. Use when choosing where secrets live, encrypting secrets committed to a repo, wiring secrets into Kubernetes or CI, rotating a credential, or responding to a leaked key.

Use it when

  • Secrets sit in code, env files, CI variables or Helm values in plaintext
  • A team is choosing between Vault, SOPS and a cloud secret manager
  • Kubernetes workloads need secrets synced from an external store
  • A credential needs rotating or has leaked

Use something else when

  • You need to scan repositories and history for leaked secrets: use secret-scanning
  • The concern is how CI jobs receive credentials: use secrets-in-ci

How to check the result

Scanners find no live secrets in the tree or history, workloads start with store access and fail clearly without it, and a staging rotation drill completes with zero failed requests.

The mistake it prevents

Scrubbing a leaked key from Git history before revoking it, when the key must be assumed copied the moment it was pushed.

~/.agents/skills/secrets-management/SKILL.md

--- name: secrets-management description: Moves application secrets out of code, env files and CI variables into a managed store - HashiCorp Vault or OpenBao, SOPS with age keys in Git, AWS… license: MIT ---

Done well: no plaintext secret in Git, images, logs or shell history; each workload reads only its own secrets with an identity it already has (IAM role, Kubernetes service account, OIDC) rather than a bootstrap password; every secret has an owner and a rotation path that has been exercised; and a leak is handled by revoking first.

Inspect first

  1. Find where secrets live today: rg -n --hidden -g '!.git' -i "(api[_-]?key|secret|passw|token|BEGIN .*PRIVATE KEY)" . and check .env*, CI variables, Helm values, Terraform state, Docker build args. Use gitleaks git . or trufflehog git file://. for history if installed (see secret-scanning).
  2. Read AGENTS.md and infra code to find the cloud, the orchestrator, and the existing identity mechanism (instance roles, workload identity, IRSA or EKS Pod Identity).
  3. List each secret with: consumer, owner, how it is issued, and whether the issuer supports two valid credentials at once (needed for zero-downtime rotation).

Never print secret values in chat or logs while inspecting; report locations and names only.

Choose the store

SituationDefault
Single cloud, app on that cloudThat cloud’s manager: AWS Secrets Manager (or SSM Parameter Store SecureString for config), GCP Secret Manager, Azure Key Vault
Multi-cloud or on-prem, need dynamic DB/cloud credentialsVault (or its open-source fork OpenBao)
Small team, GitOps, secrets must be versioned with configSOPS with age keys (or cloud KMS) committed encrypted
Kubernetes consuming any of the aboveExternal Secrets Operator syncing into Secrets
Developer laptopsPassword manager CLI (op run, bw) or sops exec-env, not shared .env files

Do not run Vault just to store ten static strings; its operational cost (unseal, HA, upgrades, audit) is real.

SOPS with age

age-keygen -o ~/.config/sops/age/keys.txt         # private key stays local or in CI secret
# .sops.yaml
creation_rules:
  - path_regex: secrets/prod/.*\.yaml$
    age: age1prodrecipient...,age1breakglass...
  - path_regex: secrets/.*\.yaml$
    age: age1devrecipient...
    encrypted_regex: ^(data|stringData|password|token|.*_key)$
sops --encrypt --in-place secrets/prod/api.yaml
sops secrets/prod/api.yaml                       # edit decrypted in $EDITOR, re-encrypts on save
sops --decrypt secrets/prod/api.yaml | kubectl apply -f -   # only with user confirmation
sops updatekeys secrets/prod/api.yaml            # after changing recipients in .sops.yaml
  • Keys stay readable in diffs; only values are encrypted. Review that encrypted_regex covers every sensitive field.
  • Removing a recipient does not revoke what they already decrypted; rotate the secrets too.
  • Prefer cloud KMS recipients (kms:, gcp_kms:, azure_keyvault:) for production so access follows IAM rather than a key file.

Cloud managers

aws secretsmanager get-secret-value --secret-id prod/api/db --query SecretString --output text
gcloud secrets versions access latest --secret=api-db-password
az keyvault secret show --vault-name acme-prod --name api-db-password --query value -o tsv
  • Grant read on specific secret ARNs or names, not secretsmanager:* on *.
  • Fetch at startup and cache in memory with a refresh interval; per-request calls cost money and add latency. AWS provides caching clients for common languages.
  • Name secrets by environment and service (prod/api/db) so IAM policies can use prefixes.

Vault

vault kv put secret/api/prod [email protected]   # @file avoids shell history
vault kv get -field=db_password secret/api/prod
  • Authenticate workloads with the Kubernetes, AWS, or JWT/OIDC auth methods; never bake a token into an image.
  • Use the database secrets engine for per-pod, short-TTL DB credentials where possible; it removes rotation as a separate task.
  • Policies per service path (path "secret/data/api/prod" { capabilities = ["read"] }); note KV v2 policies use secret/data/... while the CLI uses secret/....
  • Enable an audit device before going to production.

Kubernetes

apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata: { name: api-db }
spec:
  refreshInterval: 1h
  secretStoreRef: { kind: ClusterSecretStore, name: aws-sm }
  target: { name: api-db }
  data:
    - secretKey: DB_PASSWORD
      remoteRef: { key: prod/api/db, property: password }
  • Kubernetes Secrets are base64, not encrypted. Enable encryption at rest (KMS provider) and restrict get/list on Secrets via RBAC.
  • Mount as files when the app can reload; env vars need a pod restart to pick up rotation (use a checksum annotation or Reloader).
  • Older clusters may only serve external-secrets.io/v1beta1; match the installed CRD version.

Rotation without downtime

  1. Create the new credential while the old one stays valid (dual users, two API keys, or Secrets Manager’s alternating-users rotation).
  2. Update the store; roll consumers (or wait for the refresh interval).
  3. Confirm no consumer still uses the old credential (DB pg_stat_activity by user, API provider’s last-used timestamp, access logs).
  4. Revoke the old credential.

Schedule: database and service credentials 90 days or dynamic; signing keys per their spec; anything a departed employee could have read, immediately.

Leaked secret response

  • Revoke or rotate the credential first, before cleaning Git history. A pushed secret must be assumed copied, even from a private repo.
  • Check the issuer’s logs for use since the leak time.
  • Remove it from code, replace with a store lookup, add a pre-commit scanner.
  • History rewrite (git filter-repo) and force push only with explicit user approval; coordinate with everyone who has clones, and remember forks and CI caches keep copies.

Rotating production credentials, deleting secrets or versions, and force pushes all need the user’s explicit confirmation.

Verification

  • Scanner over the working tree and history finds no live secrets.
  • Each workload starts with its store access and fails closed (clear error) without it.
  • A rotation drill in staging completes with no failed requests.
  • IAM or Vault policy review: no wildcard read across environments.

Output template

## Secrets inventory: <system>
| Secret | Consumer | Store | Access identity | Rotation | Owner |
|---|---|---|---|---|---|
| prod/api/db | api pods | AWS SM | IRSA role api-prod | 30-day alternating users | platform |
Found in plaintext: <file:line, values not shown>
Actions requiring approval: <rotations, deletions, history rewrite>

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Secrets Management"
  short_description: "No plaintext keys, rotation you have rehearsed"
  default_prompt: "$secrets-management Get the database password and API keys out of our .env files and into AWS Secrets Manager"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem