Expert · DevSecOps · topic 47 of 53 · 30 min
Secrets management
Explanation
What counts as a secret?
A secret is any value that lets someone access or change something. If a stranger who found it could log in, read data, spend money or pretend to be your service, it is a secret.
- Passwords and database connection strings that contain a password
- API keys and tokens (payment gateway keys, GitHub tokens, SMS provider keys)
- Cloud access keys (for example an AWS access key ID with its secret access key)
- Private keys: SSH keys, TLS certificate keys, code-signing keys
- Webhook signing secrets, OAuth client secrets, kubeconfig files with credentials
Ordinary configuration, such as a port number or a feature flag, is not secret. Keep the two apart: configuration can live in Git, secrets cannot.
How secrets leak
| Where | How it happens | Prevention |
|---|---|---|
| Git history | A .env file is committed, then deleted in the next commit. It is still in the history. | .gitignore, pre-commit scanning, push protection |
| Logs | The app logs full request headers or all environment variables | Log only what you need; mask tokens |
| Container images | ENV PASSWORD=... in a Dockerfile, or COPY . . copies .env | .dockerignore, pass secrets at run time |
| CI output | echo $TOKEN, or set -x prints every command with its values | Use the CI secret store; never print secrets |
| Screenshots and chat | A terminal screenshot in a ticket or a key pasted in a team chat | Share through a secret manager, not chat |
Public repositories are scanned by automated bots within minutes of a push. If a cloud key is pushed to a public repository, assume it has already been copied.
Prevention: stop it before the push
A pre-commit hook is a small script that Git runs on your machine before it creates a commit. gitleaks is a free open-source scanner that looks for secret patterns. Run it as a hook so a secret never enters history, and again in CI as a safety net. On GitHub, secret scanning finds known token formats in repositories, and push protection blocks a push that contains one.
# .pre-commit-config.yaml
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.24.2 # pin a release tag; update it from time to time
hooks:
- id: gitleakspip install pre-commit
pre-commit install # add the hook to this repository
pre-commit run --all-files # scan everything once
gitleaks git -v # scan the whole Git history (older versions: gitleaks detect -v)Where secrets should live
| Option | What it is | Notes |
|---|---|---|
| HashiCorp Vault / OpenBao | A central secret store with access policies, audit logs and dynamic secrets | OpenBao is a community fork of Vault under the Linux Foundation |
| Cloud secret managers | AWS Secrets Manager, Azure Key Vault, Google Secret Manager | Access controlled by cloud IAM; rotation built in for some secrets |
| Kubernetes Secrets | Objects that hold small secret values for pods | Only base64-encoded by default: turn on encryption at rest and restrict who can read them |
| External Secrets Operator | Copies secrets from a vault or cloud manager into Kubernetes Secrets | The source of truth stays in the secret manager |
| Sealed Secrets | Encrypts a Secret so the encrypted version can be stored in Git | Only the controller inside the cluster can decrypt it |
Short-lived credentials and OIDC from CI
A long-lived key stored in CI works until someone leaks it, and then it works for the attacker too. A short-lived credential expires on its own, often within an hour. OIDC (OpenID Connect) lets your CI job prove who it is to the cloud: GitHub Actions issues a signed token that says "this job runs in repository acme/canteen on branch main". The cloud checks the signature and a trust rule, then hands back temporary credentials. No cloud key is stored in GitHub at all.
permissions:
id-token: write # allow the job to request an OIDC token
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::123456789012:role/canteen-deploy
aws-region: ap-south-1
- run: aws sts get-caller-identity # temporary credentials, no stored keyRotation
Rotation means replacing a secret with a new one on a schedule, or straight away when someone leaves the team. Automate it: a manual rotation that happens "every year" usually never happens. To rotate without downtime, create the new secret, let the app accept both for a short overlap, switch the app over, then remove the old one. Vault can go further with dynamic secrets: it creates a unique database user for each app instance and deletes it when the lease ends.
After a leak: the order matters
- Revoke or rotate the secret immediately. This is the only step that stops an attacker.
- Check the logs for use during the exposure window: cloud audit logs (such as AWS CloudTrail), the provider's dashboard, unusual bills.
- Clean the history with git filter-repo or BFG Repo-Cleaner and force-push, after warning the team. Remember that forks, clones and caches may still hold the old commits.
- Fix the cause: add the pre-commit hook, turn on push protection, move the secret to a secret manager.
- Write a short blameless review so the team learns from it.
Need help?
Stuck on a word or an idea? Search this course, or every course, and jump straight to the explanation or a worked question.
Try:
Watch the lesson
Secrets management · 1/7
A secret is anything that gives access: passwords, API keys, tokens and private keys.
Prefer a video by a teacher? Find free videos on “secrets management devops vault github oidc gitleaks” on YouTube ↗
In real life: An AWS key pushed to a public repository in Bengaluru
A student intern at a Bengaluru startup pushes a side project to a public GitHub repository. The .env file holds the company's AWS access key. Within the hour, unknown instances start in another region, and the billing alert fires that evening. The DevOps lead deactivates the key first, then checks CloudTrail to see what the key did, terminates the unknown instances, and opens a support case with AWS. Afterwards the team switches CI to OIDC so no long-lived AWS keys exist, adds gitleaks as a pre-commit hook, and turns on GitHub push protection for the organisation.
Practice (0/3 done)
You notice you pushed a payment gateway API key to GitHub ten minutes ago. What should you do FIRST?
Write scan_secrets(text) that checks each line of text and returns a list of (line_number, kind) tuples, with line numbers starting at 1. Kinds, checked in this order: "aws_access_key" (AKIA followed by 16 capital letters or digits), "github_token" (ghp_, gho_, ghu_, ghs_ or ghr_ followed by 36 letters or digits), "private_key" (a line containing -----BEGIN PRIVATE KEY----- or with a word before PRIVATE, like -----BEGIN RSA PRIVATE KEY-----) and "password" (password = "..." or password = '...', any case, spaces allowed around =). Skip any line containing # nosecret.
Your canteen API reads its database password from a hard-coded line in config.py, and the GitHub Actions workflow deploys to AWS with an access key stored as a repository secret. Write a short plan (5 to 8 steps) to fix both, in the right order.
Quick quiz
Read more (free)
Related help
Before this, learn
This topic builds on these. If something here feels new, open them first.
Related topics
- Software supply chain securityDevSecOps · same module
- Kubernetes securityDevSecOps · same module
- Keeping secrets safeBackend Development · Backend security
- The command line on all three cloudsCloud Computing (AWS, Azure, Google Cloud) · Google Cloud and comparing the clouds
- Environment variables and secretsFull-Stack Development · Deploying and running the app
- Encryption, keys and secretsCloud Computing (AWS, Azure, Google Cloud) · Cloud security and compliance
Questions people ask about this
Open a question to see the answer and why. The first ones are this topic's own quiz, so try the quiz above before you peek.
A Kubernetes Secret holds the value cGFzc3dvcmQ= (base64). How protected is it?
Answer: Not at all against anyone who can read the Secret: base64 is just an encoding
base64 decodes with one command. Use RBAC, encryption at rest and keep Secrets out of Git.
What is the main benefit of OIDC from CI to a cloud provider?
Answer: No long-lived cloud key is stored in CI; credentials are temporary
The job exchanges a signed token for credentials that expire on their own.
Which tool lets you keep an encrypted Kubernetes Secret in Git that only the cluster can decrypt?
Answer: Sealed Secrets
Sealed Secrets encrypts with the controller's public key; only the controller in the cluster has the private key.
A developer deletes .env in a new commit after pushing it. Is the secret gone?
Answer: No, it is still in the earlier commit in history
Git keeps every earlier commit. Revoke the secret; cleaning history is a later step.
What does GitHub push protection do?Related
Answer: Blocks a push that contains a detected secret
Push protection scans the changes being pushed and blocks them if a known secret format is found.
From Keeping secrets safe
You pushed an access key to a public GitHub repository. What should you do FIRST?Related
Answer: Deactivate or delete the key in the cloud console, then check logs and clean up
The key may already be copied, so revoke it at once. Cleaning Git history comes after.
A session secret was pushed to a public GitHub repo. What fixes the problem?Related
Answer: Rotate: make a new secret, deploy it, and stop using the old one
The old value stays in git history and may already be copied. Only replacing it makes it useless.
A database password was committed to a public GitHub repository an hour ago. What is the first thing to do?Related
Answer: Rotate (change) the password immediately
Assume it is already copied. Rotate it first, then clean the history and add secret scanning.
Pass the quiz (60% or more) or mark this topic as done when you are ready.
Your progress is saved on this device only.
Next steps
- 2 more topics in “DevSecOps” before its exam: Software supply chain security, Kubernetes security.
- Module 11 exam: DevSecOps · 12 questions · 20 min, without help. 4 topics of this module still to finish first.
- Then the next module, GitOps, platform engineering and DevOps careers. 53 topics left in the course before the final exam.