Encrypt Traffic To HTTPS Load Balancers With TLS
More Info:
Configure HTTPS with TLS certificates on load balancers to encrypt traffic in transit. Consult your load balancer vendor documentation for configuration details.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS OKE
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
Inventory all externally exposed load balancers
- On an admin workstation with cloud CLI configured, list all LBs that front Kubernetes workloads (adapt provider as needed):
- AWS:
aws elbv2 describe-load-balancers --query 'LoadBalancers[].{Name:LoadBalancerName,DNSName:DNSName,Type:Type,Scheme:Scheme}'
- GCP:
gcloud compute forwarding-rules list --format='table(name,IPAddress,IPProtocol,portRange,target)'
- Azure:
az network lb list --query '[].{Name:name,Frontends:frontendIPConfigurations[].privateIPAddress}'
- AWS:
- Filter to internet-facing endpoints used by this cluster (by name, tags, annotations, or target backends).
- On an admin workstation with cloud CLI configured, list all LBs that front Kubernetes workloads (adapt provider as needed):
-
Verify protocol and ports for each public endpoint
- For each LB DNS name or IP, check if HTTPS (443) is enabled and HTTP (80) is still open:
nmap -Pn -p 80,443 <LB_DNS_or_IP>
- In the cloud console, open each LB and review listeners / rules:
- Confirm at least one HTTPS/TLS listener (usually port 443).
- Note any plaintext HTTP listeners (80 or custom).
- For each LB DNS name or IP, check if HTTPS (443) is enabled and HTTP (80) is still open:
-
Inspect TLS certificate configuration on HTTPS listeners
- In the console for each LB with HTTPS:
- Confirm a certificate is attached to the HTTPS listener.
- Confirm:
- The certificate is not expired and matches the LB hostname / domain.
- A trusted CA was used (or your approved internal CA).
- Strong TLS protocol versions and cipher policies are enforced (per your security baseline).
- If needed, validate from an admin workstation:
openssl s_client -connect <LB_DNS_or_IP>:443 -servername <LB_hostname> -showcerts </dev/null 2>/dev/null | openssl x509 -noout -text | egrep 'Subject:|Issuer:|Not Before:|Not After :'
- In the console for each LB with HTTPS:
-
Decide and implement required HTTPS/TLS configuration changes
- For any internet-facing LB without HTTPS:
- In the cloud console or via IaC, add an HTTPS/TLS listener (e.g., 443) and point it to the same backend target group / pool.
- Attach an existing approved certificate or request/import a new one using the provider’s certificate manager.
- Optionally configure HTTP (80) only to:
- Redirect to HTTPS (preferred), or
- Be disabled entirely if not needed.
- For any internet-facing LB without HTTPS:
-
Update or create TLS certificates as needed
- For endpoints missing valid certificates or using weak / untrusted certs:
- Request or import a compliant certificate via the cloud provider’s certificate manager (e.g., ACM, Google Managed Certs, Azure Key Vault/Certificates).
- Attach the new certificate to the relevant HTTPS listeners.
- Ensure IaC (Terraform, CloudFormation, ARM/Bicep, etc.) is updated to declare:
- HTTPS listeners with certificate ARNs/IDs.
- Any required redirect rules, so future deployments remain compliant.
- For endpoints missing valid certificates or using weak / untrusted certs:
-
Verify enforcement of HTTPS and correct behavior
- From an admin workstation, confirm HTTP is redirected or closed and HTTPS works:
# Expect redirect or failure (no 200 OK over HTTP for sensitive apps)curl -I http://<LB_DNS_or_IP># Expect successful TLS connection and 2xx/3xx responsecurl -I https://<LB_DNS_or_IP>
- Optionally re-run the initial CLI listing and document which LBs:
- Have HTTPS enabled with valid certificates, and
- No longer expose unprotected HTTP endpoints (except where explicitly and formally approved).
- From an admin workstation, confirm HTTP is redirected or closed and HTTPS works:
Using kubectl
kubectl cannot configure TLS on cloud provider or external HTTPS load balancers; that configuration must be done in your cloud provider console/CLI or IaC tooling where the load balancer is defined. Refer to the Manual Steps section for guidance on reviewing and updating your load balancer TLS settings.
Automation
#!/usr/bin/env bash
# Purpose: Report Services using external load balancers that are NOT configured for HTTPS/TLS.
# Scope: Any machine with kubectl access and correct KUBECONFIG.
set -euo pipefail
echo "=== Checking Services of type LoadBalancer for HTTPS/TLS exposure ==="
echo
# 1) List all LoadBalancer Services with their ports and annotations
echo "All LoadBalancer Services and ports:"
kubectl get svc --all-namespaces -o jsonpath='{range .items[?(@.spec.type=="LoadBalancer")]}{.metadata.namespace}{"\t"}{.metadata.name}{"\t"}{.spec.loadBalancerIP}{"\t"}{range .spec.ports}{.port}{"/"}{.protocol}{":"}{.name}{" "}{end}{"\n"}{end}' \
| sed 's/[[:space:]]\+$//'
echo
# 2) Flag Services that:
# - Are type LoadBalancer
# - Expose any port that looks like HTTP (80/8080/8000-8099) AND
# - Do NOT expose a typical HTTPS/TLS port (443/8443) on the same Service
#
# These are *candidates* for unencrypted traffic and require manual review.
echo "Potentially PROBLEMATIC LoadBalancer Services (HTTP-like ports without HTTPS ports):"
echo -e "NAMESPACE\tNAME\tPORTS"
kubectl get svc --all-namespaces -o json | \
jq -r '
.items[]
| select(.spec.type == "LoadBalancer")
| {
ns: .metadata.namespace,
name: .metadata.name,
ports: [.spec.ports[] | {port: .port, name: (.name // ""), protocol: .protocol}]
}
| . as $svc
# Determine if any HTTP-like port exists
| ($svc.ports | map(select(
.protocol == "TCP"
and (
.port == 80
or .port == 8080
or (.port >= 8000 and .port <= 8099)
)
)) | length) as $http_like
# Determine if any HTTPS-like port exists
| ($svc.ports | map(select(
.protocol == "TCP"
and (
.port == 443
or .port == 8443
)
)) | length) as $https_like
# Report only those with HTTP-like ports and no HTTPS-like ports
| select($http_like > 0 and $https_like == 0)
| "\(.ns)\t\(.name)\t" +
($svc.ports | map("\(.port)/\(.protocol)(\(.name))") | join(", "))
' || echo "No candidates found or jq not installed."
echo
# 3) Ingress resources (if using cloud L7 load balancers) – list TLS usage
echo "Ingress resources and TLS configuration:"
echo -e "NAMESPACE\tNAME\tTLS_SECRETS"
kubectl get ingress --all-namespaces -o json 2>/dev/null | \
jq -r '
.items[]
| {
ns: .metadata.namespace,
name: .metadata.name,
tls: ( .spec.tls // [] | map(.secretName) | join(",") )
}
| "\(.ns)\t\(.name)\t\(.tls)"
' || echo "No Ingress resources found or jq not installed."
echo
cat <<'EOF'
INTERPRETING THE OUTPUT
-----------------------
1) "All LoadBalancer Services and ports":
- Review Services and confirm which ones are internet-facing load balancers.
- Any Service exposing HTTP-like ports without TLS termination on the LB is a concern.
2) "Potentially PROBLEMATIC LoadBalancer Services":
- Listed Services expose HTTP-like ports (80/8080/8000–8099) and do NOT expose typical HTTPS ports (443/8443).
- These are strong candidates for unencrypted traffic and must be reviewed:
* Check your cloud provider load balancer configuration (console/CLI/IaC)
to see if TLS is terminated there (HTTPS listener + certificate).
* If TLS is not configured on the load balancer, this is a finding.
3) "Ingress resources and TLS configuration":
- Ingress entries with an empty TLS_SECRETS column are *likely* serving HTTP only.
- For cloud-managed HTTP(S) load balancers, you must verify in the provider console
that HTTPS listeners/certificates are configured even if a TLS secret is present.
This script does NOT automatically fix configuration; it highlights where manual
review of cloud load balancer settings and TLS certificates is required.
EOF