Secrets Management Rules
Mandatory rules for managing secrets in UIS. These rules ensure security, prevent accidental exposure, and maintain consistency across services.
Core Pattern: Template + Gitignore
All secrets follow a three-stage pipeline:
Container image templates → .uis.secrets/secrets-config/ → .uis.secrets/generated/
↑ ↑ ↑
Git-tracked (${VARIABLES}) Gitignored (actual values) Gitignored (final YAML)
Safe operations
- Edit files in
.uis.secrets/secrets-config/with actual secret values - Run
./uis secrets generateto produce final YAML - Run
./uis secrets applyto push to the cluster
Forbidden operations
- Never put actual secrets in container image templates
- Never commit
.uis.secrets/to git - Never edit files in
.uis.secrets/generated/directly - Never store secrets in documentation or comments
Variable Substitution
All secrets use centralized variable management. Define values once in 00-common-values.env.template, reference them everywhere via ${VARIABLE}:
# .uis.secrets/secrets-config/00-common-values.env.template
DEFAULT_DATABASE_PASSWORD=YourSecurePassword123
DEFAULT_ADMIN_EMAIL=admin@yourcompany.com
# .uis.secrets/secrets-config/00-master-secrets.yml.template
PGPASSWORD: "${DEFAULT_DATABASE_PASSWORD}"
AUTHENTIK_BOOTSTRAP_EMAIL: "${DEFAULT_ADMIN_EMAIL}"
Anti-pattern — hard-coding different passwords per service:
# WRONG: breaks centralized rotation
PGPASSWORD: "postgres-specific-password"
MYSQL_ROOT_PASSWORD: "mysql-different-password"
Centralized variables enable password rotation across all services simultaneously.
Correct Workflow
# 1. Edit your values
nano .uis.secrets/secrets-config/00-common-values.env.template
# 2. Generate secrets
./uis secrets generate
# 3. Validate before applying
kubectl apply --dry-run=client -f .uis.secrets/generated/kubernetes/kubernetes-secrets.yml
# 4. Apply to cluster
./uis secrets apply
Anti-pattern — editing generated files directly or skipping validation:
# WRONG: edits will be overwritten on next generate
nano .uis.secrets/generated/kubernetes/kubernetes-secrets.yml
Git Safety
Before any git operation, verify no secrets are staged:
# Check what's staged
git status
# Verify gitignore covers secrets
git check-ignore .uis.secrets/
# Check for secret patterns in staged files
git diff --cached | grep -i "password\|secret\|key"
Never use git add . without checking what's included. Never add .uis.secrets/ to git.
Service Integration
When adding secrets for a new service, use the established namespace pattern:
---
apiVersion: v1
kind: Secret
metadata:
name: urbalurba-secrets
namespace: myservice
type: Opaque
stringData:
MYSERVICE_DATABASE_PASSWORD: "${DEFAULT_DATABASE_PASSWORD}"
MYSERVICE_API_KEY: "${MYSERVICE_API_KEY}"
Anti-patterns:
- Hard-coding secrets in templates instead of using
${VARIABLES} - Using service-specific secret names instead of
urbalurba-secrets - Skipping namespace organization
No Helm Chart Defaults for Security Values
Never use Helm chart default values for security-sensitive parameters. Always override with values from urbalurba-secrets:
# In Ansible playbook
helm upgrade --install {{ service_name }} bitnami/rabbitmq \
--set auth.username={{ rabbitmq_username_fact | quote }} \
--set auth.password={{ rabbitmq_password_fact | quote }} \
--set auth.erlangCookie={{ rabbitmq_erlang_cookie_fact | quote }}
Parameters to always override: auth.username, auth.password, rootPassword, adminPassword, apiKey, secretKey, jwtSecret, erlangCookie, and any connection strings with embedded credentials.
Common Bitnami chart defaults to avoid:
| Chart | Default Username | Default Password |
|---|---|---|
| PostgreSQL | postgres | postgres |
| Redis | — | bitnami |
| RabbitMQ | user | bitnami |
| MongoDB | root | root |
ConfigMap Management
ConfigMaps follow the same template pattern but for non-sensitive configuration:
.uis.secrets/secrets-config/configmaps/[namespace]/[category]/*.template
ConfigMaps are auto-discovered and auto-labeled based on directory conventions:
| Directory | Auto-Label |
|---|---|
dashboards/ | grafana_dashboard: "1" |
nginx/ | app: nginx |
otel/ | app.kubernetes.io/name: otel-collector |
| Default | managed-by: secrets-pipeline |
ConfigMap vs Secret: Use ConfigMaps for application config files, dashboard definitions, public certificates, hosts/ports. Use Secrets for passwords, API keys, tokens, private keys, connection strings with credentials.
Testing and Validation
All secret changes must be validated before deployment:
# 1. Generate and validate YAML
./uis secrets generate
kubectl apply --dry-run=client -f .uis.secrets/generated/kubernetes/kubernetes-secrets.yml
# 2. Check for unresolved variables (should return nothing)
grep '${' .uis.secrets/generated/kubernetes/kubernetes-secrets.yml
# 3. Verify critical secrets are present
grep -c "PGPASSWORD\|REDIS_PASSWORD\|AUTHENTIK_SECRET_KEY" \
.uis.secrets/generated/kubernetes/kubernetes-secrets.yml
Secret Rotation
# 1. Update central variables
nano .uis.secrets/secrets-config/00-common-values.env.template
# 2. Generate and validate
./uis secrets generate
kubectl apply --dry-run=client -f .uis.secrets/generated/kubernetes/kubernetes-secrets.yml
# 3. Apply to cluster
./uis secrets apply
# 4. Restart affected services
./uis undeploy postgresql
./uis deploy postgresql
Incident Response
If secrets are accidentally committed to git:
- Remove from git immediately (
git reset HEAD~1if not pushed) - If pushed, contact the team — may need
git filter-branch - Rotate all exposed secrets in
secrets-config/ - Audit access logs for the exposed period
Template Update Rules
The generation script prioritizes .uis.secrets/secrets-config/ over container image templates (to allow user customization). When updating base templates in the container image, also update the user's config for immediate effect:
# Verify user config is up to date with base templates
diff <container-template> .uis.secrets/secrets-config/00-master-secrets.yml.template
On ./uis start, new template variables are automatically synced to secrets-config/. Existing values are preserved.
Cross-System Dependencies
- Deployment: Secrets must be generated and applied before deploying services
- Ingress: Domain names in secrets must match ingress configurations
- Verification:
kubectl get secret urbalurba-secrets -n default
kubectl get secret urbalurba-secrets -n ai
kubectl get secret urbalurba-secrets -n authentik
Related Documentation
- Secrets Management Reference — Commands, file structure, and defaults
- Provisioning Rules — Ansible playbook patterns
- Ingress & Networking Rules — Domain and routing configuration