InfraRunBook
    Back to articles

    AWS Security Group Blocking Traffic

    Cloud
    Published: Apr 4, 2026
    Updated: Apr 4, 2026

    AWS Security Groups silently drop blocked traffic with no error message, making misconfigurations notoriously hard to debug. This runbook covers every root cause — wrong ports, bad CIDRs, missing outbound rules, NACL conflicts, and more — with real CLI commands and fix procedures.

    AWS Security Group Blocking Traffic

    Symptoms

    AWS Security Groups act as virtual firewalls for EC2 instances and other VPC resources, controlling inbound and outbound traffic at the elastic network interface (ENI) level. When a Security Group is misconfigured, the result is almost always a silent drop — packets disappear without an ICMP error or TCP RST, leaving engineers staring at connection timeouts rather than actionable error messages.

    Common symptoms of an AWS Security Group blocking traffic include:

    • SSH or RDP sessions hanging indefinitely with no prompt or error
    • curl
      or
      wget
      commands timing out with no response body
    • Application Load Balancer targets marked as unhealthy despite the application running correctly on the instance
    • Database connections from application servers failing with a timeout (not a refused connection)
    • ICMP ping returning no response when testing basic connectivity
    • VPC Flow Logs showing
      REJECT
      action for otherwise expected traffic flows
    • AWS Systems Manager Session Manager succeeding while direct TCP connections on custom ports fail, confirming the instance is running but a port is blocked

    The critical diagnostic distinction: Connection refused means the packet reached the host but no service is listening on that port. Connection timeout means the packet never reached the host, or the return path is blocked. Security Group issues almost always produce timeouts, never refused errors.


    Root Cause 1: Wrong Port in Inbound Rule

    Why It Happens

    This is the single most common Security Group mistake. Engineers remember to open a port but enter the wrong number — for example, opening TCP 8080 when the application actually listens on 8443, or opening port 22 when SSH was moved to port 2222 for hardening purposes. Numeric confusion between similar port numbers is also frequent: 3306 versus 33060 for MySQL versus MySQL X Protocol, or 5432 versus 54320 for PostgreSQL versus a custom service. Even off-by-one errors (8080 vs 8081) are enough to cause complete failure.

    How to Identify It

    First, confirm the port the process is actually listening on. Use AWS Systems Manager Session Manager to access the instance without needing SSH access through the Security Group:

    $ ss -tlnp | grep LISTEN
    LISTEN  0  128  0.0.0.0:2222   0.0.0.0:*  users:(("sshd",pid=1234,fd=3))
    LISTEN  0  128  0.0.0.0:8443   0.0.0.0:*  users:(("java",pid=5678,fd=12))

    Then describe the Security Group inbound rules using the AWS CLI:

    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'SecurityGroups[*].IpPermissions' \
        --output table
    
    ------------------------------------------------------
    |           DescribeSecurityGroups                   |
    +----------+-----------+----------+-----------------+
    | FromPort | IpProtocol| ToPort   | CidrIp          |
    +----------+-----------+----------+-----------------+
    |  22      | tcp       |  22      | 10.0.0.0/16     |
    |  8080    | tcp       |  8080    | 10.0.0.0/16     |
    +----------+-----------+----------+-----------------+

    The Security Group allows port 8080, but the application listens on 8443. All traffic to that service is silently dropped.

    How to Fix It

    Add the correct inbound rule and remove the incorrect one:

    # Add the correct rule
    $ aws ec2 authorize-security-group-ingress \
        --group-id sg-0abc123def456789 \
        --protocol tcp \
        --port 8443 \
        --cidr 10.0.0.0/16
    
    # Remove the wrong rule
    $ aws ec2 revoke-security-group-ingress \
        --group-id sg-0abc123def456789 \
        --protocol tcp \
        --port 8080 \
        --cidr 10.0.0.0/16

    Verify the corrected rules:

    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'SecurityGroups[0].IpPermissions[*].[FromPort,ToPort,IpProtocol,IpRanges[0].CidrIp]' \
        --output table
    
    -------------------------------------
    |  22  |  22  | tcp | 10.0.0.0/16  |
    | 8443 | 8443 | tcp | 10.0.0.0/16  |
    -------------------------------------

    Root Cause 2: Wrong CIDR Block

    Why It Happens

    A Security Group rule may allow the correct port but scope it to the wrong IP range. This happens when the source IP is misidentified — for example, allowing

    10.0.1.0/24
    when traffic arrives from
    10.0.2.50
    in a different subnet. It also occurs when an on-premises IP range changes and the Security Group is never updated, or when engineers copy CIDR blocks from documentation without validating them against the actual network topology. Subnet mask mistakes (using /32 for a host when intending /24 for a subnet) are another frequent variant.

    How to Identify It

    Identify the actual source IP of the failing connection using VPC Flow Logs:

    $ aws logs filter-log-events \
        --log-group-name /aws/vpc/flowlogs \
        --filter-pattern "[version, account, eni, srcaddr=10.0.2.*, dstaddr=10.0.1.50, srcport, dstport=443, protocol=6, packets, bytes, start, end, action=REJECT, status]" \
        --start-time $(date -d '30 minutes ago' +%s000)
    
    {
      "srcaddr": "10.0.2.100",
      "dstaddr": "10.0.1.50",
      "dstport": "443",
      "action": "REJECT"
    }

    Compare the actual source IP against the Security Group inbound rules:

    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'SecurityGroups[0].IpPermissions[?FromPort==`443`]'
    
    [
        {
            "FromPort": 443,
            "IpProtocol": "tcp",
            "IpRanges": [
                {
                    "CidrIp": "10.0.1.0/24"
                }
            ],
            "ToPort": 443
        }
    ]

    The rule allows only

    10.0.1.0/24
    , but traffic arrives from
    10.0.2.100
    — outside the permitted CIDR. The Security Group drops it.

    How to Fix It

    Update the CIDR to cover the correct source range. In this case, the full VPC CIDR

    10.0.0.0/16
    covers all internal subnets:

    # Add the correct broader CIDR
    $ aws ec2 authorize-security-group-ingress \
        --group-id sg-0abc123def456789 \
        --protocol tcp \
        --port 443 \
        --cidr 10.0.0.0/16
    
    # Remove the overly narrow CIDR
    $ aws ec2 revoke-security-group-ingress \
        --group-id sg-0abc123def456789 \
        --protocol tcp \
        --port 443 \
        --cidr 10.0.1.0/24

    Root Cause 3: Missing Outbound Rule

    Why It Happens

    By default, AWS Security Groups allow all outbound traffic (

    0.0.0.0/0
    on all ports and protocols). However, teams that harden their Security Groups by removing this default all-allow egress rule must explicitly define every outbound rule for every destination the instance needs to reach. When a required outbound rule is missing, the instance initiates a connection, but the SYN packet is dropped before it ever leaves the ENI. This is particularly common on EC2 instances acting as clients: worker nodes polling SQS queues, application servers connecting to RDS, and Lambda functions inside a VPC calling external API endpoints.

    How to Identify It

    Inspect the egress rules on the Security Group:

    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'SecurityGroups[*].IpPermissionsEgress' \
        --output json
    
    [
        [
            {
                "IpProtocol": "tcp",
                "FromPort": 443,
                "ToPort": 443,
                "IpRanges": [
                    {
                        "CidrIp": "10.0.3.0/24"
                    }
                ]
            }
        ]
    ]

    The instance needs to reach a PostgreSQL database on port 5432 at

    10.0.4.20
    , but only outbound TCP 443 is permitted. Confirm the block in VPC Flow Logs:

    $ aws logs filter-log-events \
        --log-group-name /aws/vpc/flowlogs \
        --filter-pattern "[version, account, eni, srcaddr=10.0.1.50, dstaddr=10.0.4.20, srcport, dstport=5432, protocol=6, packets, bytes, start, end, action=REJECT, status]"
    
    {
      "srcaddr": "10.0.1.50",
      "dstaddr": "10.0.4.20",
      "dstport": "5432",
      "action": "REJECT"
    }

    How to Fix It

    Add the required outbound rule for PostgreSQL:

    $ aws ec2 authorize-security-group-egress \
        --group-id sg-0abc123def456789 \
        --protocol tcp \
        --port 5432 \
        --cidr 10.0.4.0/24

    If the instance requires broad outbound access and the security posture permits it, restore the default allow-all egress rule:

    $ aws ec2 authorize-security-group-egress \
        --group-id sg-0abc123def456789 \
        --ip-permissions '[{"IpProtocol": "-1", "IpRanges": [{"CidrIp": "0.0.0.0/0"}]}]'

    Root Cause 4: Stateful Rule Misunderstanding

    Why It Happens

    AWS Security Groups are stateful. When an inbound rule permits a connection, the return traffic for that session is automatically allowed — even with no matching outbound rule for the return path. Engineers who have worked extensively with stateless firewalls (raw iptables, pfSense without state tracking, or AWS Network ACLs) frequently misapply stateless mental models to Security Groups.

    This creates two failure patterns:

    • Unnecessary bidirectional rules: An engineer opens port 443 inbound and also adds a matching outbound rule for port 443, believing both are needed. They later delete the outbound rule during a cleanup audit, nothing breaks (because return traffic is stateful), and they incorrectly conclude outbound rules are never needed. They then fail to add a required outbound rule when the instance acts as a client, and the connection times out.
    • Missing client-side outbound rules: An engineer only adds inbound rules for every service, not realizing that when this instance is the client initiating a connection to another host, an outbound rule is absolutely required. The return traffic to the ephemeral port is stateful and auto-permitted — but the initial outbound SYN is not.

    How to Identify It

    Determine whether the instance is acting as a server (accepting connections) or a client (initiating connections) for the failing traffic:

    # Connect via SSM Session Manager and run:
    $ ss -tnp | grep ESTABLISHED
    
    # Server mode (incoming connection — remote is the source):
    ESTAB  0  0  10.0.1.50:443    10.0.2.100:54321  users:(("nginx",pid=902,fd=8))
    
    # Client mode (outgoing connection — local has ephemeral port):
    ESTAB  0  0  10.0.1.50:49823  10.0.4.20:5432    users:(("app",pid=3344,fd=11))

    For client-mode traffic, check whether the relevant outbound rule exists:

    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'SecurityGroups[0].IpPermissionsEgress[?FromPort==`5432`]'
    
    []   # Empty array — no outbound rule exists for port 5432

    How to Fix It

    For server-mode instances that only receive inbound connections: only an inbound rule is needed. The stateful engine automatically permits return traffic. Do not add outbound rules for the same port to match inbound rules — they are redundant.

    For client-mode instances that initiate outbound connections: an outbound rule is required for the destination port. The return traffic arriving on an ephemeral source port is automatically permitted by the stateful engine — you do not need an inbound rule for ephemeral ports (1024–65535) on the client Security Group.

    # Client initiating PostgreSQL connections: add outbound rule ONLY
    $ aws ec2 authorize-security-group-egress \
        --group-id sg-0abc123def456789 \
        --protocol tcp \
        --port 5432 \
        --cidr 10.0.4.0/24
    
    # DO NOT add: inbound allow for ephemeral ports 1024-65535
    # The stateful connection tracker handles return traffic automatically.

    Root Cause 5: NACL Overriding the Security Group

    Why It Happens

    Network Access Control Lists (NACLs) operate at the subnet level and are evaluated independently of Security Groups. For inbound traffic, the NACL is evaluated first, before the Security Group. For outbound traffic, the Security Group is evaluated first, then the NACL. Critically, unlike Security Groups, NACLs are stateless — each direction of every flow must be explicitly permitted, including the return path using ephemeral ports.

    When a NACL has an explicit DENY rule — or simply lacks a required ALLOW rule — it blocks traffic that the Security Group would otherwise permit. Engineers debugging Security Groups often forget NACLs exist entirely, especially because the default NACL for a VPC allows all traffic and most teams never modify it. The problem arises when a custom NACL is created and associated with a subnet. Custom NACLs deny all traffic by default (via the implicit rule 32767 DENY), and any traffic not explicitly permitted is silently dropped regardless of the Security Group configuration.

    How to Identify It

    Find the subnet of the affected instance and locate its associated NACL:

    # Step 1: Get the subnet ID of the instance
    $ aws ec2 describe-instances \
        --instance-ids i-0abc123def456789 \
        --query 'Reservations[0].Instances[0].SubnetId' \
        --output text
    
    subnet-0def456abc789012
    
    # Step 2: Find the NACL associated with that subnet
    $ aws ec2 describe-network-acls \
        --filters "Name=association.subnet-id,Values=subnet-0def456abc789012" \
        --query 'NetworkAcls[0].{NaclId:NetworkAclId,Entries:Entries}' \
        --output json
    
    {
        "NaclId": "acl-0abc123456def789",
        "Entries": [
            {
                "CidrBlock": "10.0.0.0/16",
                "Egress": false,
                "Protocol": "6",
                "RuleAction": "allow",
                "RuleNumber": 100,
                "PortRange": { "From": 443, "To": 443 }
            },
            {
                "CidrBlock": "0.0.0.0/0",
                "Egress": false,
                "Protocol": "-1",
                "RuleAction": "deny",
                "RuleNumber": 32767
            }
        ]
    }

    Inbound port 8443 has no ALLOW entry — the implicit DENY at rule 32767 drops it. Now check the egress entries — NACLs are stateless, so return traffic on ephemeral ports must also be explicitly permitted outbound:

    $ aws ec2 describe-network-acls \
        --filters "Name=association.subnet-id,Values=subnet-0def456abc789012" \
        --query 'NetworkAcls[0].Entries[?Egress==`true`]' \
        --output json
    
    [
        {
            "CidrBlock": "0.0.0.0/0",
            "Egress": true,
            "Protocol": "-1",
            "RuleAction": "deny",
            "RuleNumber": 32767
        }
    ]

    There are zero egress ALLOW rules. All return traffic is blocked at the NACL level, regardless of what the Security Group permits.

    How to Fix It

    Add inbound and outbound NACL entries. Because NACLs are stateless, rules for both directions are mandatory:

    # Allow inbound port 8443 from VPC CIDR
    $ aws ec2 create-network-acl-entry \
        --network-acl-id acl-0abc123456def789 \
        --rule-number 110 \
        --protocol tcp \
        --rule-action allow \
        --ingress \
        --cidr-block 10.0.0.0/16 \
        --port-range From=8443,To=8443
    
    # Allow outbound ephemeral return traffic to VPC CIDR
    $ aws ec2 create-network-acl-entry \
        --network-acl-id acl-0abc123456def789 \
        --rule-number 100 \
        --protocol tcp \
        --rule-action allow \
        --egress \
        --cidr-block 10.0.0.0/16 \
        --port-range From=1024,To=65535
    Important: NACL rules are evaluated in ascending order by rule number. A DENY at a lower rule number overrides an ALLOW at a higher rule number for matching traffic. Always verify no explicit DENY rule at a lower number precedes your new ALLOW entry for the same traffic class.

    Root Cause 6: Wrong Protocol Specified

    Why It Happens

    AWS Security Group rules are protocol-specific. A rule opening port 53 for TCP will not allow DNS queries that use UDP port 53. A rule permitting TCP does not permit ICMP ping. Engineers frequently assume a port-based rule covers all protocols on that port, or they forget that certain services like DNS operate on both TCP and UDP. Rules allowing only ICMP type 8 (echo request) but not type 0 (echo reply) cause one-way ping failures that look like intermittent connectivity issues.

    How to Identify It

    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'SecurityGroups[0].IpPermissions[?FromPort==`53`]'
    
    [
        {
            "FromPort": 53,
            "IpProtocol": "tcp",
            "IpRanges": [{"CidrIp": "10.0.0.0/16"}],
            "ToPort": 53
        }
    ]

    Only TCP port 53 is permitted. Route 53 Resolver and most DNS clients default to UDP port 53. Validate from the instance:

    $ dig @10.0.0.2 solvethenetwork.com +tcp   # Succeeds (TCP allowed)
    $ dig @10.0.0.2 solvethenetwork.com        # Times out (UDP blocked)

    How to Fix It

    $ aws ec2 authorize-security-group-egress \
        --group-id sg-0abc123def456789 \
        --protocol udp \
        --port 53 \
        --cidr 10.0.0.0/16

    Root Cause 7: Security Group Not Attached to the Instance

    Why It Happens

    Engineers sometimes create and correctly configure a Security Group, then forget to attach it to the target instance or network interface. The instance continues using its original Security Group, which has no relevant rules for the new service. This is common in Terraform or CloudFormation deployments where the Security Group resource is correctly defined but the

    vpc_security_group_ids
    or
    SecurityGroupIds
    reference is missing from the instance or launch template configuration.

    How to Identify It

    $ aws ec2 describe-instances \
        --instance-ids i-0abc123def456789 \
        --query 'Reservations[0].Instances[0].SecurityGroups'
    
    [
        {
            "GroupId": "sg-0old111111111111",
            "GroupName": "default"
        }
    ]

    The newly created Security Group

    sg-0abc123def456789
    is not present. The instance only has the default SG, which has no relevant rules.

    How to Fix It

    Attach the correct Security Group to the instance. For a primary network interface, modify the instance attribute directly (this replaces all attached SGs, so include any you want to keep):

    # Retrieve the network interface ID first
    $ aws ec2 describe-instances \
        --instance-ids i-0abc123def456789 \
        --query 'Reservations[0].Instances[0].NetworkInterfaces[0].NetworkInterfaceId' \
        --output text
    
    eni-0abc123def456789
    
    # Modify the network interface to attach both SGs
    $ aws ec2 modify-network-interface-attribute \
        --network-interface-id eni-0abc123def456789 \
        --groups sg-0abc123def456789 sg-0old111111111111

    Root Cause 8: Security Group Rule Limit Exceeded

    Why It Happens

    AWS imposes a default quota of 60 inbound rules and 60 outbound rules per Security Group. When a Security Group reaches this limit, new

    authorize-security-group-ingress
    or
    authorize-security-group-egress
    calls fail with a hard error. Security Groups accumulate rules over time as infrastructure grows — temporary access rules added for debugging, IP ranges that are no longer valid, and overlapping rules from multiple teams all consume quota. When the quota is exhausted, legitimate required rules simply cannot be added.

    How to Identify It

    # Count current inbound rules
    $ aws ec2 describe-security-groups \
        --group-ids sg-0abc123def456789 \
        --query 'length(SecurityGroups[0].IpPermissions)'
    
    60
    
    # Attempt to add a rule — the error:
    An error occurred (RulesPerSecurityGroupLimitExceeded) when calling the
    AuthorizeSecurityGroupIngress operation: The maximum number of rules per
    security group has been reached.

    How to Fix It

    Audit and remove stale or redundant rules. You can also consolidate multiple individual /32 host entries into a single CIDR, or request a service quota increase:

    # Request a quota increase for inbound rules per SG
    $ aws service-quotas request-service-quota-increase \
        --service-code ec2 \
        --quota-code L-0EA8095F \
        --desired-value 120
    
    # Check current quota values
    $ aws service-quotas get-service-quota \
        --service-code ec2 \
        --quota-code L-0EA8095F

    Prevention

    Preventing Security Group misconfigurations is substantially easier than debugging them in production. Implement these practices across your AWS environment:

    • Enable VPC Flow Logs on all VPCs from day one. Flow logs are the most effective diagnostic tool for Security Group and NACL issues. Publish them to CloudWatch Logs Insights or S3, and retain them for at least 30 days. Without flow logs, debugging network drops becomes a process of elimination rather than evidence-based investigation.
    • Use AWS Network Reachability Analyzer before and after changes. This tool analyzes whether a specific source-destination pair can communicate and identifies exactly which Security Group rule or NACL entry is blocking the path — without transmitting any actual test traffic. Run it proactively after any Security Group change to validate intent.
    • Reference Security Groups instead of CIDR ranges wherever possible. When the traffic source is another EC2 instance, ECS task, or RDS cluster, reference its Security Group ID as the inbound source rather than its IP address. Security Group references automatically track IP changes and eliminate CIDR mismatch errors entirely.
    • Enforce Infrastructure as Code for all Security Group changes. Terraform, CDK, and CloudFormation enforce code review for Security Group mutations, which catches port and CIDR errors before they ever reach production. Direct console edits should be treated as break-glass exceptions, not standard workflow.
    • Standardize naming and tagging. Include the service name, environment tier, and owning team in every Security Group name. Use the Description field to document the intended purpose. Tags should include the team, cost center, and creation date for audit traceability.
    • Never modify or attach resources to the default Security Group. Leave the default VPC Security Group with no inbound or outbound rules and keep it unattached to any resource. It exists only as a fallback and its unrestricted default rules are a compliance liability.
    • Audit Security Groups regularly with AWS Config managed rules. Enable
      vpc-sg-open-only-to-authorized-ports
      ,
      restricted-ssh
      , and
      restricted-common-ports
      to detect overly permissive rules automatically and generate findings before they cause a security incident.
    • Document the stateful (SG) vs. stateless (NACL) distinction in all onboarding runbooks. This misunderstanding is a recurring source of production misconfigurations. New engineers working on AWS networking should understand the distinction on day one, not after their first production incident.

    Frequently Asked Questions

    Q: How do I tell if a Security Group is blocking traffic versus the application not listening on the port?

    A: The connection behavior is the key indicator. A connection timeout (the connection hangs with no response for the full TCP timeout period) means the packet was dropped before reaching the OS — this points to a Security Group, NACL, or routing issue. A connection refused error (immediate response with RST) means the packet reached the host but no process is listening on that port. Use

    nc -zv 10.0.1.50 8443
    from the source to observe the exact behavior. A timeout means Security Group; a refused means application.

    Q: Do Security Group rules apply to traffic between instances in the same VPC?

    A: Yes. Security Groups evaluate all traffic arriving at an ENI, regardless of origin. Traffic between two EC2 instances in the same VPC subnet is still subject to the destination instance's inbound Security Group rules. Same-subnet traffic is not implicitly trusted or bypassed.

    Q: Can I attach multiple Security Groups to one EC2 instance, and how are they evaluated?

    A: Yes, up to 5 Security Groups can be attached per network interface (adjustable via service quota). AWS evaluates all attached Security Groups as a union. If any single Security Group has an inbound rule that permits the traffic, it is allowed. There is no priority ordering, no most-specific-wins logic, and no deny rules within Security Groups — only allows. The only implicit deny is for traffic not matched by any rule across any attached Security Group.

    Q: Do Security Group rule changes take effect immediately?

    A: Yes. Security Group rule changes propagate and take effect within seconds for all traffic — including existing established connections. You do not need to restart instances, reboot, or terminate connections for new rules to apply.

    Q: What is the functional difference between a Security Group and a Network ACL?

    A: Security Groups are stateful, operate at the ENI (instance) level, support only ALLOW rules, and evaluate all attached SGs as a union. Network ACLs are stateless, operate at the subnet level, support both ALLOW and DENY rules, and evaluate rules in ascending rule number order with the first match winning. NACLs are evaluated before Security Groups for inbound traffic. Both must permit traffic for it to flow.

    Q: Why does AWS Network Reachability Analyzer show a path as reachable, but traffic is still failing?

    A: Reachability Analyzer tests the logical rule configuration only — it does not send actual data plane traffic. It will not detect OS-level firewalls (iptables, nftables, Windows Firewall), application-layer ACLs, routing table issues inside the guest OS, or network interfaces in unexpected states. If Reachability Analyzer shows the path as clear but traffic still fails, move your investigation to the instance OS, the application configuration, and the guest routing table.

    Q: Can a Security Group block traffic between instances that share the same Security Group?

    A: Yes. By default, instances sharing the same Security Group cannot communicate with each other unless an explicit inbound rule is added with the Security Group itself as the source (a self-referencing rule). To allow all instances in Security Group

    sg-0abc123def456789
    to communicate with each other on all ports, add an inbound rule with source set to
    sg-0abc123def456789
    and protocol set to
    -1
    (all traffic).

    Q: What happens if I try to delete a Security Group that is still attached to a running instance?

    A: AWS will reject the deletion with the error:

    DependencyViolation: resource sg-0abc123def456789 has a dependent object
    . You must first detach the Security Group by modifying the instance or network interface to use a different Security Group, then delete it. The same applies to Security Groups referenced as sources or destinations in other Security Groups' rules — those references must be removed before deletion.

    Q: Does AWS Systems Manager Session Manager bypass Security Group restrictions?

    A: Session Manager communicates over HTTPS (port 443) to the SSM VPC endpoints or the public SSM service endpoints — it does not use SSH port 22. If the instance Security Group blocks outbound TCP 443, Session Manager will fail. If your VPC has no internet gateway and no VPC endpoints for SSM (

    ssm
    ,
    ssmmessages
    ,
    ec2messages
    ), Session Manager will also fail regardless of Security Group rules. Session Manager is extremely useful for debugging Security Groups precisely because it uses a different path than SSH.

    Q: How do I find all Security Groups in my account that have no rules and are not attached to any resource?

    A: Use this CLI query to find unused Security Groups. First list all SG IDs in use by EC2 network interfaces, then compare against all Security Groups in the account:

    # List all SG IDs currently attached to network interfaces
    $ aws ec2 describe-network-interfaces \
        --query 'NetworkInterfaces[*].Groups[*].GroupId' \
        --output text | tr '\t' '\n' | sort -u > /tmp/used_sgs.txt
    
    # List all SG IDs in the account
    $ aws ec2 describe-security-groups \
        --query 'SecurityGroups[*].GroupId' \
        --output text | tr '\t' '\n' | sort -u > /tmp/all_sgs.txt
    
    # Find orphaned SGs
    $ comm -23 /tmp/all_sgs.txt /tmp/used_sgs.txt

    Q: Is there a way to test Security Group rules without making live traffic changes?

    A: Yes. Use AWS Network Reachability Analyzer to validate rule logic without sending traffic. Additionally, the AWS Console Security Group rule evaluation view shows which rule would match a given source IP, port, and protocol combination. For more comprehensive testing, AWS Inspector and third-party tools like Steampipe can query Security Group configurations and flag rules that deviate from expected policies — all without touching live traffic flows.

    Q: Why do I see ACCEPT entries in VPC Flow Logs but the application still reports connection failures?

    A: ACCEPT in VPC Flow Logs means the packet was permitted by the Security Group and NACL — it does not mean the full TCP handshake completed successfully or that the application processed the request. If you see ACCEPT logs for SYN packets but no corresponding ACCEPT for the return SYN-ACK, the return path is blocked (check the destination instance's outbound rules or the NACL egress rules on the source subnet). If both directions show ACCEPT but the application fails, the issue is above Layer 4: TLS certificate errors, application crashes, or resource exhaustion on the server.

    Frequently Asked Questions

    How do I tell if a Security Group is blocking traffic versus the application not listening on the port?

    A connection timeout means the packet was dropped before reaching the OS, pointing to a Security Group, NACL, or routing issue. A connection refused error means the packet reached the host but no process is listening. Use nc -zv from the source to observe the exact behavior. Timeout means Security Group; refused means application.

    Do Security Group rules apply to traffic between instances in the same VPC?

    Yes. Security Groups evaluate all traffic arriving at an ENI regardless of origin. Traffic between two EC2 instances in the same VPC subnet is still subject to the destination instance's inbound Security Group rules. Same-subnet traffic is not implicitly trusted.

    Can I attach multiple Security Groups to one EC2 instance, and how are they evaluated?

    Yes, up to 5 per network interface by default. AWS evaluates all attached Security Groups as a union — if any single SG allows the traffic, it is permitted. There is no priority ordering and no deny rules within Security Groups, only allows. Traffic not matched by any rule across all attached SGs is implicitly denied.

    Do Security Group rule changes take effect immediately?

    Yes. Security Group rule changes propagate and take effect within seconds for all traffic, including existing established connections. You do not need to restart instances or terminate connections for new rules to apply.

    What is the functional difference between a Security Group and a Network ACL?

    Security Groups are stateful, operate at the ENI level, support only ALLOW rules, and evaluate all attached SGs as a union. Network ACLs are stateless, operate at the subnet level, support ALLOW and DENY rules, and evaluate rules in ascending rule number order with the first match winning. NACLs are evaluated before Security Groups for inbound traffic.

    Why does AWS Network Reachability Analyzer show a path as reachable but traffic is still failing?

    Reachability Analyzer tests logical rule configuration only — it does not send actual data plane traffic. It cannot detect OS-level firewalls (iptables, Windows Firewall), application-layer ACLs, routing issues inside the guest OS, or network interfaces in unexpected states. If the path shows clear but traffic fails, investigate the instance OS and application configuration.

    Can a Security Group block traffic between instances that share the same Security Group?

    Yes. Instances sharing the same Security Group cannot communicate unless an explicit inbound rule is added with the Security Group itself as the source (a self-referencing rule). To allow all instances within a Security Group to communicate on all ports, add an inbound rule with the SG ID as source and protocol set to all traffic.

    What happens if I try to delete a Security Group that is still attached to a running instance?

    AWS will reject the deletion with a DependencyViolation error. You must first detach the Security Group by modifying the instance or network interface to use a different SG, then delete it. Security Groups referenced as sources or destinations in other SG rules must also have those references removed before deletion succeeds.

    Does AWS Systems Manager Session Manager bypass Security Group restrictions?

    Session Manager communicates over HTTPS port 443 to SSM endpoints — it does not use SSH port 22. If outbound TCP 443 is blocked, Session Manager will also fail. If the VPC has no internet gateway and no VPC endpoints for SSM, Session Manager fails regardless of Security Group rules. This makes Session Manager useful for debugging Security Groups because it uses a different traffic path than SSH.

    Is there a way to test Security Group rules without making live traffic changes?

    Yes. Use AWS Network Reachability Analyzer to validate rule logic without sending traffic. The AWS Console Security Group rule evaluation view shows which rule matches a given source IP, port, and protocol. AWS Inspector and tools like Steampipe can also query Security Group configurations and flag deviations from expected policies without touching live traffic.

    Related Articles