ELB application and network load balancers should only use SSL or HTTPS listeners
Load balancers sit at the boundary between clients and your internal services. An HTTP or plain TCP listener exposes every request, including authentication tokens, session cookies, and API payloads, to interception anywhere along the network path. TLS termination at the load balancer with an ACM certificate gives you automated renewal, removes the manual certificate management overhead, and ensures client traffic is encrypted by default.
Misconfigured listeners are common in development environments that get promoted to production without a security pass. A single unencrypted listener on a public-facing ALB can result in credential theft or regulatory penalties.
Retrofit consideration
Existing HTTP listeners require redirect actions to HTTPS, new ACM certificates, and DNS validation records before the old listeners can be removed. Clients hardcoded to HTTP endpoints may break if redirects are not configured alongside the protocol change.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "alb" {
source = "pcidss.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "hipaa.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "nist80053.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "nistcsf.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "fedrampmoderate.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "nist800171.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "cisacyberessentials.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "nydfs23.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "ffiec.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "eugmpannex11.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "cfrpart11.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "rbicybersecurity.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "rbiitfnbfc.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "nistcsfv11.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
module "alb" {
source = "pcidssv321.compliance.tf/terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
If you use terraform-aws-modules/alb/aws, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "alb" {
source = "terraform-aws-modules/alb/aws"
version = ">=10.0.0,<11.0.0"
access_logs = {
bucket = "example-bucket-abc123"
enabled = true
}
internal = true
listeners = {
https = {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
forward = {
target_group_key = "default"
}
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
}
load_balancer_type = "application"
name = "abc123"
security_groups = ["sg-abc12345"]
subnets = ["subnet-abc123", "subnet-def456"]
target_groups = {
default = {
create_attachment = false
name_prefix = "def-"
port = 443
protocol = "HTTPS"
target_type = "ip"
}
}
vpc_id = "vpc-12345678"
}
Use AWS provider resources directly. See docs for the resources involved: aws_lb_listener.
resource "aws_lb_listener" "this" {
certificate_arn = "arn:aws:acm:us-east-1:123456789012:certificate/12345678-1234-1234-1234-123456789012"
default_action {
fixed_response {
content_type = "text/plain"
message_body = "OK"
status_code = "200"
}
type = "fixed-response"
}
load_balancer_arn = "arn:aws:elasticloadbalancing:us-east-1:123456789012:loadbalancer/net/example/1234567890123456"
port = 443
protocol = "HTTPS"
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
}
What this control checks
This control checks every aws_lb_listener resource on an ALB (load_balancer_type = "application") or NLB (load_balancer_type = "network"). For ALB listeners, protocol must be "HTTPS" (port 443 by convention). For NLB listeners, protocol must be "TLS". In both cases, certificate_arn must reference a valid ACM certificate ARN, not an IAM server certificate. Listeners with protocol = "HTTP" or protocol = "TCP" serving application traffic directly will fail. Additional certificates attached via aws_lb_listener_certificate are acceptable, but the primary certificate_arn on the listener itself must be present and point to ACM.
Common pitfalls
HTTP listeners without redirect actions flagged as failures
An HTTP listener on port 80 only passes this control if its
default_actionspecifiestype = "redirect"withredirect { protocol = "HTTPS" }. Without that redirect block, the policy engine treats it as serving unencrypted traffic and fails it. The redirect must be explicit in the Terraform resource, not assumed from downstream behavior.IAM server certificates do not satisfy ACM requirement
certificate_arnpointing to an IAM-uploaded cert (arn:aws:iam::...) fails this control regardless of whether the certificate itself is valid. The ARN must come from ACM (arn:aws:acm::...). Migrate toaws_acm_certificatewith DNS validation to get automated renewal at the same time.Deprecated aws_alb alias can obscure listener review
If your configuration still uses
aws_alb(a deprecated alias ofaws_lb), audits targetingaws_lb_listenerresources should confirm they are reviewing the right type. The listener protocol andcertificate_arnlive onaws_lb_listenerresources regardless of which load balancer alias appears in your config. Don't let the alias be a reason listener resources get skipped during review.NLB TCP passthrough mistaken for TLS
NLB TCP passthrough is a common source of confusion.
protocol = "TCP"means the load balancer forwards bytes without inspecting or terminating TLS. Even if the backend terminates TLS itself, this control fails because the NLB listener must carryprotocol = "TLS"with acertificate_arnfor the load balancer to validate the certificate.
Audit evidence
Config evaluation results showing all ALB and NLB listener resources as COMPLIANT are the primary evidence artifact. Console screenshots of each listener's configuration tab, showing the HTTPS or TLS protocol and the associated ACM certificate ARN, provide direct confirmation. CloudTrail CreateListener and ModifyListener events establish that listeners were created with encrypted protocols and that no subsequent modification downgraded them to HTTP or TCP.
Security Hub findings mapped to this control should show PASSED across all accounts and regions where load balancers are deployed.
Framework-specific interpretation
PCI DSS v4.0: For merchants and service providers handling cardholder data, Requirement 4.2.1 is explicit: strong cryptography on all transmissions over open, public networks. Load balancers fronting payment services must terminate TLS with trusted certificates, and ACM certificates from a publicly trusted CA satisfy the non-expired, valid-certificate condition that assessors check.
HIPAA Omnibus Rule 2013: 45 CFR 164.312(e)(1) requires a mechanism to guard against unauthorized access to ePHI during transmission. Any load balancer routing health-related traffic is in scope. TLS termination with an ACM certificate at the ALB or NLB boundary covers the encryption piece of that requirement, keeping ePHI out of cleartext on the wire.
NIST SP 800-53 Rev 5: SC-8(1) calls for cryptographic mechanisms that prevent both unauthorized disclosure and undetected modification of data in transit, not just channel encryption. ACM-managed certificates with automated renewal satisfy the trusted-certificate requirement, and this control confirms SC-8 and its (1) enhancement are addressed at the listener level.
NIST Cybersecurity Framework v2.0: PR.DS covers data security under the Protect function. Enforcing TLS or HTTPS on every listener is one straightforward way to satisfy the data-in-transit protection objective for load balancer traffic.
FedRAMP Moderate Baseline Rev 4: SC-8 and SC-23 together cover transmission confidentiality, integrity, and session authenticity for federal systems. At the Moderate baseline, every load balancer listener serving federal information needs TLS termination with a trusted certificate. ACM handles the certificate lifecycle; the listener configuration is where you prove it is applied.
Related controls
ELB application and classic load balancer logging should be enabled
CloudFront distributions should have a default root object configured
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
elb_application_network_lb_use_ssl_certificateAWS Config Managed Rules:
ELBV2_ACM_CERTIFICATE_REQUIRED,ELBV2_LISTENER_ENCRYPTION_IN_TRANSITCheckov Check:
CKV_AWS_127Powerpipe Control:
aws_compliance.control.elb_application_network_lb_use_ssl_certificateProwler Check:
elb_ssl_listeners_use_acm_certificateAWS Security Hub Control:
ELB.18
Last reviewed: 2026-03-09