Skip to main content

Ensure No EC2 Instances Allow Ingress from the Internet to LDAP Ports

Overview

This check identifies EC2 instances that have LDAP (Lightweight Directory Access Protocol) ports accessible from the internet through their security group rules. LDAP uses two main TCP ports:

PortPurpose
389LDAP standard port (unencrypted)
636LDAPS secure port (TLS encrypted)

When these ports are open to 0.0.0.0/0 (all IPv4) or ::/0 (all IPv6), anyone on the internet can attempt to connect to your LDAP directory server.

Risk

Exposing LDAP ports to the internet creates serious security risks:

  • Directory enumeration: Attackers can query user accounts, groups, and organizational structure
  • Credential theft: Password spraying attacks and credential harvesting, especially on unencrypted port 389
  • Data exfiltration: Sensitive directory data (emails, phone numbers, organizational hierarchy) can be stolen
  • Unauthorized access: Anonymous binds may allow unauthenticated queries depending on configuration
  • Privilege escalation: Compromised accounts can be used to access other systems that rely on LDAP authentication
  • Denial of service: Account lockout attacks can disable legitimate users

This is rated as critical severity because directory services contain sensitive identity information and should never be directly accessible from the internet.

Remediation Steps

Prerequisites

You need:

  • Access to the AWS Console with permissions to modify EC2 security groups
  • Knowledge of which IP addresses or CIDR ranges legitimately need LDAP access
Required IAM permissions

To modify security groups, your IAM user or role needs these permissions:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ec2:DescribeSecurityGroups",
"ec2:DescribeSecurityGroupRules",
"ec2:RevokeSecurityGroupIngress",
"ec2:AuthorizeSecurityGroupIngress"
],
"Resource": "*"
}
]
}

AWS Console Method

  1. Sign in to the AWS Console and go to EC2
  2. In the left navigation, click Instances
  3. Select the flagged EC2 instance
  4. Click the Security tab at the bottom of the page
  5. Under Security groups, click on the security group link
  6. Select the Inbound rules tab
  7. Click Edit inbound rules
  8. Find any rules that:
    • Have Source set to 0.0.0.0/0 or ::/0
    • Allow ports 389 or 636
  9. For each problematic rule, either:
    • Delete it by clicking the Delete button on that row
    • Restrict it by changing the Source to a specific IP or CIDR (e.g., 10.0.0.0/8)
  10. Click Save rules

Important: Before removing rules, confirm that no legitimate users or applications rely on internet access to these ports. Consider using a VPN, AWS PrivateLink, or bastion host for remote access instead.

AWS CLI method

First, identify the security group and problematic rules:

# Find security groups with LDAP ports open to the internet
aws ec2 describe-security-groups \
--region us-east-1 \
--filters "Name=ip-permission.cidr,Values=0.0.0.0/0" \
--query "SecurityGroups[?IpPermissions[?contains([`389`,`636`], to_string(FromPort))]].{GroupId:GroupId,GroupName:GroupName}" \
--output table

Remove the unrestricted rules for each LDAP port:

# Replace <SECURITY_GROUP_ID> with your actual security group ID

# Remove unrestricted access to port 389 (LDAP)
aws ec2 revoke-security-group-ingress \
--region us-east-1 \
--group-id <SECURITY_GROUP_ID> \
--protocol tcp \
--port 389 \
--cidr 0.0.0.0/0

# Remove unrestricted access to port 636 (LDAPS)
aws ec2 revoke-security-group-ingress \
--region us-east-1 \
--group-id <SECURITY_GROUP_ID> \
--protocol tcp \
--port 636 \
--cidr 0.0.0.0/0

If you also have IPv6 rules to remove:

# Remove unrestricted IPv6 access to port 389 (LDAP)
aws ec2 revoke-security-group-ingress \
--region us-east-1 \
--group-id <SECURITY_GROUP_ID> \
--ip-permissions IpProtocol=tcp,FromPort=389,ToPort=389,Ipv6Ranges='[{CidrIpv6=::/0}]'

# Remove unrestricted IPv6 access to port 636 (LDAPS)
aws ec2 revoke-security-group-ingress \
--region us-east-1 \
--group-id <SECURITY_GROUP_ID> \
--ip-permissions IpProtocol=tcp,FromPort=636,ToPort=636,Ipv6Ranges='[{CidrIpv6=::/0}]'

To add restricted access for trusted networks:

# Add access from a trusted CIDR (e.g., your VPC CIDR)
aws ec2 authorize-security-group-ingress \
--region us-east-1 \
--group-id <SECURITY_GROUP_ID> \
--protocol tcp \
--port 636 \
--cidr 10.0.0.0/8
CloudFormation template

