GitOps with FluxCD
Secret Management Sign Verification
DEMO EncryptDecrypt Secret using Bitnami Sealed Secrets
In this guide, we’ll cover how to secure Kubernetes Secrets by encrypting them with Bitnami Sealed Secrets and manage them declaratively using FluxCD and Kustomize.
Table of Contents
Step | Description | Reference Command |
---|---|---|
1. Background | Plaintext Secret in Git | – |
2. Automatic Reconciliation | FluxCD constantly applies Git manifests | kubectl -n database get po,secret |
3. Suspend Reconciliation | Pause FluxCD Kustomization | flux suspend kustomization … |
4. Trigger Pod Failure | Restart Pod to observe missing Secret | kubectl rollout restart … |
5. Encrypt with kubeseal | Generate a SealedSecret | kubeseal --cert … |
6. Replace Plaintext | Commit encrypted manifest to Git | git add sealed-secret-mysql.yaml |
7. Resume Reconciliation | Apply updated Git source and resume FluxCD | flux resume kustomization … |
8. Verify Decryption | Confirm the decrypted Secret in cluster | kubectl get secret … |
1. Background: Plaintext Secret in Git
We have a FluxCD Kustomization
that applies manifests from a Git repository:
apiVersion: kustomize.toolkit.fluxcd.io/v1beta2
kind: Kustomization
metadata:
name: infra-database-kustomize-git-mysql
namespace: flux-system
spec:
interval: 10s
path: ./database
prune: true
sourceRef:
kind: GitRepository
name: infra-source-git
targetNamespace: database
Under ./database/secret-mysql.yaml
, the MySQL password is stored in plaintext:
apiVersion: v1
kind: Secret
metadata:
name: secret-mysql
namespace: database
stringData:
password: mysql-password-0123456789
Warning
Storing passwords or tokens in plaintext within Git exposes them to unauthorized access. Always encrypt sensitive data before committing.
FluxCD’s Kustomize controller reconciles this Secret every 10 seconds, ensuring it’s present in the cluster.
2. Demonstrate Automatic Reconciliation
Verify the Secret and Pod exist:
kubectl -n database get pods,secret
Delete the Secret to see automatic re-creation:
kubectl -n database delete secret secret-mysql
# Wait a few seconds…
kubectl -n database get secret secret-mysql
FluxCD detects the drift and re-applies the manifest, recreating the Secret.
3. Suspend Reconciliation
Pause the Kustomization
so FluxCD stops reconciling this directory:
flux suspend kustomization infra-database-kustomize-git-mysql
flux get kustomization infra-database-kustomize-git-mysql
Now, deleting the Secret will not trigger re-creation:
kubectl -n database delete secret secret-mysql
kubectl -n database get secrets
4. Trigger Pod Failure
Force a deployment restart to spawn a new Pod, which will fail due to the missing Secret:
kubectl -n database rollout restart deployment mysql
kubectl -n database get pods -w
Observe a CreateContainerConfigError
:
kubectl -n database describe pod mysql-*
# ...
# Warning Failed Error: cannot find secret "secret-mysql"
5. Encrypt the Secret with kubeseal
Ensure you have:
- The
kubeseal
CLI installed. - The Sealed Secrets public key (
sealed-secrets.pub
).
Encrypt the existing Secret manifest:
kubeseal --cert ../../sealed-secrets.pub \
--scope cluster-wide \
-o yaml < secret-mysql.yaml > sealed-secret-mysql.yaml
This creates a SealedSecret
resource:
apiVersion: bitnami.com/v1alpha1
kind: SealedSecret
metadata:
name: secret-mysql
namespace: database
annotations:
sealedsecrets.bitnami.com/cluster-wide: "true"
spec:
encryptedData:
password: AgBv9SokhhVk4WNdTmmPxd9D0J2ETJY...
template:
metadata:
name: secret-mysql
namespace: database
Note
Only the Secret’s values are encrypted. The keys (password
) stay in cleartext for mapping.
6. Replace the Plaintext Secret
Backup the original manifest and commit the sealed version:
mv secret-mysql.yaml secret-mysql.yaml.bak
git add sealed-secret-mysql.yaml
git commit -m "Add SealedSecret for MySQL password"
git push
7. Resume Reconciliation
Sync your Git source and resume the Kustomization:
flux reconcile source git flux-system
flux resume kustomization infra-database-kustomize-git-mysql
FluxCD applies the SealedSecret
, and the Bitnami controller decrypts it into a normal Kubernetes Secret in database
.
8. Verify the Decrypted Secret
Check that the Secret has been created:
kubectl -n database get secret secret-mysql
Decode and inspect the password:
kubectl -n database get secret secret-mysql -o jsonpath='{.data.password}' | base64 -d
# => mysql-password-0123456789
Confirm the Pod is now running:
kubectl -n database get pods
9. Conclusion
You have successfully:
- Suspended FluxCD reconciliation.
- Deleted a plaintext Secret and saw a Pod failure.
- Used
kubeseal
to create an encryptedSealedSecret
. - Committed the
SealedSecret
to your Git repo. - Resumed FluxCD reconciliation and verified automatic decryption.
By integrating Bitnami Sealed Secrets with FluxCD and Kustomize, you can store encrypted secrets in Git, maintain GitOps workflows, and ensure secrets only decrypt inside your Kubernetes cluster.
Links and References
Watch Video
Watch video content
Practice Lab
Practice lab