TLS
TLS certificate prerequisites for the Scrydon Gateway
All services must be served over HTTPS. For a public hostname that reaches Traefik directly, we recommend cert-manager with Let's Encrypt for automatic certificate provisioning.
If your hostname is private-only (app.internal, something.local, or another zone that is not delegated in public DNS), Let's Encrypt cannot issue a certificate for it. Use an internal ACME CA such as step-ca, or bring your own corporate certificate. If TLS terminates at an upstream load balancer, follow TLS Offloading. See TLS Certificates for the full decision guide.
1. Install cert-manager
# Install cert-manager (if not already present)
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager --create-namespace \
--set crds.enabled=true \
-f cert-manager-values.yamlcert-manager's Gateway API support must be on, or it ignores the annotation the chart puts on the Gateway and no certificate is ever requested. It is off by default:
# cert-manager-values.yaml
config:
apiVersion: controller.config.cert-manager.io/v1alpha1
kind: ControllerConfiguration
# Flat, and spelled exactly this way. cert-manager's own docs say
# `gatewayAPI.enabled`; that shape is rejected by strict decoding and puts the
# controller into CrashLoopBackOff.
enableGatewayAPI: true2. Create a ClusterIssuer
The chart does not create the issuer for you. When gateway.tls.enabled: true (the default), the chart annotates the Gateway with cert-manager.io/cluster-issuer: letsencrypt-prod — one annotation for the whole front door, in both routing modes — but you must create a ClusterIssuer of that exact name. Without it the certificate stays stuck (READY=False, "Issuing certificate as Secret does not exist") and no ACME challenge is ever attempted.
# clusterissuer-letsencrypt-prod.yaml — apply once, after cert-manager is running
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod # MUST match gateway.tls.clusterIssuer (chart default)
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: admin@yourdomain.com # a real address — Let's Encrypt emails expiry notices here
privateKeySecretRef:
name: letsencrypt-prod-account-key # cert-manager CREATES this Secret; do not pre-create it
solvers:
- http01:
gatewayHTTPRoute:
parentRefs:
- kind: Gateway
name: gateway-frontdoor # the Gateway the chart renders
namespace: scrydon-platform # the platform namespace, in every layoutThe solver route attaches to the Gateway's plaintext listener, which the chart keeps hostname-less in both routing modes precisely so an ACME challenge for any hostname can be answered there.
kubectl apply -f clusterissuer-letsencrypt-prod.yaml
kubectl get clusterissuer letsencrypt-prod # wait for READY=True
privateKeySecretRef.nameis not a secret you supply. cert-manager generates an ACME account key on first reconcile and stores it under that name in thecert-managernamespace. The only value you must provide is a real
Point DNS at the Traefik LoadBalancer IP before creating a production issuer. Let's Encrypt validates over HTTP-01 by fetching
http://<your-host>/.well-known/acme-challenge/..., so the hostname must resolve publicly to the controller's IP and port 80 must be reachable. Issuing against prod while DNS is wrong can trip the "5 failed validations per hostname per hour" limit. De-risk the first run with the staging server (https://acme-staging-v02.api.letsencrypt.org/directory, issuer nameletsencrypt-staging, andgateway.tls.clusterIssuer: letsencrypt-staging), confirm a cert issues, then switch to prod.
If you use a different issuer name, set it in your values:
gateway:
tls:
enabled: true
clusterIssuer: my-issuer # defaults to letsencrypt-prod3. Verify issuance
kubectl get clusterissuer # No resources found here = the cause; go back to step 2
kubectl get gateway -n scrydon-platform # PROGRAMMED=True, listeners Accepted
kubectl get certificate -A # the chart's cert flips to READY=True
kubectl describe challenge -A # if stuck: shows the HTTP-01 / DNS errorIf no Certificate appears at all, cert-manager is not watching Gateways — go back to step 1 and confirm config.enableGatewayAPI: true.
Alternatively, you can supply your own certificates as Kubernetes TLS Secrets, use an internal ACME issuer, or terminate TLS at a load balancer in front of the cluster. See TLS Certificates and TLS Offloading.