> ## Documentation Index
> Fetch the complete documentation index at: https://cloudanix.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Encrypt Traffic To HTTPS Load Balancers With TLS Certificates

### More Info:

Terminate load balancer traffic over HTTPS using TLS certificates so data in transit to and from the cluster is encrypted.

### Risk Level

Medium

### Address

Security

### Compliance Standards

* CIS AKS

### Triage and Remediation

<Tabs>
  <Tab title="Remediation">
    ### Remediation

    <AccordionGroup>
      <Accordion title="Manual Steps" defaultOpen="true">
        1. **Inventory all AKS-facing load balancers and ingresses**
           * On any machine with Azure CLI access:
             ```bash theme={null}
             az aks list -o table
             ```
             For each cluster:
             ```bash theme={null}
             # Get resource group and node RG
             az aks show -n <AKS_CLUSTER_NAME> -g <AKS_RG> \
               --query "{nodeResourceGroup:nodeResourceGroup}" -o tsv

             # List public IPs and load balancers in node RG
             az network public-ip list -g <NODE_RESOURCE_GROUP> -o table
             az network lb list -g <NODE_RESOURCE_GROUP> -o table
             ```
             If using an ingress controller, review its Service and Ingress definitions via IaC or repo to identify all external entrypoints.

        2. **Confirm only HTTPS (TCP/443) is exposed externally**
           * For each public IP used by a load balancer/ingress:
             ```bash theme={null}
             az network lb show -g <NODE_RESOURCE_GROUP> -n <LB_NAME> \
               --query "frontendIpConfigurations[].inboundNatRules"
             az network lb rule list -g <NODE_RESOURCE_GROUP> --lb-name <LB_NAME> -o table
             ```
           * Verify that:
             * Frontend rules expose port 443 (or custom TLS ports) to clients.
             * Port 80 (HTTP) is either disabled externally or only used for internal HTTP→HTTPS redirects at the application/ingress level.

        3. **Verify TLS termination and certificate configuration**
           * If using an Azure Application Gateway / AGIC:
             ```bash theme={null}
             az network application-gateway list -o table
             az network application-gateway show -g <APPGW_RG> -n <APPGW_NAME> \
               --query "{frontendPorts:frontendPorts, httpsListeners:sslCertificates}" -o json
             ```
             Ensure HTTPS listeners are configured and mapped to the relevant frontend IPs, and HTTP listeners are either disabled or only used for redirects.
           * If using a cloud load balancer with TLS passthrough to ingress: check the ingress controller configuration (Helm values, Terraform, etc.) to confirm TLS termination is enabled and bound to the HTTPS listener.

        4. **Review TLS certificate sources, validity, and key management**
           * For certificates stored in Azure Key Vault:
             ```bash theme={null}
             az keyvault certificate list --vault-name <KEYVAULT_NAME> -o table
             az keyvault certificate show --vault-name <KEYVAULT_NAME> -n <CERT_NAME> \
               --query "{name:name, enabled:attributes.enabled, \
               notBefore:attributes.notBefore, expires:attributes.expires}" -o json
             ```
           * Confirm:
             * Certificates are valid (not expired, correct CN/SAN for hostnames).
             * Private keys are protected (Key Vault or secure secret store).
             * Automated renewal and reload are configured where possible.

        5. **Harden TLS policy and disable weak protocols/ciphers**
           * For Application Gateway:
             ```bash theme={null}
             az network application-gateway show -g <APPGW_RG> -n <APPGW_NAME> \
               --query "sslPolicy" -o json
             ```
           * Decide whether to:
             * Use a predefined strong policy (e.g., `AppGwSslPolicy20170401S`) or
             * A custom policy that disables TLS 1.0/1.1 and weak ciphers.
           * Update via console or IaC to enforce the chosen policy across all HTTPS listeners.

        6. **Document and, if necessary, implement corrections via console/CLI/IaC; then re-verify**
           * Apply required changes in your chosen IaC (ARM/Bicep/Terraform) or Azure portal:
             * Ensure all external listeners use HTTPS with valid certificates.
             * Remove or redirect plain HTTP endpoints.
             * Align all entrypoints with the selected TLS policy.
           * Re-run the evidence-gathering commands from steps 2–5 to confirm that:
             * Only HTTPS endpoints are exposed externally.
             * Certificates and TLS policies match your security requirements.
      </Accordion>

      <Accordion title="Using kubectl">
        kubectl cannot configure HTTPS load balancer TLS termination, because this setting is managed in your cloud provider’s load balancer and/or IaC configuration, not via Kubernetes API objects. Make the necessary changes in your cloud console/CLI or IaC definitions, and refer to the Manual Steps section for detailed guidance.
      </Accordion>

      <Accordion title="Automation">
        ```bash theme={null}
        #!/usr/bin/env bash
        # Report Kubernetes Services exposed via cloud load balancers and whether they
        # are configured to use HTTPS/TLS on the external interface.
        #
        # Run on: any machine with kubectl access and correct context.
        # Requires: kubectl, jq

        set -euo pipefail

        # Confirm kubectl works
        kubectl version --short >/dev/null

        echo "Collecting LoadBalancer Services and ingress-related annotations..."
        echo

        # Header
        printf "%-30s %-20s %-20s %-10s %-60s\n" \
          "NAMESPACE/NAME" "TYPE" "EXTERNAL_IP/INGRESS" "PORTS" "TLS / HTTPS INDICATORS"
        echo "------------------------------------------------------------------------------------------------------------------------------------------"

        # 1) Services of type LoadBalancer
        kubectl get svc --all-namespaces -o json | jq -r '
          .items[] |
          select(.spec.type == "LoadBalancer") |
          # Basic info
          . as $svc |
          (
            (.metadata.namespace + "/" + .metadata.name) as $id |
            "Service " + $id,
            (.status.loadBalancer.ingress // [] | map(.ip // .hostname) | join(",")) as $ing,
            (.spec.ports // [] | map((.port|tostring)+"/"+(.protocol//"")) | join(",")) as $ports,
            # Heuristics for HTTPS/TLS:
            # - Any port 443 or named "https"
            # - Common cloud-controller annotations showing HTTPS listeners or certificates
            (
              [
                (if any(.spec.ports[]?; .port==443 or .name=="https") then "PORT_443_OR_HTTPS" else empty end),
                (.metadata.annotations["service.beta.kubernetes.io/aws-load-balancer-ssl-cert"] // empty | select(length>0) | "AWS_SSL_CERT"),
                (.metadata.annotations["service.beta.kubernetes.io/aws-load-balancer-backend-protocol"] // empty | select(test("https|ssl";"i")) | "AWS_BACKEND_HTTPS"),
                (.metadata.annotations["service.beta.kubernetes.io/aws-load-balancer-ssl-ports"] // empty | "AWS_SSL_PORTS=" + .),
                (.metadata.annotations["service.beta.kubernetes.io/azure-load-balancer-internal"] // empty | "AZURE_INTERNAL_LB"),
                (.metadata.annotations["service.beta.kubernetes.io/azure-load-balancer-tls-cert"] // empty | "AZURE_TLS_CERT"),
                (.metadata.annotations["cloud.google.com/app-protocols"] // empty | "GKE_APP_PROTOCOLS=" + .),
                (.metadata.annotations["networking.gke.io/app-protocols"] // empty | "GKE_NET_APP_PROTOCOLS=" + .),
                (.metadata.annotations["networking.gke.io/managed-certificates"] // empty | "GKE_MANAGED_CERTS=" + .),
                (.metadata.annotations["service.beta.kubernetes.io/do-loadbalancer-tls-passthrough"] // empty | "DO_TLS_PASSTHROUGH=" + .),
                (.metadata.annotations["service.beta.kubernetes.io/do-loadbalancer-protocol"] // empty | "DO_LB_PROTOCOL=" + .),
                (.metadata.annotations["service.beta.kubernetes.io/linode-loadbalancer-ssl-ports"] // empty | "LINODE_SSL_PORTS=" + .),
                (.metadata.annotations["service.beta.kubernetes.io/oci-load-balancer-ssl-ports"] // empty | "OCI_SSL_PORTS=" + .)
              ] | unique | join(",")
            ) as $tlsHints |
            # Emit one line
            @tsv "\($id)\tService\t\($ing)\t\($ports)\t\($tlsHints)"
          )
        ' | while IFS=$'\t' read -r id type ing ports tls; do
          printf "%-30s %-20s %-20s %-10s %-60s\n" "$id" "$type" "${ing:-<pending>}" "${ports:--}" "${tls:-<none>}"
        done

        echo
        echo "Collecting Ingresses and TLS usage..."
        echo

        # 2) Ingress resources (may front HTTPS load balancers depending on class/controller)
        kubectl get ingress --all-namespaces -o json 2>/dev/null | jq -r '
          .items[]? |
          . as $ing |
          (
            (.metadata.namespace + "/" + .metadata.name) as $id |
            (.spec.ingressClassName // .metadata.annotations["kubernetes.io/ingress.class"] // "<none>") as $class |
            (.status.loadBalancer.ingress // [] | map(.ip // .hostname) | join(",")) as $addr |
            ((.spec.tls // []) | length | tostring) as $tlsCount |
            (
              [
                (if (.spec.tls // []) | length > 0 then "INGRESS_TLS_SECTIONS="+$tlsCount else empty end),
                (.metadata.annotations["nginx.ingress.kubernetes.io/backend-protocol"] // empty | "NGINX_BACKEND_PROTO=" + .),
                (.metadata.annotations["nginx.ingress.kubernetes.io/ssl-redirect"] // empty | "NGINX_SSL_REDIRECT=" + .),
                (.metadata.annotations["ingress.gcp.kubernetes.io/pre-shared-cert"] // empty | "GCE_PRESHARED_CERT=" + .),
                (.metadata.annotations["networking.gke.io/managed-certificates"] // empty | "GKE_MANAGED_CERTS=" + .),
                (.metadata.annotations["alb.ingress.kubernetes.io/certificate-arn"] // empty | "AWS_ALB_CERT_ARN=" + .),
                (.metadata.annotations["alb.ingress.kubernetes.io/listen-ports"] // empty | "AWS_ALB_LISTEN_PORTS=" + .),
                (.metadata.annotations["azure/application-gateway-cert"] // empty | "AZURE_APPGW_CERT=" + .),
                (.metadata.annotations["konghq.com/protocols"] // empty | "KONG_PROTOCOLS=" + .)
              ] | unique | join(",")
            ) as $tlsHints |
            @tsv "\($id)\tIngress(\($class))\t\($addr)\t-\t\($tlsHints)"
          )
        ' 2>/dev/null | while IFS=$'\t' read -r id type addr ports tls; do
          printf "%-30s %-20s %-20s %-10s %-60s\n" "$id" "$type" "${addr:-<pending>}" "-" "${tls:-<none>}"
        done

        cat <<'EOF'

        How to interpret this report
        ----------------------------

        Each row represents:
        - Service: a Service of type LoadBalancer that will be backed by a cloud load balancer.
        - Ingress: an Ingress that typically provisions an external load balancer through its controller.

        Columns:
        - NAMESPACE/NAME: Resource identifier.
        - TYPE: Service or Ingress(+class).
        - EXTERNAL_IP/INGRESS: External address of the cloud load balancer if assigned.
        - PORTS: Exposed ports (for Services).
        - TLS / HTTPS INDICATORS: Heuristics suggesting HTTPS/TLS is configured.

        Potential problems (to review manually in cloud console / IaC):
        - Service rows where:
          - PORTS only show HTTP ports (e.g., 80/TCP) and
          - TLS / HTTPS INDICATORS is "<none>" or does not mention provider-specific TLS annotations.
        - Ingress rows where:
          - TLS / HTTPS INDICATORS is "<none>" and
          - You expect HTTPS termination at the load balancer for those hosts.

        This script does NOT prove traffic is encrypted:
        - It only highlights where TLS-like config appears present or absent in Kubernetes objects.
        - You must confirm in your cloud provider console, CLI, or IaC:
          - That the external load balancer listeners use HTTPS/TLS.
          - That appropriate certificates are attached.
          - That HTTP (if present) is redirected to HTTPS or otherwise acceptable by your policy.
        EOF
        ```
      </Accordion>
    </AccordionGroup>
  </Tab>
</Tabs>
