DEV Community

Hugo Prudente
Hugo Prudente

Posted on

Using AWS Network ACLs With NAT Gateway

It’s quite common the mistakes made when using the AWS Network ACLs for adding that extra layer of security in your VPC.

Given the fact that Network ACLs are stateless, meaning that the Inbound (Ingress) should have a matching rule for Outbound (Egress).

With this post, you will learn how to identify such particularities using an AWS ElasticBeanstalk environment as an example, due to its sensitivity regarding network access requirements.

Common Issues

  • Fail to access any HTTPS/TLS endpoint resulting in timeout
  • Fail to sync NTP servers

Difference between Security Group and Network ACL (NACL)

The main difference between the Security Group and the Network ACL (NACL) is the
the context where they are applied and the type of rules they provided.

  • A Security Group:
    Stateful: Therefore you don't need a rule that allows response traffic for inbound requests.
    Local: Therefore it applies only to the instance or service to which the security group is attached to.

  • A Network ACL:
    Stateless: Therefore this rule is required to allow response traffic for inbound requests on the outbound rules.
    Global: Therefore it applies to all services that are placed on the subnet that is attached to.

AWS Network NACL & Security Group

Scenario 1 - (Web Tier) Public Subnet with Network ACL without AWS NAT Gateway.

Using the diagram below as an example to configure the Network ACL's for an ElasticBeanstalk environment.

Diagram:

+------------------+
|                  |
|   +----------+   |
|   | INSTANCE |   |
|   +----------+   |
|   |  SG-001  |   |
|   +----------+   |
+------------------+
|    Subnet Pub    |
+------------------+
         +   +--------------+
         |---| ACL-001      |
         v   +--------------+
+------------------+
|       IGW        |
+------------------+
Enter fullscreen mode Exit fullscreen mode

As presented on the common issues, the simplified flow for UDP and HTTPS TCPDump packet below displays the return of 2 (two) actions from the EC2 belonging to the ElasticBeanstalk test environment.

UDP 172.31.0.31:123 > 0.amazon.pool.ntp.org
UDP 0.amazon.pool.ntp.org > 172.31.0.31:2000

TCP 172.31.0.31:443 > aws.amazon.com
TCP aws.amazon.com > 172.31.0.31:3000
Enter fullscreen mode Exit fullscreen mode

As we notice from the packet analysis the returning port is ephemeral and as we already know that Network ACL are stateless we need to account for that during the rules creation. Due to the Security Group being stateful, the above behavior will work properly.

Solution

The solution, in this case, is a mix between the Security Group (SG-001) and the Network ACLs (ACL-001) where we can see:

Security Group presents inbound traffic for TCP/HTTP, TCP/HTTPS for standard ports 80 and 443 from everywhere and outbound traffic from the instance to everywhere.

Security Group Inbound Rule (SG-001)

Type  |Protocol |Port Range |Source
--------|-----------|-----------|------
HTTP  |TCP  |80 |0.0.0.0/0
HTTPS |TCP  |443  |0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

Security Group Outbound Rule (SG-001)

Type  |Protocol |Port Range |Source
--------|-----------|-----------|------
All |Traffic  |ALL  |ALL  |0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

Network ACL Inbound (ACL-001)

Rule #  Type  Protocol  Port Range  Destination Allow / Deny
102 HTTP (80) TCP (6) 80  0.0.0.0/0 ALLOW
103 HTTPS (443) TCP (6) 443 0.0.0.0/0 ALLOW
201 Custom TCP Rule TCP (6) 1024-65535  0.0.0.0/0 ALLOW
202 Custom UDP Rule UDP (17)  123 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Enter fullscreen mode Exit fullscreen mode

Network ACL Outbond (ACL-001)

Rule #  Type  Protocol  Port Range  Destination Allow / Deny
101 HTTP (80) TCP (6) 80  0.0.0.0/0 ALLOW
202 HTTPS (443) TCP (6) 443 0.0.0.0/0 ALLOW
102 Custom TCP Rule TCP (6) 1024-65535  0.0.0.0/0 ALLOW
103 Custom UDP Rule)  UDP (17)  1024-65535  0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Enter fullscreen mode Exit fullscreen mode

As we know that ElasticBeanstalk does more than serve traffic but also has agents that connect to AWS API's we notice two different sets of configurations in the Network ACL's.

  • Rules 102 and 103 allow inbound traffic for ports 80 and 443 following by its outbound pair, the 102 and 103 that are responsible to allow ephemeral port out to answer the requests.
  • Rules 202 and 203 are using in the reverse order, an agent will post from the EC2 to AWS API, we analyze it inverting the tables. In this case, outbound requires 80 and 443 for the request, and the response will return in an ephemeral port on the inbound rules.

Scenario 2 - (Worker Tier) Private Subnet with Network ACL and AWS NAT Gateway.

Again using the diagram below as an example to configure the Network ACL's for an ElasticBeanstalk environment.

Diagram:

+------------------+
|                  |
|   +----------+   |
|   | INSTANCE |   |
|   +----------+   |
|   |  SG-002  |   |
|   +----------+   |
+------------------+
|  Subnet Private  |
+------------------+
          +
          |   +--------------+
          |---| ACL-002      |
          v   +--------------+
