You've deployed applications with ArgoCD, configured sync policies, and mastered ApplicationSets. But you haven't stored any secrets in Git yet—and for good reason. Committing API keys, database passwords, or authentication tokens to version control is a security breach waiting to happen.
GitOps requires everything to be in Git, but secrets are the exception: they must never be stored in plaintext in version control. This chapter teaches you patterns for handling secrets safely while maintaining the GitOps principle of "Git as truth."
By the end of this chapter, you'll understand:
Imagine your Python FastAPI agent needs:
In non-GitOps workflows, you might:
But GitOps says everything should be in Git—including the specification of what secrets your application needs. This creates a tension:
Requirement 1: Everything must be versioned in Git (GitOps principle) Requirement 2: Secrets must never be in plaintext in Git (security principle)
These aren't contradictory if you encrypt secrets at rest (in Git) while keeping them decrypted at runtime (in the cluster).
Even private repositories are risky—developers accidentally grant too many permissions, contractors get access, or repositories are acquired in acquisitions where permissions aren't immediately revoked.
Sealed Secrets (by Bitnami) is the simplest approach for Kubernetes-native secret management.
The private key never leaves the cluster, so only your cluster can decrypt the secrets.
First, install the Sealed Secrets controller:
Output:
Verify it's running:
Output:
You need the kubeseal CLI tool to encrypt secrets locally:
Output (after install):
Now, encrypt a secret. First, create a plaintext Kubernetes Secret manifest:
Encrypt it:
Output:
Examine the encrypted output:
Output:
The values are unreadable. This is safe to commit to Git.
Commit the sealed secret to Git:
Output:
Create an ArgoCD Application that includes this sealed secret:
Output (after sync):
Your application now has access to plaintext secrets without them being stored in Git:
Output:
The secret is decrypted in the cluster. Your Deployment mounts it:
Your container sees the plaintext environment variables.
Sealed Secrets work well for small, static secrets. But if you use AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault, External Secrets Operator keeps those systems as the single source of truth and syncs them into Kubernetes.
Output:
A SecretStore defines how to connect to your external vault:
Output (after apply):
An ExternalSecret specifies which vault secrets to sync:
Apply it:
Output:
The External Secrets controller immediately syncs from Vault. Check the Secret:
Output:
Your Deployment mounts it exactly like a Sealed Secret:
The difference: secrets now stay synchronized with Vault. If you rotate a secret in Vault, the Kubernetes Secret updates automatically within 1 hour (or immediately with a webhook trigger).
For this course, Sealed Secrets is sufficient. For production deployments in enterprises, External Secrets + Vault is standard.
Create a .gitignore rule:
For OpenAI, Anthropic, and other provider keys:
Example rotation for an OpenAI key:
Output:
Use Kubernetes namespace isolation:
Each namespace has its own Sealed Secret, encrypted with the cluster key, but never mixed.
For production deployments, use Vault with audit logging:
Vault logs every secret access. Check the logs:
Output:
Production secrets should NOT be the same as development secrets:
If a development key is compromised, production remains secure.
Here's a full example deploying your agent with Sealed Secrets:
Step 1: Create plaintext secret
Step 2: Encrypt it
Output:
Step 3: Commit encrypted version
Output:
Step 4: Create ArgoCD Application
Step 5: Create Deployment that uses the secret
Apply everything:
Output:
Setup: You have an OpenAI API key and a PostgreSQL connection string that need to be deployed with your FastAPI agent.
Part 1: Initial Request
Ask AI: "I need to securely store my OpenAI API key and PostgreSQL connection string in Kubernetes. I want to keep them encrypted in Git. Should I use Sealed Secrets or External Secrets Operator? What are the tradeoffs?"
Part 2: Critical Evaluation
Review AI's response. Ask yourself:
Part 3: Share Your Constraints
Tell AI your constraints: "We're learning Gitops in a Minikube environment, so we need something that doesn't require external services. What's the minimal setup for Sealed Secrets?"
Part 4: Refinement
Ask AI to help you: "Generate the kubeseal encryption steps and the YAML manifest for my FastAPI agent Deployment that reads these secrets."
Part 5: Final Check
Compare your result:
You built a gitops-deployment skill in Chapter 0. Test and improve it based on what you learned.
Ask yourself:
If you found gaps: