Eliminating .env Files: A Practical Guide to AWS Secrets Manager for Development Teams
Cloud DevOps/SRE engineer working with Kubernetes, GitHub Actions, Terraform, and distributed systems. I share practical guides, architecture patterns, and troubleshooting stories learned from running production systems.
Executive Summary
- Problem: Environment files containing secrets get committed to repositories, shared insecurely, and become stale
- Solution: Store secrets in AWS Secrets Manager and generate .env files programmatically on demand
- Result: Zero secrets in git history, auditable access via CloudTrail, and improved developer experience
- Cost: Approximately $0.40 per secret per month
The Challenge
Credential leaks remain one of the most common security incidents in software development. GitHub's secret scanning detected over 12 million exposed credentials in 2023 alone.
Traditional approaches to managing environment files create multiple failure points:
| Approach | Failure Mode |
| .gitignore rules | New developers forget to configure, files get committed |
| SOPS encryption | Key distribution complexity, merge conflicts, learning curve |
| Shared .env files | Sent via Slack, become stale, no access audit |
| Environment templates | Manual copying, outdated examples, human error |
Organizations need a solution that eliminates secrets from repositories entirely while maintaining developer productivity.
Technical Architecture
The solution consists of three components: a centralized secret store, a generation script, and CI/CD integration.
Secret Organization
Secrets are organized hierarchically in AWS Secrets Manager:
/application-name/environment/category
For example:
/myapp/dev/database → DB credentials
/myapp/dev/api-keys → Third-party API keys
/myapp/prod/database → Production DB credentials
/myapp/prod/api-keys → Production API keys
This structure enables granular IAM policies. Developers can access development secrets while production secrets remain restricted to CI/CD pipelines.
Generation Workflow
Developers execute a single command after cloning a repository:
make env
The underlying script:
- Validates AWS credentials
- Fetches secrets from the appropriate environment path
- Generates a .env file locally
- Validates the file is gitignored
The generated file never exists in version control. When secrets are updated in AWS Secrets Manager, developers regenerate their local file to receive the latest values.
CI/CD Integration
Pipelines use OIDC authentication to assume AWS roles without stored credentials.
GitHub Actions:
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::ACCOUNT:role/github-actions
aws-region: us-east-1
- name: Generate environment file
run: python scripts/generate_env.py prod --force
GitLab CI:
script:
- export $(aws sts assume-role-with-web-identity ...)
- python scripts/generate_env.py prod --force
Both approaches eliminate stored credentials in CI/CD systems. Access is granted through IAM role assumption with full CloudTrail auditing.
Implementation Guide
Prerequisites
- AWS account with Secrets Manager access
- Python 3.8+ with boto3
- AWS CLI configured for local development
Step 1: Create Secrets
aws secretsmanager create-secret \
--name /myapp/dev/database \
--secret-string '{"DB_HOST":"localhost","DB_PASSWORD":"dev123"}'
aws secretsmanager create-secret \
--name /myapp/dev/api-keys \
--secret-string '{"STRIPE_KEY":"sk_test_...","API_SECRET":"..."}'
Step 2: Configure IAM Policies
Developer policy (dev environment only):
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:*:*:secret:/myapp/dev/*"
}]
}
CI/CD policy (production access):
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": ["secretsmanager:GetSecretValue"],
"Resource": "arn:aws:secretsmanager:*:*:secret:/myapp/prod/*"
}]
}
Step 3: Deploy the Generation Script
The Python script handles authentication validation, secret fetching, and file generation:
def fetch_all_secrets(environment: str, region: str) -> dict:
all_secrets = {}
for key in SECRET_KEYS:
secret_path = f"/{APP_NAME}/{environment}/{key}"
secrets = get_secret(secret_path, region)
all_secrets.update(secrets)
return all_secrets
Full implementation is available in the linked repository.
Step 4: Configure OIDC for CI/CD
For GitHub Actions:
- Create OIDC provider in AWS IAM
- Create role with web identity trust policy
- Attach secrets access policy
- Reference role ARN in workflow
For GitLab CI:
- Create OIDC provider for gitlab.com
- Create role with appropriate trust policy
- Store role ARN in CI/CD variables
Cost Analysis
AWS Secrets Manager pricing is straightforward:
| Component | Cost |
| Secret storage | $0.40 per secret per month |
| API calls | $0.05 per 10,000 calls |
For a typical team:
| Team Size | Secrets | Monthly Cost |
| 5 developers | 20 | ~$8 |
| 20 developers | 50 | ~$20 |
| 100 developers | 100 | ~$40 |
Compared to dedicated secrets management SaaS solutions ($10+ per user per month), AWS Secrets Manager provides significant cost savings for AWS-native teams.
Security Benefits
| Aspect | Before | After |
| Secrets in git history | Present | Eliminated |
| Access audit trail | None | CloudTrail |
| Secret sharing | Slack, email | IAM-controlled |
| Rotation complexity | Manual everywhere | Update once, regenerate |
| Revocation | Find all copies | Update secret |
Measured Outcomes
Six months after implementation:
- Credential rotation time: Reduced from 2 hours to 5 minutes
- New developer setup: Reduced from 45 minutes to 10 minutes
- Security incidents from leaked credentials: Zero
- Secret sharing via messaging: Eliminated
Recommendations
Use this approach when:
- Your infrastructure runs on AWS
- You need auditable access to secrets
- Developer experience is a priority
- You want to avoid additional vendor dependencies
Consider alternatives when:
- You need cross-cloud secret management
- Your team has no existing AWS footprint
- You require complex approval workflows for secret access
Conclusion
Eliminating .env files from repositories requires a combination of centralized secret storage, convenient generation tooling, and proper CI/CD integration. AWS Secrets Manager provides a cost-effective solution for teams already operating on AWS infrastructure.
The key insight is that developer experience determines adoption. If generating secrets is harder than committing them, developers will commit them. The make env command must be faster and simpler than any alternative.
Resources
- Implementation repository: github.com/mateenali66/secrets-env-generator
- AWS Secrets Manager documentation: docs.aws.amazon.com/secretsmanager
- GitHub Actions OIDC guide: docs.github.com/actions/security-for-github-actions
Mateen Ali is a DevOps engineer specializing in cloud infrastructure and security automation. Connect on mateen.tech.