Overview
Penn Labs uses HashiCorp Vault to centrally manage secrets for all applications. Secrets are automatically synced to the Kubernetes cluster via thevault-secret-sync cronjob, making them available to applications as Kubernetes Secret objects.
Architecture
The secrets management system has three main components:Vault Server
Vault runs on a dedicated EC2 instance configured interraform/vault.tf:
Infrastructure:
- Instance Type: t3.small
- AMI: Official Vault OSS AMI
- Storage Backend: PostgreSQL (RDS)
- Auto-unseal: AWS KMS key
- Access: Application Load Balancer with TLS
- URL: https://vault.pennlabs.org
- Vault data is stored in a PostgreSQL database on RDS
- AWS KMS automatically unseals Vault on instance restart
- TLS certificate managed by AWS Certificate Manager
- Only accessible through load balancer (port 8200)
Secret Storage Location
Secrets are stored in Vault at:db-backup secrets are stored at:
How Applications Access Secrets
Applications access secrets through Kubernetes Secret objects, not directly from Vault. Here’s the flow:1. Secrets Defined in Vault
Secrets are created in Vault via Terraform. Example fromterraform/vault.tf:
2. vault-secret-sync Cronjob
Thevault-secret-sync cronjob runs periodically to sync secrets from Vault to Kubernetes:
Configuration (terraform/helm/vault-secret-sync.yaml):
- Authenticates to Vault using AWS IAM role
- Reads all secrets from configured Vault paths
- Creates/updates Kubernetes Secret objects in specified namespaces
- Runs on a schedule to keep secrets in sync
iam-secret-sync) with permission to:
- Assume the
secret-syncrole in Vault - Read secrets from the secrets path
3. Applications Reference Secrets
In Kittyhawk deployment configs, applications reference secrets by name:secret field causes all key-value pairs from the Kubernetes Secret to be injected as environment variables into the container.
Database Secrets
Database credentials are automatically managed through Terraform: Auto-generation (terraform/vault.tf):
DATABASE_URL secret for each database user, automatically including:
- Username
- Password (generated by Terraform)
- Database endpoint
- Database name
Vault Access Control
Who Has Access?
| User | Read Access | Write Access | Method |
|---|---|---|---|
| Kubernetes Cluster | ✓ | ✗ | IAM role (secret-sync) |
| GitHub Actions | ✓ | ✗ | AWS credentials |
| Developers/DevOps | ✓ | ✓ | UI/CLI login |
| Terraform | ✓ | ✓ | Root token |
IAM Authentication
Vault uses AWS IAM authentication for cluster access. Thesecret-sync policy is defined in terraform/modules/vault/secret-sync.tf:
Managing Secrets
Adding a New Secret
Option 1: Via Terraform (Recommended)-
Add secret definition to
terraform/vault.tf: -
Add variables to
terraform/variables.tf: -
Set the variable in your local
.envfile -
Apply the change:
- Log into Vault at https://vault.pennlabs.org
- Navigate to the secrets engine
- Create/edit secrets at
secrets/production/default/<app-name> - Wait for next sync cycle or manually trigger sync
Updating an Existing Secret
- Update in Vault (via Terraform or UI)
- Wait for sync -
vault-secret-syncwill update the Kubernetes Secret - Restart pods to pick up new values:
Deleting a Secret
- Remove from Vault (Terraform or UI)
- Delete the Kubernetes Secret:
- Update application deployment to not reference the secret
Team Sync
Theteam-sync cronjob automatically manages access permissions based on GitHub team membership:
What it syncs:
- Vault access - Team leads get Vault UI access
- Bitwarden access - Access to shared password vault
- Django admin - Admin console access for applicable apps
terraform/helm/team-sync.yaml):
Security Best Practices
DO:
- ✓ Use Terraform to manage secrets when possible (version controlled, auditable)
- ✓ Use sensitive variables in Terraform for secret values
- ✓ Rotate secrets regularly, especially API keys
- ✓ Use scoped IAM roles (principle of least privilege)
- ✓ Monitor Vault audit logs
- ✓ Use strong, unique passwords for each service
DON’T:
- ✗ Commit secrets to Git repositories
- ✗ Share Vault tokens or root credentials
- ✗ Store secrets in ConfigMaps (use Secrets instead)
- ✗ Hard-code secrets in application code
- ✗ Use the same secret across multiple applications
- ✗ Give write access to automated systems unless necessary
Troubleshooting
Secret Not Appearing in Kubernetes
-
Check if secret exists in Vault:
-
Check vault-secret-sync logs:
-
Verify IAM role has permissions:
- Check that the role ARN matches in Vault policy
- Ensure role can be assumed by the service account
-
Manually trigger sync (if needed):
Application Can’t Access Secret
-
Verify secret exists:
-
Check pod has secretRef:
- Check for typos in secret name in deployment config
-
Restart pods after secret creation/update:
Vault Unsealing Issues
Symptom: Vault is sealed and won’t auto-unseal Solution:- Check KMS key permissions
- Verify Vault instance IAM role has KMS decrypt permission
- Manually unseal if needed (requires unseal keys from initialization)