In this guide, you deploy an AWS Network Load Balancer (NLB) that encrypts traffic to the Gloo UI, as illustrated in the following diagram. TLS certificates are issued by using the Certificate Authority (CA) Let’s Encrypt, and are managed with cert-manager.

High level overview

Before you begin

  1. Set the following environment variables.

      export DOMAIN_NAME=<domain name for the GlooUI>
    export CLUSTER_REGION=<AWS region where the cluster is hosted>
      
  2. Set up the Gloo UI domain name as a DNS record in AWS Route53. Tools such as ExternalDNS can assist with automating this process. For more information and guidance, see the ExternalDNS documentation.

Expose the Gloo UI and configure it for HTTPS traffic

  1. Install cert-manager in your cluster. For more information about installation options and supported versions, see the cert-manager documentation. Refer to Best Practice if you plan to install cert-manager in production environments.

  2. Verify that cert-manager is installed successfully.

      kubectl get pods -n cert-manager
      

    Example output:

      NAME                                      READY   STATUS    RESTARTS   AGE
    cert-manager-79c4cd854c-6z9xq             1/1     Running   0          8d
    cert-manager-cainjector-97795797f-jjpz2   1/1     Running   0          8d
    cert-manager-webhook-979c74b9c-frcfp      1/1     Running   0          8d
      
  3. Install the AWS Load Balancer controller. For deployment considerations, see the AWS Load Balancer Controller documentation.

      helm repo add eks https://aws.github.io/eks-charts
    helm repo update eks
    
    # Deploy the CRDs
    wget https://raw.githubusercontent.com/aws/eks-charts/master/stable/aws-load-balancer-controller/crds/crds.yaml
    kubectl apply -f crds.yaml
    
    # Helm install
    helm upgrade --install \
      aws-load-balancer-controller eks/aws-load-balancer-controller \
      --namespace kube-system \
      --version v2.6.2 \
      --set clusterName=<cluster-name> \
      --set serviceAccount.create=false \
      --set serviceAccount.name=aws-load-balancer-controller
      
  4. Verify that the AWS Load Balancer controller is installed successfully.

      kubectl get pods -n kube-system | grep aws
      

    Example output:

      NAME                                           READY   STATUS    RESTARTS   AGE
    aws-load-balancer-controller-7c8f46dc8-9wnm2   1/1     Running   0          8d
      
  5. Create the cert-manager Issuer resource that represents the Certificate Authority (CA) that you want to use to issue the TLS certificates for your domain. In this example, you configure cert-manager to obtain a TLS certificate from Let’s Encrypt by using the ACME protocol.

    To automate domain validation in AWS Route53, the dns01 challenge is used. For information about how to set up the dns01 challenge in AWS Route53, see Route53. To manage access to AWS Route53, it is considered a best practice to use EKS IAM Role for Service Accounts (IRSA).

      cat << EOF | kubectl apply -f -
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: letsencrypt-cert-issuer
      namespace: gloo-mesh
    spec:
      acme:
        server: https://acme-v02.api.letsencrypt.org/directory
        preferredChain: "ISRG Root X1"
        email: hello@world.com
        privateKeySecretRef:
          name: cert-issuer
        solvers:
          - dns01:
              route53:
                region: $CLUSTER_REGION
    EOF
      
  6. Create the cert-manager Certificate resource to initiate the certificate issuance process from Let’s Encrypt.

      cat << EOF | kubectl apply -f -
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: gloo-ui-tls-certificate
      namespace: gloo-mesh
      annotations:
        # Issue a temporary certificate until the issuance process is complete.
        certmanager.k8s.io/issue-temporary-certificate: "true"
    spec:
      issuerRef:
        # References the Issuer created in the previous step
        name: letsencrypt-cert-issuer
        kind: Issuer
      # Matches with the `glooUi.tls.secretName` Helm value.
      secretName: gloo-ui-tls
      dnsNames:
        - glooui.${DOMAIN_NAME}
      duration: 2160h # 90 days
      renewBefore: 360h # 15 days
      subject:
        organizations:
          - solo.io
      isCA: false
      privateKey:
        algorithm: RSA
        encoding: PKCS1
        size: 2048
      usages:
        - server auth
    EOF
      

    Review the following table to understand this configuration.

    SettingDescription
    secretNameThis field must match the glooUi.tls.secretName Helm value in the Gloo Network Helm chart and represents the Kubernetes secret where cert-manager stores the TLS certificate. You set the glooUi.tls.secretName in a later step in this guide.
    renewBeforeSpecifies when you want to start the renewal of the TLS certificate in Go time.Duration format.
    durationSpecifies how long the certificate is valid for in Go time.Duration format.
    dnsNamesSpecifies the domain name for the Gloo UI that is set as the common name and the Subject Alternative Names (SANs) in the certificate.
  7. Wait for the TLS certificate to be issued by using the cmctl CLI.

    1. Use the cmctl CLI to view the status of the certificate resource and to note the Serial Number that was assigned to the certificate. If you did not install the cmctl CLI, you can skip this step.

        cmctl status certificate gloo-ui-tls-certificate -n gloo-mesh
        

      Example output:

        Name: gloo-ui-tls-certificate
      Namespace: gloo-mesh
      Conditions:
        Ready: True, Reason: Ready, Message: Certificate is up to date and has not expired
      DNS Names:
      - glooui..
      Secret:
        Name: gloo-ui-tls
        Issuer Country: US
        Issuer Organisation: Let's Encrypt
        Issuer Common Name: R3
        Key Usage: Digital Signature, Key Encipherment
        Extended Key Usages: Server Authentication, Client Authentication
        Public Key Algorithm: RSA
        Signature Algorithm: SHA256-RSA
        Subject Key ID: 4e5ab24ce36969c2dd72f6091b35a1bf5714a0d2
        Authority Key ID: 142eb317b75856cbae500940e61faf9d8b14c2c6
        Serial Number: 049c80e9fd69b183346f76d6b56729edb12c
        Events:  <none>
      Not Before: 2023-12-03T18:59:48+13:00
      Not After: 2024-03-02T18:59:47+13:00
      Renewal Time: 2024-02-16T18:59:47+13:00
      ...
        
    2. Verify that the gloo-ui-tls Kubernetes secret is created in your cluster. If you noted the serial number of the certificate in the previous step, verify that this number is the same as the serial number of the certificate that was added to the gloo-ui-tls Kubernetes secret.

        kubectl -n gloo-mesh get secret gloo-ui-tls
      kubectl -n gloo-mesh get secret gloo-ui-tls -o jsonpath={'.data.tls\.crt'}  | base64 -d | openssl x509 -noout -text
        
  8. Get your current installation Helm values, and save them in a file.

  9. Add the following values to your Helm values file to expose the Gloo UI.

      
    glooUi:
      serviceType: LoadBalancer
      serviceOverrides:
        metadata:
          annotations:
            # The AWS load balancer scheme. In this example, a public facing load balancer is used. 
            service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
            # The AWS load balancer type. Recommended mode: external
            service.beta.kubernetes.io/aws-load-balancer-type: external
            # The AWS load balancer IP address type. In this example, IPv4 is used.
            service.beta.kubernetes.io/aws-load-balancer-ip-address-type: ipv4
            # The target type that AWS uses to route traffic. In this example, traffic is directly routed to the pod IP address.
            service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
            # The protocol to use when connecting from the AWS load balancer to the backend service. In this case, you want to send HTTPS traffic to the Gloo UI.
            service.beta.kubernetes.io/aws-load-balancer-backend-protocol: ssl
            # Automate the DNS management with external-dns.
            external-dns.alpha.kubernetes.io/hostname: glooui.${DOMAIN_NAME}
        spec:
          # Override the `ports` in the Kubernetes service to expose the UI on port `443`.
          # Otherwise, the service is exposed on port `8090` by default.
          ports:
            - name: console
              port: 443
              protocol: TCP
              targetPort: 8090
      tls:
        # The TLS credentials to configure the Gloo UI for HTTPS traffic.
        enabled: true
        certDir: /etc/tls-certs
        certificate: tls.crt
        privateKey: tls.key
        secretName: "gloo-ui-tls"
      

    Review the following table to understand this configuration. For more information, see the Helm reference docs.

    SettingDescription
    glooUi.tls.enabledEnable TLS termination for the Gloo UI. The default value is false.
    glooUi.tls.certDirThe directory in the Kubernetes volume that is attached to the Gloo UI where the TLS certificate and private key are stored. The default value is /etc/tls-certs.
    glooUi.tls.certificateThe file name and file extension for the TLS certificate. The default value is tls.crt.
    glooUi.tls.privateKeyThe file name and extension for the TLS private key. The default value is tls.key.
    glooUi.tls.secretNameThe name of the Kubernetes secret where the TLS certificate and private key are stored. This value must match the secretName that you used in the cert-manager Certificate resource.
  10. Upgrade your Gloo Network installation.

  11. Verify that the Kubernetes volume is added to the Gloo UI and that the TLS directory is successfully created with the certificate and private key.

      kubectl -n gloo-mesh exec deploy/gloo-mesh-ui -c envoy -- ls /etc/tls-certs
      

    Example output:

      tls.crt
    tls.key
      
  12. From the web browser, enter the domain name that you chose for the Gloo UI, such as https://glooui.example.com, and verify that the certificate that the Gloo UI presents is trusted in the browser.