Skip to content

TLS setup

Mike Williamson edited this page Mar 4, 2021 · 1 revision

A secure TLS setup is good example of the need to implement security across all architectural layers; HTTP headers, server configuration, certificate settings and recently DNS must all align for a domain to be established as a root of trust.

Certificates

Certificate provisioning for the Tracker project is fully automated using Cert Manager.

Cert Manager provides Custom Resource Definitions (CRDs) that describes the where certificates come from, and the certificate itself.

Let's Encrypt is the entity that issues certificates for the Tracker project. This is represented using the Issuer object supplied by Cert Manager.

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: letsencrypt
  namespace: istio-system
spec:
  acme:
    email: mike@korora.ca
    preferredChain: ""
    privateKeySecretRef:
      name: letsencrypt-prod
    server: https://acme-v02.api.letsencrypt.org/directory
    solvers:
    - http01:
        ingress:
          class: istio
      selector: {}
status: {}

In line with the declarative approach that Kubernetes takes, certificates are requested via a statement that a certificate should exist that takes the form of a Certificate object.

[mike@ouroboros tracker]$ cat app/gke/certificate.yaml 
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: ingress-cert
  namespace: istio-system
spec:
  commonName: tracker.alpha.canada.ca
  dnsNames:
  - tracker.alpha.canada.ca
  - suivi.alpha.canada.ca
  issuerRef:
    kind: Issuer
    name: letsencrypt
  privateKey:
    algorithm: RSA
    encoding: PKCS8 # ITSP.40.062 6.2 Signature Algorithms
    size: 4096
  secretName: tracker-credential
status: {}

This object ends up using certificatesigningrequests and certificaterequest objects to send a request to the issuer, complete the ACME protocols HTTP-01 challenge, and save the result in a Kubernetes secret with the name specified by the secretName field.

As the name implies, the HTTP-01 challenge takes place over HTTP, but Let's Encrypt employs a multi-vantage-point verification process to mitigate against MITM attacks.

Server Config

Incoming requests are recieved by Istio's ingress gateway which then forwards the request among it's network of centrally controlled proxies according the the routing policy objects defined in the project.

Istio supplies a Gateway object that uses the secret created by the Certificate object above. The Gateway is where layer 4 concerns like ports and layer 6 details like TLS are handled, leaving layer 7 routing to a separate VirtualService object.

The details of Treasury Board's ITPIN can be mapped pretty directly to the properties of the Gateway object.

[mike@ouroboros tracker]$ cat app/gke/publicgateway.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: publicgateway
  namespace: istio-system
  labels:
    istio: publicgateway
spec:
  selector:
    istio: ingressgateway
  servers:
    - port:
        number: 80
        name: http
        protocol: HTTP
      hosts:
        - "*"
      tls:
        httpsRedirect: true # ITPIN 6.1.1 redirected from HTTP
    - port:
        number: 443
        name: https
        protocol: HTTPS # ITPIN 6.1.1 is configured for HTTPS
      hosts:
        - "*"
      tls:
        mode: SIMPLE
        credentialName: tracker-credential
        privateKey: sds
        serverCertificate: sds
        minProtocolVersion: TLSV1_2 # ITPIN 6.1.3 implements TLS 1.2, or subsequent versions
        cipherSuites: # ITPIN 6.1.3 uses supported cryptographic algorithms
        - TLS_AES_128_GCM_SHA256
        - TLS_AES_256_GCM_SHA384
        - TLS_CHACHA20_POLY1305_SHA256
        - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
        - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
        - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384

Headers

Web applications recieve HTTP requests and return HTTP responses, meaning the headers are typically the provice of the application developer. There are a few headers we always want set for our application, like the HSTS header required by the ITPIN. Istio doesn't provide a nice interface for this particular use-case, but does provide the EnvoyFilter object as a mechanism to talk directly to the Envoy proxy it uses for ingress.

Using that we can patch all outgoing requests so that security headers like HSTS are consistently applied.

[mike@ouroboros tracker]$ cat platform/components/istio/envoy-security-headers-filter.yaml 
apiVersion: networking.istio.io/v1alpha3
kind: EnvoyFilter
metadata:
  name: security-headers
  namespace: istio-system
spec:
  workloadSelector:
    labels:
      istio: ingressgateway
  configPatches:
  - applyTo: HTTP_FILTER
    match:
      context: GATEWAY
      listener:
        filterChain:
          filter:
            name: "envoy.http_connection_manager"
            subFilter:
              name: "envoy.router"
    patch: # Patch outgoing requests for ITPIN 6.1.2: has HSTS enabled
      operation: INSERT_BEFORE
      value:
       name: envoy.lua
       typed_config:
         "@type": "type.googleapis.com/envoy.config.filter.http.lua.v2.Lua"
         inlineCode: |
            function envoy_on_response(response_handle)
              if not response_handle:headers():get("X-Frame-Options") then
                response_handle:headers():add("X-Frame-Options", "deny");
              end
              if not response_handle:headers():get("Strict-Transport-Security") then
                response_handle:headers():add("Strict-Transport-Security", "max-age=31536000; includeSubDomains");
              end
            end