# ManagedSecret Operator A Kubernetes operator for declarative secret management with automated rotation, drift detection, and zero-downtime password changes. ## Overview The ManagedSecret operator provides: - 🔐 **Generates secrets** with configurable password policies - 🏦 **Stores in Vault/OpenBao** as the authoritative source - 🔄 **Syncs to Kubernetes Secrets** for application consumption - 🔍 **Detects and fixes drift** automatically (Vault → K8s) - 🔁 **Rotates secrets** on a configurable schedule - ⏱️ **Preserves previous versions** during rotation for zero-downtime password changes ### Key Principle: Vault/OpenBao is ALWAYS the source of truth - Changes in Vault → Synced to K8s automatically - Changes in K8s → Overwritten by Vault values - Drift detection runs every 1 minute --- ## 🚀 Quick Start > **Prerequisites:** Contact your administrator to receive: > - Registry username and password for `registry.c5ai.ch` > - Confirmation that OpenBao/Vault is configured for your cluster ```bash # 1. Set your credentials (provided by administrator) export REGISTRY_USER="" export REGISTRY_PASS="" # 2. Install Reloader (for automatic pod restarts during rotation) kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml # 3. Login to Helm registry helm registry login registry.c5ai.ch -u $REGISTRY_USER -p $REGISTRY_PASS # 4. Create imagePullSecret kubectl create namespace managedsecret-operator-system kubectl create secret docker-registry registry-pull-secret \ --docker-server=registry.c5ai.ch \ --docker-username=$REGISTRY_USER \ --docker-password=$REGISTRY_PASS \ --namespace managedsecret-operator-system # 5. Install operator via Helm helm install managedsecret-operator oci://registry.c5ai.ch/charts/managedsecret-operator \ --version 1.0.7 \ --namespace managedsecret-operator-system \ --set imagePullSecrets[0].name=registry-pull-secret # 6. Verify installation kubectl get pods -n managedsecret-operator-system ``` That's it! Now check the [examples](./examples/) folder for comprehensive usage scenarios. --- ## 📦 What You Get ### Helm Chart from registry.c5ai.ch The operator is distributed as a Helm chart: - ✅ **No building required** - Just `helm install` - ✅ **Versioned releases** - Use specific versions or upgrade easily - ✅ **Pre-configured** - Sensible defaults, customize via `values.yaml` - ✅ **Private & secure** - Hosted on your infrastructure ### What's Deployed ``` managedsecret-operator-system/ ├── CustomResourceDefinition (ManagedSecret) ├── ServiceAccount (controller-manager) ├── Role & RoleBinding (RBAC) ├── ClusterRole & ClusterRoleBinding ├── Deployment (controller-manager) └── ConfigMap (operator configuration) ``` --- ## Prerequisites ### On Your Side (User) - ✅ Kubernetes cluster (1.24+) - ✅ kubectl configured and working - ✅ Helm 3.x installed - ✅ Cluster admin permissions ### Provided by Administrator - ✅ **Registry credentials** for `registry.c5ai.ch` - ✅ **OpenBao/Vault configuration** for your cluster - Vault address (e.g., `http://openbao.openbao.svc.cluster.local:8200`) - Kubernetes auth configured - Vault role name (typically `managedsecret-operator`) ### Optional (Recommended) - ✅ **Reloader by Stakater** (for automatic pod restarts on rotation) --- ## Installation Steps ### Step 1: Install Reloader (Recommended) Reloader automatically restarts pods when secrets change: ```bash # Direct install (simplest) kubectl apply -f https://raw.githubusercontent.com/stakater/Reloader/master/deployments/kubernetes/reloader.yaml # Via Helm helm repo add stakater https://stakater.github.io/stakater-charts helm install reloader stakater/reloader \ --namespace reloader \ --create-namespace ``` ### Step 2: Authenticate to Registry ```bash # Set credentials from administrator export REGISTRY_USER="" export REGISTRY_PASS="" # Login to Helm registry helm registry login registry.c5ai.ch -u $REGISTRY_USER -p $REGISTRY_PASS # Create namespace kubectl create namespace managedsecret-operator-system # Create imagePullSecret kubectl create secret docker-registry registry-pull-secret \ --docker-server=registry.c5ai.ch \ --docker-username=$REGISTRY_USER \ --docker-password=$REGISTRY_PASS \ --namespace managedsecret-operator-system ``` ### Step 3: Install the Operator ```bash # Install with default configuration helm install managedsecret-operator \ oci://registry.c5ai.ch/charts/managedsecret-operator \ --version 1.0.7 \ --namespace managedsecret-operator-system \ --set imagePullSecrets[0].name=registry-pull-secret # Or with custom values cat > values.yaml <-previous with old values 4. Updates K8s Secret with new values 5. If Reloader is enabled: - Reloader detects change → Restarts pods 6. After previousVersionTTL: - Operator deletes -previous secret ``` ### When to Use `keepPreviousVersion` Use `keepPreviousVersion: true` when your service needs the **old password to authenticate** before changing to the new password: - ✅ PostgreSQL, MySQL, MariaDB (`ALTER USER` requires authentication) - ✅ MinIO (`mc admin` needs old credentials) - ✅ LDAP, Active Directory - ❌ Container registries (htpasswd regenerated fresh) - ❌ Redis (CONFIG SET doesn't need old password) - ❌ Web services with startup scripts ### Forcing Rotation ```bash # Trigger immediate rotation kubectl annotate managedsecret -n \ reconcile="$(date +%s)" --overwrite ``` --- ## 🔍 Drift Detection The operator automatically detects and fixes drift every 60 seconds: **Scenario 1: Secret deleted in Kubernetes** ```bash kubectl delete secret my-secret -n my-app # Operator recreates it from Vault within 60 seconds ``` **Scenario 2: Secret modified in Vault** ```bash # Update value in Vault vault kv put secret/my-app/keys password=newvalue # Operator syncs to K8s within 60 seconds ``` **Scenario 3: Secret manually edited in K8s** ```bash kubectl edit secret my-secret -n my-app # Changes are overwritten by Vault values within 60 seconds ``` --- ## 🔧 Troubleshooting ### Operator Not Starting ```bash # Check pod status kubectl get pods -n managedsecret-operator-system # View logs kubectl logs -n managedsecret-operator-system \ -l control-plane=controller-manager --tail=100 # Common issues: # - ImagePullBackOff: Check imagePullSecret is created correctly # - CrashLoopBackOff: Check Vault connectivity ``` ### Secret Not Created ```bash # Check ManagedSecret status kubectl get managedsecret -n -o yaml # Look for conditions/events kubectl describe managedsecret -n # Check operator logs kubectl logs -n managedsecret-operator-system \ -l control-plane=controller-manager | grep ``` ### Vault Authentication Failing ```bash # Verify ServiceAccount exists kubectl get sa controller-manager -n managedsecret-operator-system # Check Vault role configuration vault read auth/kubernetes/role/managedsecret-operator # Test authentication manually kubectl exec -it -n managedsecret-operator-system \ deployment/managedsecret-operator-controller-manager -- sh # Inside pod: Check /var/run/secrets/kubernetes.io/serviceaccount/token exists ``` ### Rotation Not Working ```bash # Check ManagedSecret schedule kubectl get managedsecret -n -o yaml | grep schedule # Force rotation to test kubectl annotate managedsecret -n \ reconcile="$(date +%s)" --overwrite # Check if Reloader is installed (if using rotation) kubectl get pods -n reloader ``` ### Reloader Not Restarting Pods ```bash # Verify Reloader is running kubectl get pods -n reloader # Check pod has correct annotation kubectl get deployment -n -o yaml | grep reloader # View Reloader logs kubectl logs -n reloader -l app=reloader # Required annotation on pod template: # annotations: # reloader.stakater.com/auto: "true" ``` --- ## 🎯 Best Practices ### 1. Always Use Reloader for Rotating Secrets Without Reloader, pods won't pick up new credentials: ```yaml template: metadata: annotations: reloader.stakater.com/auto: "true" ``` ### 2. Set Appropriate Rotation Schedules - **High Security** (passwords, admin credentials): 30-90 days - **Medium Security** (application credentials): 90-180 days - **Low Security** (read-only API keys): 180+ days or disabled ### 3. Use `keepPreviousVersion` Correctly Only use it when the service needs the old password to authenticate: ```yaml destination: keepPreviousVersion: true # Only if old password is needed previousVersionTTL: 1h # Adjust based on your workflow ``` ### 4. Test Rotation Before Production ```bash # Create test ManagedSecret with short rotation spec: rotation: enabled: true schedule: 5m # Test rotation every 5 minutes # Watch the rotation kubectl get secrets -n -w # Verify application handles rotation kubectl logs -n ``` ### 5. Monitor Rotation Jobs For services using `keepPreviousVersion`, monitor your CronJobs: ```bash # Check job status kubectl get jobs -n # View job logs kubectl logs -n -l job-name= # Set up alerts for failed jobs ``` ### 6. Backup Vault Regularly Vault is your source of truth: ```bash # Example: Backup with Velero velero backup create vault-backup \ --include-namespaces openbao \ --snapshot-volumes ``` ### 7. Version Control Your ManagedSecrets Store ManagedSecret manifests in Git: ```yaml # managedsecrets/ # ├── production/ # │ ├── postgres-credentials.yaml # │ └── api-keys.yaml # └── staging/ # ├── postgres-credentials.yaml # └── api-keys.yaml ``` ### 8. Use GitOps for Deployment Deploy with ArgoCD or Flux: ```yaml apiVersion: argoproj.io/v1alpha1 kind: Application metadata: name: managedsecrets spec: source: path: managedsecrets/production destination: namespace: default ``` --- ## 🔒 Security Considerations ### Production Checklist - [ ] OpenBao/Vault is properly secured (TLS, audit logging, backups) - [ ] RBAC configured with least-privilege - [ ] Network policies in place - [ ] Monitoring and alerting configured - [ ] Disaster recovery plan documented - [ ] Registry credentials stored securely (not in Git) ### Credentials Management The operator needs: 1. Access to Vault (via Kubernetes ServiceAccount auth) 2. Access to pull its image (via imagePullSecret) Both use Kubernetes-native methods. **Never hardcode credentials in manifests!** --- ## 📞 Support ### Getting Help 1. **Check documentation**: - This README - [examples/EXAMPLES-SUMMARY.md](./examples/EXAMPLES-SUMMARY.md) - Individual example files 2. **Check operator logs**: ```bash kubectl logs -n managedsecret-operator-system \ -l control-plane=controller-manager --tail=100 ``` 3. **Contact your administrator** if: - You need registry credentials - Vault is not configured for your cluster - Operator authentication issues ### For Administrators #### Information to Provide Users **Registry Credentials:** ``` Registry: registry.c5ai.ch Username: Password: Chart: oci://registry.c5ai.ch/charts/managedsecret-operator Version: 1.0.7 ``` **Vault Configuration:** ``` Address: http://openbao.openbao.svc.cluster.local:8200 Auth Method: kubernetes Role: managedsecret-operator KV Mount: secret KV Version: v2 ``` #### Prerequisites for New Cluster ```bash # 1. Enable Kubernetes auth bao auth enable kubernetes bao write auth/kubernetes/config \ kubernetes_host="https://kubernetes.default.svc:443" # 2. Create policy bao policy write managedsecret-operator - <<'EOF' path "secret/data/*" { capabilities = ["create", "read", "update", "delete", "list"] } path "secret/metadata/*" { capabilities = ["list", "read", "delete"] } EOF # 3. Create role bao write auth/kubernetes/role/managedsecret-operator \ bound_service_account_names=controller-manager \ bound_service_account_namespaces=managedsecret-operator-system \ policies=managedsecret-operator \ ttl=1h ``` --- ## 🔄 Upgrading ### Upgrade Operator Version ```bash # Check current version helm list -n managedsecret-operator-system # Upgrade to new version helm upgrade managedsecret-operator \ oci://registry.c5ai.ch/charts/managedsecret-operator \ --version 1.0.8 \ --namespace managedsecret-operator-system \ --reuse-values ``` ### Migration Notes When upgrading from earlier versions: - CRD updates are handled automatically - Existing ManagedSecrets continue to work - No manual migration required - Check changelog for breaking changes --- ## 📝 Changelog ### Version 1.0.7 - ✨ Added `keepPreviousVersion` for zero-downtime rotation - ✨ Added `previousVersionTTL` for automatic cleanup - 📦 Helm chart deployment support - 📚 Comprehensive examples and documentation - 🐛 Bug fixes and improvements --- ## License Proprietary Use License Permission is granted to use this software for any purpose, including commercial use, without charge. Modification, adaptation, or creation of derivative works is prohibited. Redistribution of modified versions is prohibited. --- **Version:** 1.0.7 **Registry:** registry.c5ai.ch/charts/managedsecret-operator **Minimum Kubernetes:** 1.24+ **Compatible with:** OpenBao, HashiCorp Vault