[AWS Infra] Building & Configuring a NAT Instance from an AMI to Cut NAT Gateway Costs (Part 1)

Overview: Building a NAT Instance (cost saving)

  1. Why a NAT Instance (instead of a NAT gateway) (Part 1)
  2. How to use the NAT Instance AMI provided on AWS (Part 1)
  3. Building a NAT Instance directly with iptables (Part 2)

This Part 1 post is about using the NAT Instance AMI provided by the AWS community. If you want to build a NAT Instance directly using iptables, please refer to Part 2. (Part 2 is below.)

[AWS Infra] Building & Configuring a NAT Instance to Cut NAT Gateway Costs (Part 2)
[AWS Infra] Building & Configuring a NAT Instance to Cut NAT Gateway Costs (Part 2)
The Part 1 community AMI runs an old (EOS) OS and is hard to maintain. In Part 2 we build a NAT instance on the latest Ubuntu by configuring iptables directly (IP forwarding + MASQUERADE), and persist the rules across reboots.
taystudios.com/blog

NAT gateway & NAT Instance?

Recently, I ended up taking charge of the network and application architecture on AWS. It's not exactly as it was at the time, but the network diagram I had in mind is as follows.

Connecting a Private subnet to the internet using a NAT Instance (EC2) instead of a NAT gateway Figure 1. Connecting a Private subnet to the internet using a NAT Instance (EC2) instead of a NAT gateway

Normally, to let a private network (Private subnet) communicate with the internet, you need a NAT Gateway. But in this setup, instead of placing a separate NAT Gateway in the Public subnet, I wanted to connect the Private Subnet's internet through an EC2 (NAT Instance). At the same time, I made it serve as both a Reverse Proxy Server and a Bastion Server.

If I describe the pros and cons of a NAT Instance, I can put it as follows.

Pros

Since you don't directly use a NAT Gateway on AWS, you can cut costs. The idea is that if you're going to have a Proxy Server or Bastion Server anyway, you use that Proxy Server to connect to the internet.

Cons

  • If the Proxy Server shuts down or has a problem, the Private Subnet's internet is cut off. (In the application architecture, if the Proxy Server has a problem, it's right that the services behind it can't be served anyway.)
  • It doesn't guarantee high availability, scalability, security, patch management, etc., the way AWS's NAT gateway does. In other words, you have to manage the OS version, security, and so on yourself. (This is essentially the reason to use AWS's NAT gateway.)

Despite the cons above, the reason I wanted to build and use a NAT Instance directly was partly that the project scale wasn't large, and above all because I had to cut costs. (Roughly, the base maintenance cost is about $32 a month + additional fees depending on traffic.)

Let's look at how you can create a NAT Instance on AWS. It can be summarized into two methods.

Method 1. Using the AMI provided by AWS (from the community)

1) Creating a NAT Instance using the AMI

Selecting 'Browse more AMIs' in the EC2 creation screen Figure 2. Selecting 'Browse more AMIs' in the EC2 creation screen

In the EC2 creation screen, click "Browse more AMIs."

Searching in the Community AMIs tab Figure 3. Searching in the Community AMIs tab

In the Community AMIs tab, search for 'amzn-ami-vpc-nat'. What's registered in the community differs by region. When I set the Seoul region, several AMIs appear as above. Among these, I selected the most recently published AMI by publish date.

Creating the NAT Instance Figure 4. Creating the NAT Instance

When you select that AMI, as in Figure 4, the CPU architecture (x86_64 above), storage format, etc., matching that AMI are shown, and on top of that type you can select the instance type. When you create the EC2 this way, that instance will be configured to be able to pass incoming external traffic to another destination. In other words, you can think of it as 'configured to be able to act as a NAT gateway.'

* For reference, the username when SSH-ing in is shown as Username: ec2-user, as in Figure 4 above.

