Kubernetes module
Deploy a certificate as a kubernetes.io/tls Secret in
one or more clusters. Works with in-cluster service-account auth
(when CertAutoPilot itself runs on Kubernetes) or with inline
kubeconfig for external clusters. Multi-cluster is supported via
multiple targets.
01Overview
- Resource produced:
Secretof typekubernetes.io/tlswith keystls.crt(cert + chain) andtls.key(private key). An optionalca.crtcan be included if the consumer expects it separately. - Auth: inline kubeconfig string (stored in a module credential), or in-cluster service-account token (when use-in-cluster is checked and the backend runs on K8s).
- Namespace: fixed per target, or templated with a variable for multi-tenant reuse.
- Rollback: conditional. Set Store content on the distribution to capture the previous Secret bytes in
LastRollbackMeta; otherwise there is nothing to restore.
02Prerequisites
- A module credential holding the kubeconfig (for external clusters) or a ServiceAccount binding (for in-cluster).
- The credential's identity must have get, create, update, patch on
secretsin the target namespace. An in-cluster install using the bundled chart grants these automatically viaRole+RoleBinding. - The namespace must exist before distribution — the module does not create namespaces.
03Create a K8s target
- Settings → Distribution → Targets → New. Module type: Kubernetes.
-
Connection mode:
- In-cluster — available only when the backend detects it is running inside Kubernetes. Uses the mounted service-account token.
- Kubeconfig — pick a credential that stores the kubeconfig bytes. Kubeconfigs are envelope-encrypted.
- Namespace: e.g.
ingressor a templated value like{{ .tenant }}-edge. - Secret name: templated from the cert. Default:
{{ .cn | replaceAll "." "-" }}-tls. Override with a fixed name when the consumer expects a specific one (e.g.ingress-nginx-tls). - Include ca.crt: leave OFF unless your consumer explicitly reads
ca.crtfrom the Secret. - Store content for rollback: ON if you need the Rollback button to restore the previous Secret. OFF keeps the rollback metadata empty and the button greyed-out.
- Save → health check reads the namespace.
04Execute
- Attach a Kubernetes distribution to a cert.
- Dry-run prints the diff between the live Secret and the one we would write (or would create if it does not exist).
- Execute writes via
Update(server-side) — no patch gymnastics, the Secret is replaced. Any consumer that mounts the Secret as a Volume re-reads it on kubelet's sync interval (~60s); consumers using env vars require a pod restart.
CertAutoPilot writes the Secret but does not restart the consuming pods. For cert-auto-reload behaviour, use a sidecar like secretgen-controller or annotate your Deployment with a checksum/tls pattern so a kubectl rollout restart hook picks up the change. Webhook distributions can be stacked after the K8s one to fire the rollout.
05Rollback
When Store content is ON, the module stashes the previous
tls.crt / tls.key into the rollback metadata
before overwriting. Rollback re-applies that snapshot. When the
toggle is OFF, rollback is unavailable for this distribution — the
UI surfaces this as a greyed-out button with a tooltip.
06Multi-cluster deployments
Create one target per cluster (each with its own kubeconfig credential) and group them. Attaching a single distribution to the group fans out across every cluster. Fan-out follows the same threshold / batch-size settings as the SSH module.
07Minimum RBAC for an in-cluster install
The Helm chart ships with this Role; if you run custom RBAC, mirror it:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: certautopilot-distributor
namespace: <target-ns>
rules:
- apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "update", "patch"]
- apiGroups: [""]
resources: ["namespaces"]
verbs: ["get"]
Bind it to the ServiceAccount the backend pod uses.
08Troubleshooting
Fails with "forbidden: secrets cannot be updated"
ServiceAccount lacks update verb in the target namespace. Fix the RoleBinding.
"namespaces \"X\" not found"
The module does not create namespaces. Create the namespace first, then retry.
Ingress still serves the old cert
Ingress controllers cache certs. Check the controller's reload story — nginx-ingress reloads on Secret watch (fast), HAProxy Ingress reconciles on a timer. If in doubt, restart the controller pods; the Secret is already updated.