This template creates a security group with LDAP ports restricted to trusted CIDR blocks:

AWSTemplateFormatVersion: '2010-09-09'
Description: Secure EC2 Security Group - LDAP ports restricted

Parameters:
VpcId:
Type: AWS::EC2::VPC::Id
Description: VPC where the security group will be created
TrustedCidr:
Type: String
Description: Trusted CIDR block for LDAP access
Default: 10.0.0.0/8

Resources:
LdapSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Security group for LDAP with restricted access
VpcId: !Ref VpcId
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 389
ToPort: 389
CidrIp: !Ref TrustedCidr
Description: LDAP standard port (unencrypted)
- IpProtocol: tcp
FromPort: 636
ToPort: 636
CidrIp: !Ref TrustedCidr
Description: LDAPS secure port (TLS encrypted)
Tags:
- Key: Name
Value: ldap-restricted-sg

Outputs:
SecurityGroupId:
Description: ID of the LDAP security group
Value: !Ref LdapSecurityGroup

Deploy the template:

aws cloudformation deploy \
--region us-east-1 \
--template-file ldap-sg.yaml \
--stack-name ldap-security-group \
--parameter-overrides VpcId=<YOUR_VPC_ID> TrustedCidr=10.0.0.0/8
Terraform configuration
terraform {
required_version = ">= 1.0.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 4.0.0"
}
}
}

variable "vpc_id" {
description = "VPC ID where the security group will be created"
type = string
}

variable "trusted_cidr_blocks" {
description = "List of trusted CIDR blocks for LDAP access"
type = list(string)
default = ["10.0.0.0/8"]
}

resource "aws_security_group" "ldap" {
name = "ldap-restricted-sg"
description = "Security group for LDAP with restricted access"
vpc_id = var.vpc_id

# LDAP standard port
ingress {
from_port = 389
to_port = 389
protocol = "tcp"
cidr_blocks = var.trusted_cidr_blocks
description = "LDAP standard port (unencrypted)"
}

# LDAPS secure port
ingress {
from_port = 636
to_port = 636
protocol = "tcp"
cidr_blocks = var.trusted_cidr_blocks
description = "LDAPS secure port (TLS encrypted)"
}

egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow all outbound traffic"
}

tags = {
Name = "ldap-restricted-sg"
}
}

output "security_group_id" {
description = "ID of the LDAP security group"
value = aws_security_group.ldap.id
}

Verification

After making changes, verify the fix:

  1. Go to EC2 > Security Groups in the AWS Console
  2. Select your security group and check the Inbound rules tab
  3. Confirm no rules allow 0.0.0.0/0 or ::/0 on ports 389 or 636
CLI verification commands

Check that no LDAP ports are open to the internet:

# This should return empty results if properly remediated
aws ec2 describe-security-groups \
--region us-east-1 \
--group-ids <SECURITY_GROUP_ID> \
--query "SecurityGroups[].IpPermissions[?contains([`389`,`636`], to_string(FromPort)) && contains(IpRanges[].CidrIp, '0.0.0.0/0')]" \
--output json

Re-run the Prowler check to confirm remediation:

prowler aws --checks ec2_instance_port_ldap_exposed_to_internet --region us-east-1

Additional Resources

Notes

  • Service interruption: Removing security group rules takes effect immediately. Ensure applications and users have alternative access methods before making changes.
  • Multiple security groups: An EC2 instance can have multiple security groups attached. Check all of them for exposed LDAP ports.
  • IPv6 considerations: Remember to check for both IPv4 (0.0.0.0/0) and IPv6 (::/0) unrestricted access.
  • Use LDAPS: If you must allow LDAP access, prefer port 636 (LDAPS) over port 389 to ensure traffic is encrypted.
  • Network ACLs: Security groups are stateful, but Network ACLs are stateless. Consider adding NACL rules as an additional layer of defense.
  • Alternative access methods: For remote LDAP access, consider using AWS Systems Manager Session Manager, a bastion host, AWS Client VPN, or AWS Directory Service with AWS PrivateLink instead of exposing ports to the internet.

Compliance Mapping

This check supports compliance with:

  • SOC 2 - CC6.1, CC6.6 (Logical and Physical Access Controls)
  • ISO 27001 - A.13.1.1 (Network Controls)
  • C5 - OPS-02 (Operational Security)
  • KISA-ISMS-P - Network Security
  • NIS2 - Article 21 (Cybersecurity Risk Management)