5.1.2 Certificates¶
cert-manager automates the issuance and renewal of X.509 TLS certificates from sources such as Let's Encrypt, Vault, or private CAs. Every ingress-exposed service in the cluster relies on cert-manager for its TLS certificates.
How to use this page
Each component has an Install section showing the Flux HelmRelease, a Configuration section with Helm values, and a Verify section to confirm it is working.
All code blocks are labelled with their file path in the repository. Select your target environment (AWS or Bare Metal) in any tab group — the choice syncs across the entire page.
- Using the existing
rciis-devopsrepository: All files already exist. Skip themkdirandgit add/git commitcommands — they are for users building a new repository. Simply review the files, edit values for your environment, and push. - Building a new repository from scratch: Follow the
mkdir, file creation, andgitcommands in order. - No Git access: Expand the "Alternative: Helm CLI" block under each Install section.
cert-manager¶
cert-manager runs as a Deployment with three components: the main controller, the webhook, and the CA injector. It watches for Certificate and ClusterIssuer resources and orchestrates certificate issuance, renewal, and injection into Secrets.
Install¶
The base HelmRelease tells Flux which chart to install. This file is shared across all environments — environment-specific settings are applied via patches (shown in the Configuration section).
Create the base directory and file:
| Field | Value | Explanation |
|---|---|---|
chart |
cert-manager |
The Helm chart name from the Jetstack registry |
version |
1.19.4 |
Pinned chart version — update this to upgrade cert-manager |
sourceRef.name |
jetstack |
References a HelmRepository CR pointing to https://charts.jetstack.io |
targetNamespace |
cert-manager |
cert-manager runs in its own namespace |
crds: CreateReplace |
— | Automatically installs and updates cert-manager CRDs |
remediation.retries |
3 |
Flux retries up to 3 times if the install or upgrade fails |
Save the following as flux/infra/base/cert-manager.yaml:
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
namespace: flux-system
spec:
targetNamespace: cert-manager
interval: 30m
chart:
spec:
chart: cert-manager
version: "1.19.4"
sourceRef:
kind: HelmRepository
name: jetstack
namespace: flux-system
releaseName: cert-manager
install:
createNamespace: true
crds: CreateReplace
remediation:
retries: 3
upgrade:
crds: CreateReplace
remediation:
retries: 3
values:
crds:
enabled: true
keep: true
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
nodeTaintsPolicy: Honor
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: controller
startupapicheck:
timeout: 5m
webhook:
hostNetwork: false
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: webhook
cainjector:
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: cainjector
global:
rbac:
create: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
prometheus:
enabled: true
servicemonitor:
enabled: true
labels:
release: prometheus
Alternative: Helm CLI
If you do not have Git access, install cert-manager directly:
Configuration¶
The environment patch overrides the base HelmRelease with cluster-specific settings. The values file controls how cert-manager behaves. Select your environment and deployment size below.
Create the environment overlay directory:
Environment Patch¶
The patch file enables Gateway API support and adjusts replica counts based on cluster size. Save the following as the patch file for your environment:
On AWS, cert-manager is configured with a single replica to reduce costs while maintaining functionality. Gateway API support is enabled for automatic certificate provisioning on Gateway resources.
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
spec:
storageNamespace: cert-manager
values:
replicaCount: 1
topologySpreadConstraints: []
config:
enableGatewayAPI: true
webhook:
replicaCount: 1
topologySpreadConstraints: []
cainjector:
replicaCount: 1
topologySpreadConstraints: []
| Setting | Value | Why |
|---|---|---|
replicaCount: 1 |
Single replica | AWS has built-in HA; single cert-manager instance is sufficient |
topologySpreadConstraints: [] |
Disabled | No need for spread constraints with one replica |
config.enableGatewayAPI |
true |
Enables automatic certificate provisioning for Gateway API resources |
webhook.replicaCount |
1 |
Webhook runs on a single replica for cost efficiency |
On Bare Metal, cert-manager is configured for HA with topology spreading to ensure availability across cluster nodes. Gateway API support is enabled.
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
spec:
values:
config:
enableGatewayAPI: true
| Setting | Value | Why |
|---|---|---|
config.enableGatewayAPI |
true |
Enables automatic certificate provisioning for Gateway API resources |
On Bare Metal, cert-manager is configured for HA with topology spreading to ensure availability across cluster nodes. Gateway API support is enabled.
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: cert-manager
spec:
values:
config:
enableGatewayAPI: true
| Setting | Value | Why |
|---|---|---|
config.enableGatewayAPI |
true |
Enables automatic certificate provisioning for Gateway API resources |
Helm Values¶
The values file controls cert-manager's core features. For Bare Metal, the base
configuration in flux/infra/base/cert-manager.yaml already includes HA settings
and does not require additional values overrides — the patch above is sufficient.
For AWS, if you need to customize beyond the patch, you can create a values file. Most AWS deployments use the patch only.
# cert-manager — AWS HA configuration
# Use only if you need to override base values
crds:
enabled: true
keep: true
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
nodeTaintsPolicy: Honor
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: controller
startupapicheck:
timeout: 5m
webhook:
hostNetwork: false
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: webhook
cainjector:
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: cainjector
global:
rbac:
create: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
prometheus:
enabled: true
servicemonitor:
enabled: true
labels:
release: prometheus
# cert-manager — AWS Non-HA configuration
# Single replica per component, reduced resources
crds:
enabled: true
keep: true
replicaCount: 1
startupapicheck:
timeout: 5m
webhook:
hostNetwork: false
replicaCount: 1
cainjector:
replicaCount: 1
global:
rbac:
create: true
resources:
requests:
cpu: 25m
memory: 32Mi
limits:
cpu: 100m
memory: 128Mi
prometheus:
enabled: true
servicemonitor:
enabled: false
The base configuration already includes HA settings. No additional values file is required unless you want to customize specific behavior. The patch above is sufficient for most deployments.
If customization is needed:
# cert-manager — Bare Metal HA configuration (Base settings)
# This is already defined in flux/infra/base/cert-manager.yaml
# Only create this file if you need to override specific values
crds:
enabled: true
keep: true
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
nodeTaintsPolicy: Honor
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: controller
startupapicheck:
timeout: 5m
webhook:
hostNetwork: false
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: webhook
cainjector:
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: cainjector
global:
rbac:
create: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
prometheus:
enabled: true
servicemonitor:
enabled: true
labels:
release: prometheus
The base configuration already includes HA settings. No additional values file is required unless you want to customize specific behavior. The patch above is sufficient for most deployments.
If customization is needed:
# cert-manager — Bare Metal HA configuration (Base settings)
# This is already defined in flux/infra/base/cert-manager.yaml
# Only create this file if you need to override specific values
crds:
enabled: true
keep: true
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
nodeTaintsPolicy: Honor
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: controller
startupapicheck:
timeout: 5m
webhook:
hostNetwork: false
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: webhook
cainjector:
replicaCount: 2
topologySpreadConstraints:
- maxSkew: 1
topologyKey: kubernetes.io/hostname
whenUnsatisfiable: DoNotSchedule
labelSelector:
matchLabels:
app.kubernetes.io/instance: cert-manager
app.kubernetes.io/component: cainjector
global:
rbac:
create: true
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 200m
memory: 256Mi
prometheus:
enabled: true
servicemonitor:
enabled: true
labels:
release: prometheus
Key settings (all environments):
| Setting | Value | Why |
|---|---|---|
crds.enabled |
true |
Automatically installs cert-manager CRDs (Certificate, Issuer, ClusterIssuer) |
replicaCount |
1 (AWS) / 2 (Bare Metal) | Controller instances — bare metal uses 2 for HA |
topologySpreadConstraints |
Enabled (Bare Metal) | Spreads replicas across different nodes for availability |
config.enableGatewayAPI |
true |
Enables automatic cert provisioning for Gateway API resources |
webhook.replicaCount |
1 (AWS) / 2 (Bare Metal) | Webhook instances for certificate validation |
prometheus.enabled |
true |
Exports cert-manager metrics for monitoring |
Extra Manifests¶
Save the following ClusterIssuer for your environment. This enables automatic certificate provisioning from Let's Encrypt using Cloudflare DNS-01 challenges.
Save as flux/infra/aws/cert-manager/cluster-issuer.yaml:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare-issuer
spec:
acme:
email: [email protected]
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: cloudflare-issuer-account-key
solvers:
- dns01:
cloudflare:
email: [email protected]
apiKeySecretRef:
name: cloudflare-api-key
key: api-key
Info
The ClusterIssuer uses the cloudflare-api-key Secret in the cert-manager
namespace. This Secret is deployed via SOPS-encrypted secrets in
apps/infra/secrets/. The issuer automatically renews certificates 30 days
before expiration.
Save as flux/infra/baremetal/cert-manager/cluster-issuer.yaml:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare-issuer
spec:
acme:
email: [email protected]
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: cloudflare-issuer-account-key
solvers:
- dns01:
cloudflare:
email: [email protected]
apiKeySecretRef:
name: cloudflare-api-key
key: api-key
Info
The ClusterIssuer uses the cloudflare-api-key Secret in the cert-manager
namespace. This Secret is deployed via SOPS-encrypted secrets in
apps/infra/secrets/. The issuer automatically renews certificates 30 days
before expiration.
Save as flux/infra/baremetal/cert-manager/cluster-issuer.yaml:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: cloudflare-issuer
spec:
acme:
email: [email protected]
server: https://acme-v02.api.letsencrypt.org/directory
privateKeySecretRef:
name: cloudflare-issuer-account-key
solvers:
- dns01:
cloudflare:
email: [email protected]
apiKeySecretRef:
name: cloudflare-api-key
key: api-key
Info
The ClusterIssuer uses the cloudflare-api-key Secret in the cert-manager
namespace. This Secret is deployed via SOPS-encrypted secrets in
apps/infra/secrets/. The issuer automatically renews certificates 30 days
before expiration.
Commit and Deploy¶
Once all files are in place, commit and push to trigger Flux deployment:
Flux will detect the new commit and begin deploying cert-manager. To trigger an immediate sync instead of waiting for the next poll interval:
Verify¶
After cert-manager is deployed, confirm it is working:
# Test certificate issuance (optional)
kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: test-cert
namespace: default
spec:
secretName: test-cert-tls
issuerRef:
name: cloudflare-issuer
kind: ClusterIssuer
dnsNames:
- test.rciis.africa
EOF
# Clean up test certificate
kubectl delete certificate test-cert -n default
kubectl delete secret test-cert-tls -n default
Flux Operations¶
This component is managed by Flux as HelmRelease cert-manager and Kustomization infra-cert-manager.
Check whether the HelmRelease and Kustomization are in a Ready state:
Trigger an immediate sync — pulls the latest Git revision and re-applies the manifests. Use after pushing config changes or to verify a fix:
Trigger a Helm upgrade — re-runs the Helm install/upgrade for this release without waiting for the next interval. Use when the HelmRelease values have changed:
View recent Flux controller logs for this release — useful for diagnosing why a sync or upgrade failed:
Recovering a stalled HelmRelease
If the HelmRelease shows Stalled with RetriesExceeded, Flux will not retry automatically. Suspend and resume to clear the failure counter, then reconcile:
flux suspend helmrelease cert-manager -n flux-system
flux resume helmrelease cert-manager -n flux-system
flux reconcile kustomization infra-cert-manager -n flux-system
Only run this after confirming the underlying issue (e.g. pod crash, timeout) has been resolved. See Maintenance — Recovering Stalled Resources for details.
Next Steps¶
Certificates are now configured. Proceed to 5.1.3 GitOps & Delivery to set up Flux and the GitOps deployment pipeline.