+------------------+
|                  |
|   +----------+   |
|   |  NAT GW  |   |
|   |  SG-002  |   |
|   +----------+   |
+------------------+
|    Subnet Pub    |
+------------------+
         +   +--------------+
         |---| ACL-003      |
         v   +--------------+
+------------------+
|       IGW        |
+------------------+
Enter fullscreen mode Exit fullscreen mode

Same as before as presented on the common issues, the simplified flow for UDP and HTTPS TCPDump packet below displays the return of 2 (two) actions from the EC2 belonging to the ElasticBeanstalk test environment.

UDP 172.31.0.31:123 > 172.31.0.34:2000
UDP 172.31.0.34:2000 > 0.amazon.pool.ntp.org
UDP 0.amazon.pool.ntp.org > 172.31.0.34:2000
UDP 172.31.0.34:2000 > 172.31.0.31:3000

TCP 172.31.0.31:443 > 172.31.0.33:2000
TCP 172.31.0.33:2000 > aws.amazon.com
TCP aws.amazon.com > 172.31.0.33:3000
TCP 172.31.0.33:3000 > 172.31.0.31:3000
Enter fullscreen mode Exit fullscreen mode

We can see that this is a little bit different than before, now 4 (four) pairs of packets with a extra jump returning different ports for each pair.

It happens due to a particular behavior of the AWS NAT Gateway. AWS Nat Gateway encapsulates packets to achieve higher performance, causing the change on the packet header during its life cycle.

Solution

The solution, in this case, is a also a mix between the Security Group (SG-002) and the Network ACLs but this case ACL-002 and ACL-003 where we can see:

Security Group Inbound Rule (SG-002)

Type  Protocol  Port Range  Source
HTTP  TCP 80  0.0.0.0/0
Custom UDP  UDP 123 0.0.0.0/0
Custom UDP  UDP 1024-65535  0.0.0.0/0
Security Group Outbond Rule (SG-002)
Type  Protocol  Port Range  Source
All Traffic ALL ALL 0.0.0.0/0
Enter fullscreen mode Exit fullscreen mode

Network ACL Inbound - Private Subnet (ACL-002)

Rule #  Type  Protocol  Port Range  Destination Allow / Deny
102 HTTP (80) TCP (6) 80  0.0.0.0/0 ALLOW
103 HTTPS (443) TCP (6) 443 0.0.0.0/0 ALLOW
202 Custom TCP Rule TCP (6) 1024-65535  0.0.0.0/0 ALLOW
203 Custom UDP Rule UDP (17)  123 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Enter fullscreen mode Exit fullscreen mode

Network ACL Outbond - Private Subnet (ACL-002)

Rule #  Type  Protocol  Port Range  Destination Allow / Deny
202 HTTP (80) TCP (6) 80  0.0.0.0/0 ALLOW
203 HTTPS (443) TCP (6) 443 0.0.0.0/0 ALLOW
102 Custom TCP Rule TCP (6) 1024-65535  0.0.0.0/0 ALLOW
103 Custom UDP Rule)  UDP (17)  1024-65535  0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Enter fullscreen mode Exit fullscreen mode

Network ACL Inbound - Public Subnet (ACL-003)

Rule #  Type  Protocol  Port Range  Destination Allow / Deny
102 HTTP (80) TCP (6) 80  0.0.0.0/0 ALLOW
103 HTTPS (443) TCP (6) 443 0.0.0.0/0 ALLOW
202 Custom TCP Rule TCP (6) 1024-65535  0.0.0.0/0 ALLOW
203 Custom UDP Rule UDP (17)  123 0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Enter fullscreen mode Exit fullscreen mode

Network ACL Outbond - Public Subnet (ACL-003)

Rule #  Type  Protocol  Port Range  Destination Allow / Deny
202 HTTP (80) TCP (6) 80  0.0.0.0/0 ALLOW
203 HTTPS (443) TCP (6) 443 0.0.0.0/0 ALLOW
102 Custom TCP Rule TCP (6) 1024-65535  0.0.0.0/0 ALLOW
103 Custom UDP Rule)  UDP (17)  1024-65535  0.0.0.0/0 ALLOW
* ALL Traffic ALL ALL 0.0.0.0/0 DENY
Enter fullscreen mode Exit fullscreen mode

Again we have the rule set for the Network ACL where.

  • ACL-002 Rules 102 and 103 allow inbound traffic for ports 80 and 443 following by its outbound pair, the 102 and 103 that are responsible to allow ephemeral port out to answer the requests.
  • ACL-002 Rules 202 and 203 are using in the reverse order, an agent will post from the EC2 to AWS API, we analyze it inverting the tables. In this case, outbound requires 80 and 443 for the request, and the response will return in an ephemeral port on the inbound rules.
  • We would expect only outbound traffic for the NAT Gateway, but due to the encapsulation, NAT Gateway is opening a new TCP connection with the backend using the new port requiring the same set as before.

These problems only happen if you tight the security on the Network ACL used by the AWS NAT Gateway, as the AWS default NACL that allows all the traffic inbound and outbound.

Originally posted on: hugoprudente.github.io/en/posts/

References:

Top comments (1)

Collapse
 
cgill27 profile image
Craig Gill

For time sync, Amazon Linux 2 uses the built-in instance endpoint to sync time with, so no need to have traffic go external for time sync:
docs.aws.amazon.com/AWSEC2/latest/...