Search code examples
kuberneteshttp-headersgoogle-kubernetes-enginekubernetes-ingressnginx-ingress

How do I set custom headers using Google Kubernetes Engine?


I understand that an NGINX Ingress controller allows custom header creation using a ConfigMap. Is there either:

  1. a way to use NGINX for GKE or
  2. to directly specify custom headers in the networking.gke.io namespace?

I am specifically interested in setting HTTPS Strict Transport Security, Upgrade Insecure Requests and Content Security Policy headers. I find it a little award that the redirectToHttpfeature does not enabled these by default so I am desperate for any ideas.


Solution

  • Taken from one of my Nginx ingress config values:

    HSTS - under controller.config:

      hsts: "True" # default is "False". Enables HTTP Strict Transport Security (HSTS): the HSTS header is added to the responses from backends. See https://www.nginx.com/blog/http-strict-transport-security-hsts-and-nginx/
      hsts-max-age: "31536000" # default is 2592000 (1 month).
      hsts-include-subdomains: "True" # default is "False".
    

    Redirect to HTTPS - under anotations:

    nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
    

    CORS - Under anotations:

    nginx.ingress.kubernetes.io/enable-cors: "true"
    nginx.ingress.kubernetes.io/cors-allow-origin: "http://localhost:8888/"
    nginx.ingress.kubernetes.io/cors-max-age: "3600"
    nginx.ingress.kubernetes.io/cors-allow-headers: "DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization,apikey,x-apikey,Accept-Language,impersonated,source"
    nginx.ingress.kubernetes.io/cors-allow-methods: "PUT, GET, POST, PATCH, OPTIONS"
    

    So, an example would look like this:

    ❯ kubectl get configmaps -n ingress nginx-ingress-0-24-controller -o yaml

    apiVersion: v1
    data:
      Content-Security-Policy: default-src 'self'; script-src 'self'; object-src 'none';
        style-src 'self' 'unsafe-inline'; frame-src 'self'
      Referrer-Policy: 'Referrer-Policy: strict-origin-when-cross-origin'
      X-API-Token: x
      X-Content-Type-Options: nosniff
      X-Frame-Options: SAMEORIGIN
      X-Using-Nginx-Controller: "true"
      X-XSS-Protection: 1; mode=block
      client_body_buffer_size: 128k
      client_max_body_size: 24M
      enable-vts-status: "true"
      hsts: "True"
      hsts-include-subdomains: "True"
      hsts-max-age: "31536000"
      http-snippet: |
        more_clear_headers 'Server';
      log-format-upstream: '{"time": "$time_iso8601", "remote_addr": "$proxy_protocol_addr",
        "x-forward-for": "$proxy_add_x_forwarded_for", "request_id": "$request_id", "remote_user":
        "$remote_user", "bytes_sent": $bytes_sent, "request_time": $request_time, "status":
        $status, "vhost": "$host", "request_proto": "$server_protocol", "path": "$uri",
        "request_query": "$args", "request_length": $request_length, "duration": $request_time,
        "method": "$request_method", "http_referrer": "$http_referer", "http_user_agent":
        "$http_user_agent"}'
      proxy-hide-headers: Server, server, Access-Control-Allow-Origin, X-Using-Nginx-Controller
      proxy-set-headers: ingress/nginx-ingress-0-24-custom-headers
      server-tokens: "False"
      ssl-ciphers: ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA
      ssl-protocols: TLSv1.2
      use-http2: "true"
    kind: ConfigMap
    metadata:
      creationTimestamp: "2020-08-20T08:46:22Z"
      labels:
        app: nginx-ingress
        chart: nginx-ingress-1.8.2
        component: controller
        heritage: Tiller
        release: nginx-ingress-0-24
      name: nginx-ingress-0-24-controller
      namespace: ingress
      resourceVersion: "205918413"
      selfLink: /api/v1/namespaces/ingress/configmaps/nginx-ingress-0-24-controller
      uid: 9fc20850-e2c1-11ea-87b8-42010af00186
    

    While the annotations go in the ingress yaml:

    ❯ kubectl get ingresses -n system nginx-ingress-ingress-config protect-private -o yaml

    apiVersion: extensions/v1beta1
    kind: Ingress
    metadata:
      annotations:
        kubernetes.io/ingress.class: nginx-0-24
        nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
      creationTimestamp: "2021-03-05T13:03:49Z"
    (...)