MATIH Platform is in active MVP development. Documentation reflects current implementation status.
17. Kubernetes & Helm
Security
Secrets Management

Secrets Management

Secrets management in the MATIH platform follows a zero-hardcoded-credentials policy. All sensitive values including database passwords, API keys, and TLS certificates are stored in Kubernetes Secrets, with production environments using the External Secrets Operator (ESO) to sync from cloud key vaults.


Secrets Architecture

Development:
  dev-secrets.sh --> kubectl create secret --> Kubernetes Secrets --> Pod env vars

Production:
  Cloud Key Vault --> External Secrets Operator --> Kubernetes Secrets --> Pod env vars

Secret Categories

CategoryExamplesStorageRotation
Database credentialsPostgreSQL, Redis, Kafka passwordsKubernetes SecretManual (dev), Automated (prod)
API keysOpenAI, Anthropic, cloud provider keysKubernetes SecretManual
TLS certificatesService TLS, ingress TLScert-manager SecretAutomated
Service tokensJWT signing keys, inter-service tokensKubernetes SecretPeriodic
Object storeMinIO/S3 access keysKubernetes SecretManual

Development Secrets

In development, secrets are created using the dev-secrets.sh script:

# Create all development secrets
./scripts/lib/k8s/dev-secrets.sh

This script creates Kubernetes Secrets with development-safe values. Secrets are never committed to Git.

Production Secrets with External Secrets Operator

In production, ESO syncs secrets from cloud key vaults:

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: ai-service-secrets
  namespace: matih-data-plane
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: azure-key-vault
    kind: ClusterSecretStore
  target:
    name: ai-service-secrets
    creationPolicy: Owner
  data:
    - secretKey: database-url
      remoteRef:
        key: ai-service-database-url
    - secretKey: openai-api-key
      remoteRef:
        key: openai-api-key
    - secretKey: jwt-secret-key
      remoteRef:
        key: jwt-secret-key

Secret References in Helm Charts

Services reference secrets through secretKeyRef in environment variables:

env:
  - name: DATABASE_URL
    valueFrom:
      secretKeyRef:
        name: ai-service-secrets
        key: database-url
  - name: OPENAI_API_KEY
    valueFrom:
      secretKeyRef:
        name: ai-service-secrets
        key: openai-api-key
  - name: REDIS_PASSWORD
    valueFrom:
      secretKeyRef:
        name: redis-credentials
        key: password

Credentials are never placed directly in values.yaml or values-dev.yaml files.

Supported Key Vault Backends

ProviderServiceESO Provider
AzureAzure Key Vaultazure/keyvault
AWSAWS Secrets Manageraws/secretsmanager
GCPGCP Secret Managergcp/secretmanager
HashiCorpVaultvault

Secret Rotation

MethodTriggerDowntime
ESO refreshAutomatic (refreshInterval)None (env var update on next pod restart)
Rolling restartManual or automated after ESO refreshZero (rolling update)
cert-manager renewalAutomatic (30 days before expiry)None

Security Best Practices

PracticeImplementation
Encryption at restKubernetes etcd encryption enabled
Encryption in transitTLS for all secret access
Least privilegeRBAC restricts secret access to owning namespace
Audit loggingAll secret access logged in audit trail
No git commitsPre-commit hook blocks .env files and known secret patterns
RotationAutomated via ESO with configurable refresh interval

Troubleshooting

IssueSymptomResolution
CreateContainerConfigErrorPod fails with "secret not found"Create missing secret or check name
ExternalSecret not syncingSecret not updated from vaultCheck ESO logs and vault permissions
Permission denied on secretRBAC error accessing secretVerify ServiceAccount has secret read access
Stale credentialsApplication using old passwordRestart pods after secret rotation