Situation

A Recent Task Was To Convert An Existing External Environment On GCP Into An Internal One. The Whole Setup Runs On GKE With Gateway API Handling Load Balancing. The Assumption Going In Was That A Google-Managed Certificate Would Attach To The Gateway API Internal LB The Same Way It Already Worked On The Gateway API External LB. That Assumption Ran Into Trouble Immediately.

Result First:

Expected Attach An Existing Google-Managed Certificate Manager Cert To An Internal Regional Gateway, Same As Already Works On The External One
Actual GKE’s Gateway Controller Silently Refuses — Treats The Certificate Reference As If It Doesn’t Exist
Root Cause gke-l7-rilb Does Not Support Google-Managed Certificates At All. Verified Against The Official GatewayClass Capabilities Table, Then Confirmed Live By Actually Trying It
The Twist The Underlying GCP Product — A Regional Internal Application Load Balancer — Has No Such Restriction. The Gap Is Specific To GKE’s Gateway API Controller, Not The Infrastructure It’s Built On
Fix Bypassed The Controller Entirely — Built The Regional Internal ALB Directly Via Raw Compute Engine Resources, Reusing The Existing Backend Service

Turns Out “It Already Works On The External One” Was Never Good Evidence For Internal. Two GatewayClasses, Same API Surface, Same Cluster, Completely Different Certificate Support — And Nothing About The YAML You’d Write Tells You That Up Front.

Finding Out The Hard Way

First Move Was The Obvious One — Add The Certificate Manager Annotation To A Gateway And See What Happens:

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  annotations:
    networking.gke.io/certificate-manager-certs: my-managed-cert
spec:
  gatewayClassName: gke-l7-rilb
  listeners:
    - name: https
      protocol: HTTPS
      port: 443

Applied Cleanly. Accepted: True. Then Programmed Flipped To False:

Error GWCER106: Gateway "..." is invalid, err: no certificates specified for protocol "HTTPS"

Read That Twice. The Annotation Is Right There. The Certificate Exists, Is Active, Has A Valid Expiry Date Months Out. GKE’s Own Error Message Is Reporting It As Though The Field Were Empty — Not “Certificate Invalid,” Not “Certificate Not Found,” Just Not Specified. That Phrasing Is The Tell: The Controller Isn’t Rejecting The Certificate. It’s Not Recognizing The Annotation As Applicable To This GatewayClass At All, And Falling Back To Its Generic “You Didn’t Give Me A Cert” Path.

Went To The Actual GatewayClass Capabilities Documentation Rather Than Assume From The Error Text Alone. The Table Is Explicit For Internal Regional (gke-l7-rilb) — Three Supported Certificate Mechanisms Listed:

  • Kubernetes Secret-Based Certificates
  • Self-Managed Compute Engine SSL Certificates
  • Self-Managed Certificate Manager Certificates

Google-Managed Certificates — Whether The Classic Compute Engine Kind Or The Certificate Manager Kind — Aren’t On That List For This GatewayClass. They Are For The External GatewayClasses (Both Regional And Global). That Asymmetry Is The Whole Bug: It’s Not That Internal Load Balancers Can’t Do Google-Managed Certs As A Category. It’s That This Specific GatewayClass’s Controller Implementation Never Wired Up That Path.

Notes

  • A Working External Example Told Me Nothing Useful About Internal. Same Cluster, Same Kind Of Certificate, Same General Idea Of “Attach A Cert To A Gateway” — And Zero Transferable Confidence, Because The Actual Support Matrix Is Keyed Per GatewayClass, Not Per Feature Category.
  • “No Certificates Specified” From A Config That Clearly Specifies One Is A Strong Signal The Field Is Being Ignored, Not Rejected. Worth Distinguishing Early — It Changes Where You Go Looking For Answers (Capability Docs, Not Certificate Troubleshooting).

The Twist: The Underlying Load Balancer Doesn’t Have This Problem

Before Accepting “Can’t Be Done,” Checked Whether The Restriction Was Really About The Load Balancer Product Or Just The Kubernetes-Level Abstraction Sitting On Top Of It. Google’s Own Certificate Manager Documentation Answered That Directly:

To deploy the regional Google-managed certificate to a regional external Application Load Balancer or regional internal Application Load Balancer, attach it directly to the target proxy.

gcloud compute target-https-proxies update PROXY_NAME --region=LOCATION \
  --certificate-manager-certificates=CERTIFICATE_NAME

No Caveat About Backend Type, No Mention Of GKE At All. The Regional Internal Application Load Balancer — As A GCP Product — Fully Supports Google-Managed Certificates On Its target-https-proxy. GKE’s Gateway API Just Never Exposed That Capability Through Its Own CRD For This GatewayClass. Two Completely Separate Layers: The Infrastructure Underneath Is Capable; The Kubernetes-Native Interface On Top Of It Has A Gap.

