Secrets Management
Secure secrets management practices for CI/CD pipelines using Vault, AWS Secrets Manager, and other tools.
Purpose
Implement secure secrets management in CI/CD pipelines without hardcoding sensitive information.
When to Use
-
Store API keys and credentials
-
Manage database passwords
-
Handle TLS certificates
-
Rotate secrets automatically
-
Implement least-privilege access
Secrets Management Tools
HashiCorp Vault
-
Centralized secrets management
-
Dynamic secrets generation
-
Secret rotation
-
Audit logging
-
Fine-grained access control
AWS Secrets Manager
-
AWS-native solution
-
Automatic rotation
-
Integration with RDS
-
CloudFormation support
Azure Key Vault
-
Azure-native solution
-
HSM-backed keys
-
Certificate management
-
RBAC integration
Google Secret Manager
-
GCP-native solution
-
Versioning
-
IAM integration
HashiCorp Vault Integration
Setup Vault
Start Vault dev server
vault server -dev
Set environment
export VAULT_ADDR='http://127.0.0.1:8200' export VAULT_TOKEN='root'
Enable secrets engine
vault secrets enable -path=secret kv-v2
Store secret
vault kv put secret/database/config username=admin password=secret
GitHub Actions with Vault
name: Deploy with Vault Secrets
on: [push]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Import Secrets from Vault
uses: hashicorp/vault-action@v2
with:
url: https://vault.example.com:8200
token: ${{ secrets.VAULT_TOKEN }}
secrets: |
secret/data/database username | DB_USERNAME ;
secret/data/database password | DB_PASSWORD ;
secret/data/api key | API_KEY
- name: Use secrets
run: |
echo "Connecting to database as $DB_USERNAME"
# Use $DB_PASSWORD, $API_KEY
GitLab CI with Vault
deploy: image: vault:latest before_script: - export VAULT_ADDR=https://vault.example.com:8200 - export VAULT_TOKEN=$VAULT_TOKEN - apk add curl jq script: - | DB_PASSWORD=$(vault kv get -field=password secret/database/config) API_KEY=$(vault kv get -field=key secret/api/credentials) echo "Deploying with secrets..." # Use $DB_PASSWORD, $API_KEY
Reference: See references/vault-setup.md
AWS Secrets Manager
Store Secret
aws secretsmanager create-secret
--name production/database/password
--secret-string "super-secret-password"
Retrieve in GitHub Actions
-
name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: us-west-2
-
name: Get secret from AWS run: | SECRET=$(aws secretsmanager get-secret-value
--secret-id production/database/password
--query SecretString
--output text) echo "::add-mask::$SECRET" echo "DB_PASSWORD=$SECRET" >> $GITHUB_ENV -
name: Use secret run: |
Use $DB_PASSWORD
./deploy.sh
Terraform with AWS Secrets Manager
data "aws_secretsmanager_secret_version" "db_password" { secret_id = "production/database/password" }
resource "aws_db_instance" "main" { allocated_storage = 100 engine = "postgres" instance_class = "db.t3.large" username = "admin" password = jsondecode(data.aws_secretsmanager_secret_version.db_password.secret_string)["password"] }
GitHub Secrets
Organization/Repository Secrets
- name: Use GitHub secret run: | echo "API Key: ${{ secrets.API_KEY }}" echo "Database URL: ${{ secrets.DATABASE_URL }}"
Environment Secrets
deploy: runs-on: ubuntu-latest environment: production steps: - name: Deploy run: | echo "Deploying with ${{ secrets.PROD_API_KEY }}"
Reference: See references/github-secrets.md
GitLab CI/CD Variables
Project Variables
deploy: script: - echo "Deploying with $API_KEY" - echo "Database: $DATABASE_URL"
Protected and Masked Variables
-
Protected: Only available in protected branches
-
Masked: Hidden in job logs
-
File type: Stored as file
Best Practices
-
Never commit secrets to Git
-
Use different secrets per environment
-
Rotate secrets regularly
-
Implement least-privilege access
-
Enable audit logging
-
Use secret scanning (GitGuardian, TruffleHog)
-
Mask secrets in logs
-
Encrypt secrets at rest
-
Use short-lived tokens when possible
-
Document secret requirements
Secret Rotation
Automated Rotation with AWS
import boto3 import json
def lambda_handler(event, context): client = boto3.client('secretsmanager')
# Get current secret
response = client.get_secret_value(SecretId='my-secret')
current_secret = json.loads(response['SecretString'])
# Generate new password
new_password = generate_strong_password()
# Update database password
update_database_password(new_password)
# Update secret
client.put_secret_value(
SecretId='my-secret',
SecretString=json.dumps({
'username': current_secret['username'],
'password': new_password
})
)
return {'statusCode': 200}
Manual Rotation Process
-
Generate new secret
-
Update secret in secret store
-
Update applications to use new secret
-
Verify functionality
-
Revoke old secret
External Secrets Operator
Kubernetes Integration
apiVersion: external-secrets.io/v1beta1 kind: SecretStore metadata: name: vault-backend namespace: production spec: provider: vault: server: "https://vault.example.com:8200" path: "secret" version: "v2" auth: kubernetes: mountPath: "kubernetes" role: "production"
apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: database-credentials namespace: production spec: refreshInterval: 1h secretStoreRef: name: vault-backend kind: SecretStore target: name: database-credentials creationPolicy: Owner data: - secretKey: username remoteRef: key: database/config property: username - secretKey: password remoteRef: key: database/config property: password
Secret Scanning
Pre-commit Hook
#!/bin/bash
.git/hooks/pre-commit
Check for secrets with TruffleHog
docker run --rm -v "$(pwd):/repo"
trufflesecurity/trufflehog:latest
filesystem --directory=/repo
if [ $? -ne 0 ]; then echo "❌ Secret detected! Commit blocked." exit 1 fi
CI/CD Secret Scanning
secret-scan: stage: security image: trufflesecurity/trufflehog:latest script: - trufflehog filesystem . allow_failure: false
Related Skills
-
github-actions-templates
-
For GitHub Actions integration
-
gitlab-ci-patterns
-
For GitLab CI integration
-
deployment-pipeline-design
-
For pipeline architecture