Secrets Management¶
Overview¶
Secrets are managed through two complementary systems:
- SOPS + Age -- Encrypts secrets stored in Git
- External Secrets Operator -- Pulls secrets from 1Password at runtime
SOPS + Age¶
SOPS encrypts YAML files using Age keys.
Encryption Rules (.sops.yaml)¶
| Path Pattern | Encryption Scope |
|---|---|
talos/.*\.sops\.ya?ml |
Full file encryption |
(bootstrap\|kubernetes)/.*\.sops\.ya?ml |
Only data and stringData fields |
Encrypting a Secret¶
Decrypting a Secret¶
Key Management¶
- Age public key: defined in
.sops.yaml - Age private key: stored in
age.key(gitignored) - Environment variable:
SOPS_AGE_KEY_FILEpoints toage.key
External Secrets Operator¶
External Secrets Operator v2.0.0 syncs secrets from external providers into Kubernetes.
1Password Integration¶
A ClusterSecretStore connects to 1Password:
kubernetes/apps/external-secrets/
├── external-secrets/ # Operator deployment
├── onepassword/ # ClusterSecretStore config
└── discord-webhook/ # Discord integration
Applications reference secrets via ExternalSecret resources that pull values from 1Password vaults.
Creating an ExternalSecret¶
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: app-secret
spec:
secretStoreRef:
kind: ClusterSecretStore
name: onepassword
target:
name: app-secret
data:
- secretKey: password
remoteRef:
key: my-1password-item
property: password
Best Practices¶
Never commit unencrypted secrets
All sensitive data must be in *.sops.yaml files. Verify encryption by checking for sops: metadata in the file.
- Use
ExternalSecretfor runtime secrets from 1Password - Use
SOPSfor secrets that must exist in Git (bootstrap, cluster config) - Always validate that
*.sops.yamlfiles are encrypted before pushing - Renovate is configured to ignore
**/*.sops.*files