Confirmed It’s Not A Doc-Reading Error By Actually Building One — A Throwaway Regional Internal Backend Service, URL Map, Target HTTPS Proxy With That Exact Certificate Attached Via --certificate-manager-certificates, Forwarding Rule. It Came Up Fine. TLS Terminated Correctly, Traffic Reached The Backend.

Notes

  • A Kubernetes Abstraction’s Limitation Is Not Automatically The Underlying Cloud Product’s Limitation. GKE Gateway, Terraform’s Google Provider, gcloud, The Web Console — Each Is A Different Surface Over The Same Compute Engine Resources, And Each Can Lag The Others In Feature Coverage. When Something “Isn’t Supported,” Worth Asking Which Layer Is Actually Making That Claim.
  • The Fix Path That Worked Was Prefigured In The Error Message’s Vagueness. “No Certificates Specified” Rather Than A Certificate-Specific Rejection Was The Clue That The Real Gap Was In What The Controller Understood, Not In The Certificate Itself.

Working Around A Controller Gap, Not A Product Limitation

Given The Existing Gateway’s IP Was Already Depended On By Another Internal Service With The Address Hardcoded — Not Something To Touch Casually, And Recreating The Gateway Object Offered No Guarantee Of Reclaiming The Same IP Afterward — Chose Not To Rebuild It At All. Instead, Added A Second, Independent Entry Point Built From Raw Compute Resources, Pointed At The Exact Same Backend Service The Existing Gateway Already Used, With A Brand New Reserved Internal Address:

gcloud compute addresses create new-internal-addr --region=REGION --subnet=SUBNET \
  --purpose=SHARED_LOADBALANCER_VIP

gcloud compute url-maps create new-internal-urlmap --region=REGION \
  --default-service=EXISTING_BACKEND_SERVICE

gcloud compute target-https-proxies create new-internal-proxy --region=REGION \
  --url-map=new-internal-urlmap \
  --certificate-manager-certificates=CERTIFICATE_NAME

gcloud compute forwarding-rules create new-internal-fr --region=REGION \
  --load-balancing-scheme=INTERNAL_MANAGED \
  --network=NETWORK --subnet=SUBNET --address=new-internal-addr \
  --ports=443 --target-https-proxy=new-internal-proxy --target-https-proxy-region=REGION

Zero Existing Resources Touched. The Original HTTP-Only Gateway Kept Serving Its Dependent Exactly As Before. The New HTTPS Entry Point Came Up Pointed At The Same Backend, TLS Terminating Correctly, Verified From Inside The Cluster.

Notes

  • Reusing An Existing Backend Service Across Both The Old Gateway-Managed Path And The New Hand-Built One Meant Zero New NEGs, Zero New Health Checks — Genuinely Additive, Not A Parallel Copy Of The Whole Stack. A GCP Backend Service Can Be Referenced By Multiple URL Maps Simultaneously; No Need To Duplicate It Per Frontend.
  • “Rebuild The Load Balancer” And “Recreate The Same Kubernetes Object” Are Not The Same Sentence, Even Though They Sound Like It. The Actual Fork In The Road Was Never About Rebuilding Infrastructure — It Was About Which Control Plane Manages It Going Forward, And What Certificate Type That Choice Locks You Into.

Which One To Use

Scenario What To Do
Attaching Any Certificate To A GKE Gateway API Object Check The Official GatewayClass Capabilities Table For That Specific Class First — Don’t Infer From A Working Example On A Different GatewayClass In The Same Cluster
Getting GWCER106 Or Any “No Certificate Specified” Error On A Gateway That Clearly References One Treat It As A Sign The Field Isn’t Recognized For This GatewayClass, Not As A Certificate Problem — Go Check Capability Docs Before Re-Checking The Certificate
A Kubernetes Abstraction Claims A Cloud Feature Isn’t Supported Verify Against The Underlying Cloud Product’s Own Documentation Before Accepting It As A Hard Limit — The Gap May Be In The K8s-Level Controller’s Feature Coverage, Not The Infrastructure
Need Google-Managed Cert Support On A Regional Internal ALB Backing A GKE Service, And The GatewayClass Won’t Cooperate Build The Load Balancer’s Frontend (URL Map + Target HTTPS Proxy + Forwarding Rule) Directly Via Terraform/gcloud, Pointed At The Existing GKE-Managed Backend Service — No Need To Duplicate Backends Or NEGs
An Existing Internal IP Has Downstream Consumers With It Hardcoded Don’t Recreate That Load Balancer Object To Add A Feature — Reserving The Exact Same IP Afterward Isn’t Guaranteed. Add A Second, Independent Entry Point Instead

Reference: