Back to posts

GKE FrontendConfig — Auto Redirect HTTP to HTTPS

Read the full guide on docs.beyondyou.my.id
gcpgkekubernetesfrontend-configtlshttpsgateway-api

GKE FrontendConfig — Auto Redirect HTTP to HTTPS

Table of Contents

SectionTopicDescription
01Why FrontendConfigThe problem with manual HTTP→HTTPS redirect on GKE.
02FrontendConfig ResourceSpec breakdown and response codes.
03Ingress IntegrationBinding FrontendConfig to an Ingress.
04Gateway API EquivalentHow HTTP→HTTPS redirect works with Gateway API.
05Testing & ValidationVerifying the redirect behavior.
06Common PitfallsThings that break the redirect.

1. Why FrontendConfig

On GKE, the load balancer handles TLS termination. Without explicit configuration, HTTP traffic on port 80 reaches your backend directly — no redirect happens.

ApproachHowDrawback
App-level redirectSpring Boot / Express middlewareExtra latency, app must handle TLS context
Nginx Ingress annotationnginx.ingress.kubernetes.io/ssl-redirectVendor-specific, not portable
FrontendConfigGKE-native, LB-levelGKE-specific, not part of upstream K8s

FrontendConfig is the recommended GKE approach — the redirect happens at the load balancer, before traffic ever reaches your pods.


2. FrontendConfig Resource

apiVersion: networking.gke.io/v1beta1
kind: FrontendConfig
metadata:
  name: [environment]-[app_name]-frontendconfig
  namespace: [namespace]
  labels:
    app: [app_name]
    env: [environment]
    team: [team_name]
    app.kubernetes.io/name: [app_name]
    app.kubernetes.io/instance: [environment]-[app_name]
    app.kubernetes.io/component: [component_name]
    app.kubernetes.io/part-of: [Company/Project]
    app.kubernetes.io/managed-by: DevOpsTeam
spec:
  redirectToHttps:
    enabled: true
    responseCodeName: PERMANENT_REDIRECT

Response Code Options

Code NameHTTP CodePurpose
MOVED_PERMANENTLY_DEFAULT301Default, cacheable by browsers
PERMANENT_REDIRECT308Preserves HTTP method (POST stays POST)
TEMPORARY_REDIRECT307Temporary, never cacheable

Which Code to Use

ScenarioCodeWhy
Standard websiteMOVED_PERMANENTLY_DEFAULTBrowsers cache the redirect
API with POST/PUTPERMANENT_REDIRECT308 preserves request method
Maintenance modeTEMPORARY_REDIRECTClients retry the original URL

Recommendation: Use PERMANENT_REDIRECT (308) for most cases — it’s the safest default that preserves HTTP methods.


3. Ingress Integration

FrontendConfig is attached to an Ingress via the networking.gke.io/frontend-config annotation.

Full Example

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: [environment]-[app_name]-ingress
  namespace: [namespace]
  annotations:
    kubernetes.io/ingress.class: gce
    networking.gke.io/managed-certificates: [certificate_name]
    networking.gke.io/frontend-config: [environment]-[app_name]-frontendconfig
  labels:
    app: [app_name]
    env: [environment]
    team: [team_name]
    app.kubernetes.io/name: [app_name]
    app.kubernetes.io/instance: [environment]-[app_name]
    app.kubernetes.io/component: [component_name]
    app.kubernetes.io/part-of: [Company/Project]
    app.kubernetes.io/managed-by: DevOpsTeam
spec:
  rules:
  - host: [app_name].example.id
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: [environment]-[app_name]-svc
            port:
              number: 80

Annotation Reference

AnnotationValuePurpose
kubernetes.io/ingress.classgceUse GKE L7 load balancer
networking.gke.io/managed-certificatescert nameTLS certificate binding
networking.gke.io/frontend-configFrontendConfig nameHTTP→HTTPS redirect

What Happens at the LB

sequenceDiagram
    participant Client
    participant GKE_LB as GKE Load Balancer
    participant Pod

    Client->>GKE_LB: HTTP GET / (port 80)
    GKE_LB-->>Client: 308 PERMANENT_REDIRECT → https://
    Client->>GKE_LB: HTTPS GET / (port 443)
    GKE_LB->>Pod: Forward request
    Pod-->>GKE_LB: 200 OK
    GKE_LB-->>Client: 200 OK

4. Gateway API Equivalent

If you’re using Gateway API instead of Ingress, HTTP→HTTPS redirect is handled at the Gateway listener level — no FrontendConfig needed.

Gateway with Both Listeners

apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: example-gateway
  namespace: gateway-api
spec:
  gatewayClassName: gke-l7-global-external-managed
  listeners:
  - name: http
    protocol: HTTP
    port: 80
    hostname: "*.example.id"
    allowedRoutes:
      namespaces:
        from: All
  - name: https
    protocol: HTTPS
    port: 443
    hostname: "*.example.id"
    tls:
      mode: Terminate
      options:
        networking.gke.io/pre-shared-certs: [certificate_name]
    allowedRoutes:
      namespaces:
        from: All

HTTPRoute with Redirect

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: redirect-http-to-https
  namespace: gateway-api
spec:
  parentRefs:
  - name: example-gateway
    sectionName: http
  hostnames:
  - "*.example.id"
  rules:
  - filters:
    - type: RequestRedirect
      requestRedirect:
        scheme: https
        statusCode: 301

Comparison

FeatureIngress + FrontendConfigGateway API + HTTPRoute
Redirect mechanismLB-level via FrontendConfigHTTPRoute filter
ConfigurationAnnotation + CRDHTTPRoute filters
Port handlingLB handles both portsSeparate listeners
GranularityPer-IngressPer-HTTPRoute
TLS terminationIngress specGateway listener

5. Testing & Validation

Verify Redirect

# Should return 308 redirect to https
curl -I http://[app_name].example.id/

# Expected output
HTTP/1.1 308 Permanent Redirect
Location: https://[app_name].example.id/

Follow Redirect

# Should follow redirect and return 200
curl -L http://[app_name].example.id/

# Direct HTTPS should work
curl https://[app_name].example.id/

Check FrontendConfig Status

kubectl get frontendconfig -n [namespace]
kubectl describe frontendconfig [name] -n [namespace]

Check Ingress Annotations

kubectl get ingress -n [namespace] -o yaml | grep frontend-config

6. Common Pitfalls

PitfallSymptomFix
Missing networking.gke.io/frontend-config annotationNo redirect, HTTP serves directlyAdd annotation to Ingress
Wrong FrontendConfig name in annotationNo redirect, no errorVerify name matches metadata.name
FrontendConfig in wrong namespaceAnnotation found but not appliedFrontendConfig must be in same namespace as Ingress
Using gce class with FrontendConfigWorksFrontendConfig only works with gce class
FrontendConfig with Gateway APIIgnoredUse HTTPRoute filter instead
Health check fails after redirectPods marked unhealthyEnsure health check path works over HTTP too
Mixed content warningsBrowser blocks resourcesEnsure all assets use HTTPS URLs

References