Skip to content

Frontend mTLS (GKE)

Runway v2 GKE services can require a client certificate on the external Gateway. The GCP load balancer validates the certificate against root CAs you store in Vault, and only requests that pass validation reach your pods.

Use this when clients connect to your service directly with their own certificates. Traffic that comes through Cloudflare is already protected by Authenticated Origin Pulls; the two cannot be combined on one service.

  1. You store one PEM-encoded root CA certificate per key in the Vault secret runway/env/<environment>/service/<runway_service_id>/trust_anchor_pem.
  2. For each trust anchor, Runway renders an ExternalSecret that writes the certificate into a ConfigMap under the ca.crt key.
  3. The external Gateway references those ConfigMaps in spec.tls.frontend.default.validation.caCertificateRefs. GKE creates the Certificate Manager TrustConfig and the load balancer rejects requests without a valid client certificate.

Store the root CA, not an intermediate. Intermediates typically rotate automatically, which would invalidate the trust anchor.

  • GKE and Runway v2 only. The setting is ignored with a warning on EKS.
  • Requires externalLoadBalancer.enabled: true and an explicit cloudflareSetting.enabled: false. Cloudflare defaults to enabled when omitted, and runwayctl rejects the manifest if either condition is not met.
  • Disabling Cloudflare also disables the Cloudflare IP allowlist, so the load balancer is reachable from the internet. Client certificate validation is then the only origin protection.
  • Runway does not forward client certificate fields (such as the subject) to your application. Ask in #g_runway if you need this.
  1. Add the root CA to Vault. Under your workload’s secrets path (see Secrets Management), create a secret named trust_anchor_pem with a key default_cert holding the PEM certificate.

  2. Enable it in the deployment manifest:

    .runway/deployment.yaml
    spec:
    loadBalancing:
    externalLoadBalancer:
    enabled: true
    customMtls:
    enabled: true
    cloudflareSetting:
    enabled: false
  3. Deploy. The ExternalSecret refreshes from Vault every 10 minutes, so a certificate changed in Vault is picked up without a new deployment.

List several trust anchors to keep an old and a new root trusted while clients migrate:

.runway/deployment.yaml
spec:
loadBalancing:
externalLoadBalancer:
enabled: true
customMtls:
enabled: true
trustAnchorNames: [root_2024, root_2034]
cloudflareSetting:
enabled: false

Each entry is a key of the trust_anchor_pem Vault secret. Add the new key in Vault, deploy with both names, move clients to the new root, then drop the old name and key. When trustAnchorNames is omitted it defaults to [default_cert].

Names must be lowercase letters, digits and underscores, up to 40 characters, with at most 8 anchors. Each name becomes part of a ConfigMap name (<name>-frontend-mtls-ca-<anchor>, with underscores turned into hyphens).

Ask in #g_runway. Frontend mTLS was added in runway/team#1045.