Purpose: For operators, shows how to encrypt, rotate, and manage secrets with SOPS and Age encryption, covering key generation through rotation.
openCenter uses SOPS with Age encryption to secure sensitive data in Git repositories. This guide shows you how to manage encryption keys and secrets throughout their lifecycle.
Prerequisites
-
openCenter CLI installed
-
Cluster configuration created
-
Git repository for GitOps (for encrypted secrets)
Generate Age Encryption Key
Create a new Age key pair for encrypting secrets:
opencenter secrets keys generate
This creates:
-
Private key:
~/.config/sops/age/keys.txtby default -
Public key: Embedded in private key file
-
SOPS configuration:
.sops.yamlin the current directory when enabled
Key format:
# created: 2026-02-17T10:30:00Z
# public key: age1abc123...
AGE-SECRET-KEY-1ABC123...
Validate SOPS Configuration
Check that SOPS is properly configured:
opencenter secrets keys validate
This validates:
-
Age key file exists and is readable
-
Key format is valid
-
SOPS configuration (
.sops.yaml) is correct -
Encryption rules are properly defined
Expected output:
✓ Age key file found
✓ Key format valid
✓ SOPS configuration valid
✓ Encryption rules defined
SOPS configuration is valid
Encrypt Secrets
Encrypt sensitive files in your GitOps repository:
opencenter secrets encrypt --path applications/overlays/my-cluster
This encrypts:
-
flux-system/gotk-sync.yaml- FluxCD sync configuration -
managed-services/sources/base-repo.yaml- GitRepository sources -
secrets/*.yaml- Provider credentials -
Service-specific secrets (Keycloak, Grafana, etc.)
List Encrypted Secrets
See all encrypted files in repository:
opencenter secrets list
Output shows:
Encrypted secrets in repository:
applications/overlays/my-cluster/flux-system/gotk-sync.yaml
applications/overlays/my-cluster/secrets/openstack-credentials.yaml
applications/overlays/my-cluster/secrets/keycloak-secret.yaml
applications/overlays/my-cluster/secrets/grafana-secret.yaml
Total: 4 encrypted files
Rotate Encryption Keys
Rotate Age keys for security (recommended every 90 days):
opencenter secrets keys rotate --cluster my-cluster --type age
This process:
-
Generates new Age key pair
-
Decrypts all secrets with old key
-
Re-encrypts all secrets with new key
-
Updates
.sops.yamlconfiguration -
Backs up old key
Backup Encryption Keys
Create backup of Age key:
opencenter secrets keys backup
Default backup location: ~/.config/sops/age/backups/
SOPS Configuration File
The .sops.yaml file defines encryption rules:
# SOPS configuration for cluster: my-cluster
creation_rules:
# Encrypt Age keys themselves
- path_regex: 'secrets/age/keys/.*-key\.txt$'
age: >-
age1abc123...
# Encrypt SSH private keys
- path_regex: 'secrets/ssh/(?!.*\.pub$).*'
age: >-
age1abc123...
# Encrypt service secrets
- path_regex: 'applications/overlays/[^/]+/(managed-services|services)/.*/.*\.ya?ml$'
encrypted_regex: "^(secret)$"
age: >-
age1abc123...
# Encrypt infrastructure secrets
- path_regex: '^infrastructure\/clusters\/my-cluster\/(?!(?:venv|kubespray|\.terraform|\.bin)\/)(.*)'
encrypted_regex: "^(secret)$"
age: >-
age1abc123...
This configuration:
-
Encrypts Age keys with themselves (for Git storage)
-
Encrypts SSH private keys (excludes
.pubfiles) -
Encrypts service secrets (only
secretfields in YAML) -
Encrypts infrastructure secrets (excludes build directories)
Environment Variables
FluxCD Integration
FluxCD automatically decrypts secrets during reconciliation.
Configure FluxCD SOPS Decryption
Create Age key secret in cluster:
kubectl create secret generic sops-age \
--from-file=age.agekey=$HOME/.config/opencenter/clusters/my-org/secrets/age/my-cluster-key.txt \
-n flux-system
Kustomization with SOPS
apiVersion: kustomize.toolkit.fluxcd.io/v1
kind: Kustomization
metadata:
name: my-service
namespace: flux-system
spec:
interval: 5m
path: ./applications/overlays/my-cluster/services/my-service
sourceRef:
kind: GitRepository
name: my-cluster
decryption:
provider: sops
secretRef:
name: sops-age
Security Best Practices
Key Storage
-
Store private keys securely (encrypted filesystem, secrets manager)
-
Never commit unencrypted private keys to Git
-
Backup keys to secure, offline location
-
Use different keys for different environments (dev, staging, prod)
Key Rotation
-
Rotate keys every 90 days
-
Rotate immediately if key is compromised
-
Keep old keys for 30 days (for rollback)
-
Document rotation in change log
Troubleshooting
SOPS Not Found
Problem: sops: command not found
Solution: Install SOPS:
# macOS
brew install sops
# Linux
wget https://github.com/mozilla/sops/releases/download/v3.8.1/sops-v3.8.1.linux.amd64
sudo mv sops-v3.8.1.linux.amd64 /usr/local/bin/sops
sudo chmod +x /usr/local/bin/sops
Decryption Failed
Problem: Failed to decrypt: no key could decrypt the data
Solution: Ensure SOPS_AGE_KEY_FILE points to correct key:
export SOPS_AGE_KEY_FILE=/path/to/correct/key.txt
sops --decrypt secrets/credentials.yaml
Next Steps
-
customize-services.md[Customize Services] - Configure platform services with encrypted secrets
-
backup-and-restore.md[Backup and Restore] - Include encryption keys in backups
-
troubleshoot-deployment.md[Troubleshoot Deployment] - Fix SOPS-related issues
Evidence
This how-to guide is based on:
-
SOPS commands:
cmd/sops.go:57-1035 -
SOPS manager:
internal/sops/manager.go:1-600 -
Key generation:
cmd/sops.go:57-86 -
Key rotation:
cmd/sops.go:88-123 -
Validation:
cmd/sops.go:158-219 -
Encryption:
cmd/sops.go:882-957 -
Tech guide SOPS:
.kiro/steering/tech.md:137-139 -
Session 1 security review: A11
-
Session 2 facts inventory: B0 section 9