Skip to main content

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 generate to produce final YAML
  • Run ./uis secrets apply to 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:

ChartDefault UsernameDefault Password
PostgreSQLpostgrespostgres
Redisbitnami
RabbitMQuserbitnami
MongoDBrootroot

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:

DirectoryAuto-Label
dashboards/grafana_dashboard: "1"
nginx/app: nginx
otel/app.kubernetes.io/name: otel-collector
Defaultmanaged-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:

  1. Remove from git immediately (git reset HEAD~1 if not pushed)
  2. If pushed, contact the team — may need git filter-branch
  3. Rotate all exposed secrets in secrets-config/
  4. 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