When creating the EC2, place it in the Public subnet within the VPC you created. Then the public subnet's routing table must of course be connected to the internet gateway, and within the VPC's local you must let everything communicate. Also, if needed, I recommend setting up security with security groups or NACLs. (In this post I can't explain the AWS basics in detail, so I'll just mention them and move on.)

Just refer to the Public subnet's routing table. (If you don't connect to the internet gateway, AWS won't allow external communication.)

public subnet's routing table (just for reference) Reference figure. public subnet's routing table (just for reference)

2) Configuring the Private subnet Routing Table and settings in the NAT Instance console

Then, doing some additional network routing table and instance settings in the AWS console wraps it up. Let me do the final additional settings and confirm that the EC2 in the private subnet connects to the internet.

Configuring the Private Subnet Routing Table

Even when using a NAT gateway, you connected it directly to the NAT gateway in the routing table mapped to the Private subnet. You have to do this for the NAT Instance too.

Setting the target to the NAT instance in the Private subnet routing table Figure 5. Configuring the Private subnet's routing table

Private subnet: in the routing table, set the target to 'Instance' and below it select the NAT-instance I created above (in my case I named it nat-instance). You can understand this as meaning that all traffic going out from the private subnet to the internet passes through the NAT-instance.

* For reference, after you configure it, the target starts with eni- as below; this is the Elastic Network Interface, which you can confirm maps directly to the network card resource. From this you can infer that, at the OS level, it passes traffic to another target through Layer 2 (the data link layer) and Layer 3 (the network layer). (This is set up in the community AMI created above.)

network card connection Reference figure. network card connection

NAT Instance EC2 network setting

In the EC2 dashboard, click your nat-instance, then click 'Change source/destination check' under 'Networking' in the 'Actions' tab at the top right. (Besides the routing table, you have to change the AWS EC2 instance's own setting.)

Changing the nat instance networking setting Figure 6. Changing the nat instance networking setting

Source/destination check Figure 7. Source/destination check

As in Figure 7, in the source/destination check part you have to click the "Stop" radio button. On AWS, it seems to work in a way that drops traffic if it doesn't reach the target EC2 instance. In other words, you can understand it as configuring traffic to be detoured to another instance through a particular instance.

📌 Required — Generally, if you use the default security group, there's a high chance only SSH is open. At minimum you have to configure the security so that it can communicate.

private ec2 security group Reference figure. private ec2 security group

I arbitrarily set the security group of the EC2 in the private subnet so it can receive all traffic. Configure this part according to your project policy. (In this post I set it as above for demonstration.)

Also, in this post I didn't set an Elastic IP, but even without an EIP, as long as the NAT Instance's public IP is enabled, an arbitrary IP attaches on its own. By the Dynamic Host Configuration Protocol policy, the public IP will change if you turn the EC2 off and on, but if you're going to keep it running, you don't have to set an EIP.

NAT Instance build result

Before connecting the NAT Instance Figure 8. Before connecting the NAT Instance

After connecting the NAT Instance Figure 9. After connecting the NAT Instance

Before connecting the NAT Instance, you can see that the apt repository update commonly used by Debian-based systems, via sudo apt-get update, doesn't go through. But after connecting, you can confirm it's received fine.

Closing

If you use the NAT-instance-related AMI provided by the AWS community, you can build a NAT instance with hardly any setup. However, that AMI uses an old OS version and is in an End-of-Service state. Also, when trying to manually download packages, it's very hard to find the needed files, and the supported sites are limited. So maintenance is very difficult, and using it for purposes other than the NAT instance function has many difficulties. (I already tried.)

Since I want to use the NAT instance as a Reverse Proxy server as well, OS version management is important. At minimum, certificate-related packages need to be provided so it can support HTTPS, but the AMI mentioned earlier turned out not to support this. Therefore, in Part 2, I plan to cover how to build a NAT instance directly based on the latest OS version provided by AWS.


📦 Migrated from the Tistory blog I used to run. Original: taehyuklee.tistory.com/27

Share𝕏f

Comments