Secrets Component
The Secrets component creates Secret Manager secrets for sensitive configuration like database credentials and API keys.
Overview
Secrets Created
| Secret | Content | Source |
|---|---|---|
database-url | PostgreSQL connection string | Cloud SQL outputs |
redis-url | Redis connection string | Memorystore outputs |
backend-config | Backend application configuration | Pulumi config |
frontend-config | Frontend application configuration | Pulumi config |
Secret Format
Database URL
postgresql://postgres:PASSWORD@ALLOYDB_IP:5432/postgres
Redis URL
redis://:AUTH_STRING@REDIS_HOST:6379
Backend Config
JSON object containing backend application settings:
{
"DATABASE_URL": "postgresql://...",
"DATABASE_POOL_SIZE": "5",
"OPENAI_API_KEY": "sk-...",
"LANGFUSE_ENABLED": "true",
"LANGFUSE_SECRET_KEY": "sk-...",
"LANGFUSE_PUBLIC_KEY": "pk-...",
"ENVIRONMENT": "production",
"API_LOG_LEVEL": "info"
}
Frontend Config
JSON object containing frontend application settings:
{
"NEXT_PUBLIC_API_URL": "https://api.serko-northsky.com",
"NEXT_PUBLIC_FIREBASE_CONFIG": "{...}",
"NEXT_PUBLIC_LOGO_DEV_KEY": "..."
}
Configuration
Secrets are automatically populated from infrastructure outputs:
// Database URL from Cloud SQL
const databaseUrl = pulumi.interpolate`postgresql://postgres:${cloudSql.databasePassword}@${cloudSql.privateIpAddress}:5432/postgres`;
// Redis URL from Memorystore
const redisUrl = pulumi.interpolate`redis://:${memorystore.authString}@${memorystore.host}:${memorystore.port}`;
Outputs
interface SecretsOutputs {
databaseUrlSecretId: string;
redisUrlSecretId: string;
backendConfigSecretId: string;
frontendConfigSecretId: string;
}
Usage in Kubernetes
External Secrets Operator
Use External Secrets Operator to sync secrets to Kubernetes:
# Backend secrets
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: backend-config-external-secret
spec:
refreshInterval: 60s
secretStoreRef:
name: app-secretstore
kind: SecretStore
target:
name: backend-config
creationPolicy: Owner
dataFrom:
- extract:
key: serko-northsky-dev-backend-config
---
# Frontend secrets
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: frontend-config-external-secret
spec:
refreshInterval: 60s
secretStoreRef:
name: app-secretstore
kind: SecretStore
target:
name: frontend-config
creationPolicy: Owner
dataFrom:
- extract:
key: serko-northsky-dev-frontend-config
Direct Access (Application Code)
Access secrets directly using the GCP SDK:
from google.cloud import secretmanager
client = secretmanager.SecretManagerServiceClient()
name = f"projects/{project_id}/secrets/database-url/versions/latest"
response = client.access_secret_version(request={"name": name})
database_url = response.payload.data.decode("UTF-8")
IAM Permissions
| Service Account | Role | Purpose |
|---|---|---|
app@project.iam | secretmanager.secretAccessor | Read secrets |
pulumi-infra@project.iam | secretmanager.admin | Manage secrets |
Secret Versioning
Secret Manager automatically versions secrets:
- Latest: Always points to newest version
- Version Numbers: Access specific versions
- Destroy Policy: Old versions retained for audit
# Access latest version
gcloud secrets versions access latest --secret=database-url
# Access specific version
gcloud secrets versions access 3 --secret=database-url
# List all versions
gcloud secrets versions list database-url
Security Considerations
Access Control
- Secrets are only accessible to authorized service accounts
- Access is logged in Cloud Audit Logs
- No secret values in Pulumi state (marked as secret)
Rotation
Implement secret rotation:
- Create new secret version
- Update application to use new credentials
- Disable old secret version
- Delete old version after grace period
# Add new version
echo -n "new-password" | gcloud secrets versions add database-url --data-file=-
# Disable old version
gcloud secrets versions disable 1 --secret=database-url
Best Practices
- Never log secret values
- Use Workload Identity for access
- Enable audit logging
- Rotate credentials regularly
- Use separate secrets per environment