Kubernetes secrets management for SME teams means keeping database passwords, SMTP credentials, and API keys out of Git while still deploying with GitOps. Native Secret objects are base64-encoded, not encrypted at rest by default, and kubectl get secret -o yaml tempts people to paste cleartext into Slack. The fix is Sealed Secrets or SOPS, strict separation from ConfigMaps, and rotation a two-person platform team can follow.
DarDevOps runs self-hosted clusters on OVH-class VPS for internal stacks and client workloads. We treat secrets as part of the same pipeline as ingress TLS and Flux reconciliation—not a one-time kubectl create secret before lunch.
What Kubernetes Secrets actually give you
A Secret is a namespaced API object. Pods mount it as files or inject keys as environment variables. etcd stores the data; on most self-hosted clusters that storage is not encrypted unless you enable encryption at rest. RBAC limits who reads secrets, but anyone with cluster-admin or etcd backup access can recover values. Base64 is encoding, not protection.
Baseline for SMEs: never commit cleartext secrets, never log secret values in CI, and restrict who can kubectl get secret in production.
Never put passwords in ConfigMaps
ConfigMaps are for non-sensitive configuration: feature flags, public URLs, log levels. Putting POSTGRES_PASSWORD or JWT signing keys in a ConfigMap is a common shortcut because edits feel harmless and show up in git diff. They remain readable to every ServiceAccount that can list configmaps in the namespace—and they sync to GitOps repos in plain text.
- ConfigMap: app port, public API base URL, non-secret toggles
- Secret: database password, OAuth client secret, TLS private key
- SealedSecret or SOPS file: encrypted artifact safe to commit
Sealed Secrets vs SOPS
Both store encrypted secret material in Git and decrypt only inside the cluster or at deploy time.
- Sealed Secrets: apply a SealedSecret CRD; the controller mints a normal Secret. Ideal when developers run kubeseal locally and Flux applies the sealed file.
- SOPS + age or PGP: encrypt YAML in place; Flux decrypts with a mounted key. Better when one file holds several keys or non-Kubernetes config.
- External Secrets Operator: pulls from Vault or cloud secret stores—usually overkill until compliance forces it.
On one production cluster plus staging, we often start with Sealed Secrets because the model matches native Secret objects. When teams already use SOPS for Terraform, extend it to manifests instead of adding a second tool.
GitOps patterns that stay safe
GitOps reconciles from git—but git must never hold cleartext credentials. Deployments reference secretKeyRef; only SealedSecret or SOPS bundles are committed; CI validates schema without holding decryption keys.
- Bootstrap the encryptor
Install sealed-secrets controller or configure SOPS in Flux; back up the private key offline.
- Seal per environment
Staging and production use different cluster keys; never reuse a sealed blob across clusters.
- Reference, do not duplicate
Helm values list secret names, not values; charts mount Secrets created from sealed manifests.
- Reconcile and verify
Confirm the Secret exists and pods start; see gitops-flux-lessons for drift and rollback habits.
If you still deploy Compose with a.env on disk, use compose-to-kubernetes-migration as the moment you stop copying that file via SSH. Translate each sensitive env var into a sealed manifest before automating deploys.
Rotation without a dedicated security team
Rotation fails when it is annual and manual. Tie it to events you already track: offboarding, vendor credential refresh, cert-manager renewal, or a quarterly calendar reminder.
- Generate new credential upstream.
- Seal or SOPS-encrypt; open PR with only the encrypted artifact changed.
- Roll pods that mount the Secret—add a restart annotation if the chart does not auto-roll.
- Revoke old credential after error rates stay flat one business day.
For public TLS, let ingress-tls-cert-manager handle certificates; keep internal CA rotation on the same calendar as application secrets.
Mistakes we see on small clusters
- Sealed files generated against the wrong cluster public key
- cluster-admin CI tokens because sealing felt hard
- Storing the sealing private key in the same git repo as encrypted files
- Copy-pasting production secrets into staging
- Skipping backup of sealing keys while backing up etcd
Audit kubectl access quarterly. On k3s with one admin kubeconfig on a founder laptop, rotating that config matters as much as application passwords.

How DarDevOps helps
DarDevOps covers cluster bootstrap, Flux GitOps, ingress, observability, and secret workflows—patterns we use on dardev-vps and client VPS deployments. Platform overview: dardev.net/products.
Are Kubernetes Secrets encrypted by default?
No. They are base64-encoded in etcd. Enable encryption at rest for defense in depth, but still use Sealed Secrets or SOPS for git storage.
Sealed Secrets or SOPS for one k3s cluster?
Sealed Secrets if your team lives in kubectl YAML. SOPS if you already encrypt Terraform with age keys.
Can I put non-sensitive env vars in the same Secret?
Avoid mixing. ConfigMaps for public config; Secrets for sensitive keys so RBAC and rotation stay clear.
How do I rotate without downtime?
Support two valid credentials upstream when possible, update the sealed manifest, roll pods, revoke the old key after metrics look healthy.
Do I need HashiCorp Vault?
Not for most SME self-hosted clusters. Revisit when auditors require dynamic credentials or many teams share one platform.



