This check flags any AWS Classic Load Balancer that has no SSL or TLS listener, meaning traffic to it may travel unencrypted over HTTP or raw TCP. Add an HTTPS or SSL listener backed by an ACM certificate so client traffic is encrypted in transit.
Encryption in transit is one of those controls that everyone agrees on in principle and forgets in practice. A Classic Load Balancer (CLB) that serves traffic over plain HTTP or unencrypted TCP exposes every request, response, cookie, and credential to anyone positioned between the client and your infrastructure. The lb_nossl check looks at each Classic Load Balancer in your account and reports the ones that have no SSL or TLS listener configured at all.
This post walks through what the check evaluates, why an unencrypted load balancer is a real problem and not just a compliance checkbox, and how to fix and prevent it.
What this check detects
The lb_nossl check inspects the listeners on every Classic Load Balancer in the target region. A CLB listener defines a protocol and port on the front end (the part facing clients) and a protocol and port on the back end (the part facing your instances). The valid front-end protocols are HTTP, HTTPS, TCP, and SSL.
The check fails when a load balancer has zero listeners using HTTPS or SSL. In other words, every listener on the load balancer is plain HTTP or raw TCP, so no certificate is presented and nothing is encrypted at the load balancer edge.
Note: The Classic Load Balancer is the first-generation AWS Elastic Load Balancer. AWS now steers new deployments toward the Application Load Balancer (ALB) and Network Load Balancer (NLB). If you are still running CLBs, this check is a good prompt to both fix the encryption gap and plan a migration.
What a passing configuration looks like
A load balancer passes when at least one listener terminates TLS. For a web application that usually means an HTTPS listener on port 443 with an ACM certificate attached. For non-HTTP protocols it means an SSL listener on the relevant port.
Why it matters
An unencrypted load balancer is not a theoretical risk. Here is what actually goes wrong.
Credentials and session tokens travel in cleartext
If your app handles logins, API keys, or session cookies over HTTP, every one of those values is readable by anything on the network path. That includes compromised routers, malicious WiFi access points, ISP-level interception, and an attacker who has gained a foothold inside your VPC. Stealing a valid session cookie is often enough to impersonate a user with no password required.
Man-in-the-middle and content injection
Without TLS there is no way for a client to verify it is talking to your server. An attacker on the path can not only read traffic but also modify it, injecting malicious JavaScript into pages or rewriting API responses. This is the classic coffee-shop attack, and it works against any HTTP endpoint.
Warning: Even traffic that stays "inside" AWS is not automatically safe. Internal VPC traffic can still be observed by a compromised instance, a misconfigured VPC peering connection, or a malicious actor with network access. Encrypt internal and external traffic alike.
Compliance and browser pressure
PCI DSS, HIPAA, SOC 2, and most other frameworks require encryption of data in transit. An HTTP-only load balancer is a finding waiting to happen during an audit. On top of that, modern browsers flag HTTP pages as "Not Secure," block mixed content, and increasingly refuse features like geolocation and service workers on insecure origins.
SEO and trust
Search engines down-rank HTTP-only sites, and users notice the warnings. The business cost of an unencrypted endpoint is not limited to security teams.
How to fix it
The fix is to add an SSL or HTTPS listener backed by a certificate. The cleanest path is to request a free certificate from AWS Certificate Manager (ACM) and attach it to the load balancer.
Step 1: Request or import a certificate in ACM
Request a public certificate for your domain. ACM handles validation and renewal automatically.
aws acm request-certificate \
--domain-name app.example.com \
--validation-method DNS \
--region us-east-1
This returns a certificate ARN. Complete the DNS validation by adding the CNAME record ACM provides (if your domain is in Route 53, you can do this with a single click in the console or with the aws acm resource record output). Once the certificate status is ISSUED, it is ready to use.
Step 2: Add an HTTPS listener to the Classic Load Balancer
Create a new listener that maps front-end HTTPS:443 to your back-end instances and attaches the ACM certificate.
aws elb create-load-balancer-listeners \
--load-balancer-name my-classic-lb \
--listeners "Protocol=HTTPS,LoadBalancerPort=443,InstanceProtocol=HTTP,InstancePort=80,SSLCertificateId=arn:aws:acm:us-east-1:111122223333:certificate/abc-123"
Here the load balancer terminates TLS on 443 and forwards plain HTTP to instances on port 80. That keeps the external connection encrypted. If you want encryption all the way to the instances, set InstanceProtocol=HTTPS and have your instances listen with their own certificate.
Step 3: Apply a modern SSL policy
The default predefined policy can include older protocols. Set a current security policy so you do not negotiate TLS 1.0 or weak ciphers.
aws elb set-load-balancer-policies-of-listener \
--load-balancer-name my-classic-lb \
--load-balancer-port 443 \
--policy-names ELBSecurityPolicy-TLS-1-2-2017-01
Step 4: Redirect or remove the plain HTTP listener
Adding HTTPS does not stop clients from using HTTP. The Classic Load Balancer cannot perform an HTTP-to-HTTPS redirect on its own, so you have two options:
- Handle the redirect at the application layer (return a 301 to the HTTPS URL).
- Migrate to an Application Load Balancer, which supports native redirect rules.
Danger: Do not delete the existing HTTP listener until you have confirmed clients are reaching the new HTTPS listener and your DNS, security groups, and health checks all work. Removing the only working listener can take the application offline.
When you are ready to remove the plain listener:
aws elb delete-load-balancer-listeners \
--load-balancer-name my-classic-lb \
--load-balancer-ports 80
Fixing it with Terraform
If you manage infrastructure as code, define the HTTPS listener directly so the configuration is the source of truth.
resource "aws_elb" "web" {
name = "my-classic-lb"
availability_zones = ["us-east-1a", "us-east-1b"]
listener {
instance_port = 80
instance_protocol = "http"
lb_port = 443
lb_protocol = "https"
ssl_certificate_id = aws_acm_certificate.web.arn
}
health_check {
target = "HTTP:80/health"
interval = 30
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 5
}
}
Tip: If you are touching this load balancer anyway, this is the right moment to migrate to an Application Load Balancer. ALBs give you native HTTP-to-HTTPS redirects, SNI for multiple certificates, host and path routing, and better integration with WAF. The CLB is supported but increasingly a legacy choice.
How to prevent it from happening again
Fixing one load balancer is easy. Making sure the next one is never created without TLS takes a bit of automation.
Gate it in CI/CD with policy-as-code
If you provision load balancers through Terraform, run a policy check before apply. Here is a Checkov-style example using a custom policy, but the same idea works with OPA or Sentinel: fail the pipeline when an aws_elb has no HTTPS listener.
# Run Checkov against your Terraform plan in CI
checkov -d ./infra --framework terraform \
--check CKV_AWS_3,CKV_AWS_213
With OPA and Conftest you can write an explicit rule:
package main
deny[msg] {
resource := input.resource.aws_elb[name]
listeners := resource.listener
not has_https(listeners)
msg := sprintf("ELB '%s' has no HTTPS or SSL listener", [name])
}
has_https(listeners) {
listeners[_].lb_protocol == "https"
}
Detect drift continuously
Policy-as-code catches new resources, but it does not catch a load balancer someone created by hand in the console. Continuous scanning fills that gap. Lensix runs the lb_nossl check across your accounts on a schedule and alerts you when an unencrypted CLB appears, so a manual change does not sit undetected for months.
Tip: Pair the CI gate with continuous scanning. The gate stops bad config from being merged, and the scanner catches anything created outside the pipeline. Together they close both doors.
Use AWS Config for native rules
If you want an AWS-native guardrail, the managed Config rule elb-tls-https-listeners-only evaluates whether your Classic Load Balancers use only HTTPS or SSL listeners and reports non-compliant ones in your dashboard.
Best practices
- Encrypt every listener, not just the internet-facing one. Internal load balancers carry sensitive data too. Apply the same TLS standard everywhere.
- Use ACM certificates. They are free for use with ELB, and ACM renews them automatically, which eliminates the classic outage of an expired certificate.
- Pin a modern security policy. Disable TLS 1.0 and 1.1 and weak cipher suites. Prefer
ELBSecurityPolicy-TLS-1-2-2017-01or newer. - Redirect HTTP to HTTPS. An open HTTP listener that does not redirect is an invitation for clients to send their first request in cleartext.
- Consider end-to-end encryption. Terminating TLS at the load balancer protects the public hop. For regulated workloads, re-encrypt to the back end so traffic inside the VPC is encrypted too.
- Plan a migration off Classic Load Balancers. ALB and NLB offer better TLS handling, more routing options, and tighter integration with the rest of the AWS security stack.
Encryption in transit is cheap to add and expensive to skip. A single HTTPS listener with an ACM certificate turns an exposed endpoint into a properly protected one, and a CI gate plus continuous scanning keeps it that way as your environment grows.

