Secrets Management for Small Teams: AWS Secrets Manager + CI
Secrets in repos are a reliability problem and a security risk. A simple secrets manager plus a minimal CI integration eliminates most of the pain without adding heavy process.
This post shows a small-team approach using AWS Secrets Manager and a CI pipeline.
Context
Problem: Teams rely on hardcoded secrets and inconsistent handling. Approach: Centralize secrets, use least-privilege access, and fetch at runtime with OIDC. Outcome: Fewer leaked credentials and repeatable deployments.
Create and name secrets consistently
Use clear names and separate environments. Keep secrets in one place.
1
2
3
aws secretsmanager create-secret \
--name prod/app/config \
--secret-string '{"DATABASE_URL":"postgres://..."}'
Store related values together so you can rotate them as a unit.
Grant least-privilege access
Scope access to the smallest set of secrets and use a dedicated role for CI.
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:prod/app/*"
}
]
}
If you use GitHub Actions, create a role that can only be assumed by your repo.
Fetch secrets in CI
Use OIDC to avoid long-lived AWS keys. Then pull the secret at runtime.
1
2
3
4
5
6
7
8
9
10
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/gh-secrets-read
aws-region: us-east-1
- name: Fetch secrets
run: |
SECRET=$(aws secretsmanager get-secret-value \
--secret-id prod/app/config \
--query SecretString --output text)
echo "APP_CONFIG=$SECRET" >> $GITHUB_ENV
Inject only what you need for that job, then let the job exit.
Use secrets safely in the app
Parse secrets from environment variables at startup. Avoid writing them to disk.
1
export APP_CONFIG='{"DATABASE_URL":"postgres://..."}'
If your runtime needs individual values, parse JSON and map to env vars in a launch script.
Rotate secrets deliberately
Set a rotation schedule and test it. Secrets Manager can call a Lambda function to rotate database or API keys. Even if you rotate manually, track the last rotation date and make it routine.
Local development
Use a local .env file and keep it out of source control. Match the structure of production secrets so the app behaves the same way in dev.
Takeaways
Centralize secrets, scope access, and fetch them at runtime. A small workflow like this removes hardcoded credentials and scales well as your team grows.