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: Secret of type kubernetes.io/tls with keys tls.crt (cert + chain) and tls.key (private key). An optional ca.crt can 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 secrets in the target namespace. An in-cluster install using the bundled chart grants these automatically via Role + RoleBinding.
  • The namespace must exist before distribution — the module does not create namespaces.

03Create a K8s target

  1. Settings → Distribution → TargetsNew. Module type: Kubernetes.
  2. 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.
  3. Namespace: e.g. ingress or a templated value like {{ .tenant }}-edge.
  4. 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).
  5. Include ca.crt: leave OFF unless your consumer explicitly reads ca.crt from the Secret.
  6. 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.
  7. Save → health check reads the namespace.

04Execute

  1. Attach a Kubernetes distribution to a cert.
  2. Dry-run prints the diff between the live Secret and the one we would write (or would create if it does not exist).
  3. 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.
Pod restart not automatic

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.