NATゲートウェイが高いのでNATインスタンスを立てる

# 前書き

AWSを使用してシステム構築する多くの場合、プライベートサブネットを作成しインターネットから隔離することでアタックサーフェスの減少させます。
その場合は、パブリックサブネットでNATゲートウェイを作成しプライベートサブネットに紐づいたルートテーブルを変更することで、プライベートサブネットからパブリックサブネットを介してインターネット接続します。
しかしながら、小規模な開発環境でNATゲートウェイを使用するには高価である可能性があります。この記事では、一般的なVPC構成でNATゲートウェイの代わりにNATインスタンスを構築する方法を解説します。

# 構築

NATインスタンスを構築するVPCとして、一般的なマルチAZ構成で各AZにパブリックサブネットとプライベートサブネットがあり、インターネットゲートウェイがVPCに既にアタッチされている想定です。
その上で、
[1. NATインスタンスを起動する](#NATインスタンスを起動する)
[2. ネットワークルーティングの設定をする](#ネットワークルーティングの設定をする)
[3. nftablesの設定をする](#nftablesの設定をする)
を行います。（記事に記載のないパラメータはデフォルト値を使用しています。）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629414/570ae463-2243-3e90-ac35-9d50ee233b0e.png)

## NATインスタンスを起動する

### アプリケーションおよび OS イメージ (Amazon マシンイメージ)
AMIは、AWSより提供されている最新OSのAmazon Linux 2022で、パッケージが最小構成の下記AMIを使用します。

```text:AMI
AMI Name : al2022-ami-minimal-2022.0.20220928.0-kernel-5.15-arm64
AMI ID   : ami-0db1acc60b0d6baf2
Description : Amazon Linux 2022 AMI 2022.0.20220928.0 arm64 Minimal HVM kernel-5.15
```

2022年10月時点で、Amazon Linux 2022はRelease Candidateですが、2022年末にリリースされる予定です。[^1]

|OS|サポート終了期日|ステータス|
|---|---|---|
|Amazon Linux|2020年12月31日|メンテナンスサポート中|
|Amazon Linux 2|2024年6月30日|サポート中|
|Amazon Linux 2022|2027年|Release Candidate|

### インスタンスタイプ
インスタンスタイプは、バースト可能なタイプで最新最小のt4g.nanoを使用します。
|インスタンス名|時間料金|月料金|vCPU|メモリ|ネットワーク|
|---|---|---|---|---|---|
|t4g.nano|0.0054 USD|3.942 USD|2|0.5 GiB|~5Gbps|
|t4g.micro|0.0108 USD|7.884 USD|2|1 GiB|~5Gbps|

### キーペア
セッションマネージャーを利用するため、キーペアなしで続行します。

### ネットワーク設定
パブリックサブネットを選択し、パブリックIPの自動割り当ては有効化します。
また、セキュリティグループは各インバウンドルールが設定されたものを新規作成または既存利用します。

|タイプ|プロトコル|ポート範囲|ソースタイプ|ソース|
|---|---|---|---|---|
|すべてのトラフィック|ソースタイプ|すべて|すべて|プライベートサブネットのCIDR|

### 高度な詳細
インスタンスプロファイルは、セッションマネージャーを利用してEC2内部の設定を行うため、[AWSマネージドポリシー`AmazonSSMManagedInstanceCore`を使用したインスタンスプロファイルを作成します。](https://docs.aws.amazon.com/ja_jp/systems-manager/latest/userguide/setup-instance-profile.html)
ユーザーメタデータは、セッションマネージャーの接続のため、SSM Agentを起動時にインストールするスクリプトを設定します。

```bash
#!/bin/bash
cd /tmp
sudo dnf install -y https://s3.amazonaws.com/ec2-downloads-windows/SSMAgent/latest/linux_arm64/amazon-ssm-agent.rpm
sudo systemctl enable amazon-ssm-agent
sudo systemctl start amazon-ssm-agent
```

以上の設定でEC2を起動します。セッションマネージャーから接続するのに3分ほどかかります。

## ネットワークルーティングの設定をする

### ソース/宛先チェック

EC2はトラフィックの送信元、送信先のIPはどちらもENIのIPアドレスではない場合、自分自身と関係ないと判断しパケットが破棄されます。
NATインスタンスを選択し、ソース/宛先チェックを変更して、送信元/送信先チェック中を停止にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629414/1ee29f67-2a81-6c53-9b28-d4f2090b9a36.png)

### ルートテーブル

プライベートサブネットからのインターネット宛て（0.0.0.0/0）のパケットについて、NATインスタンスのENI（eni-id-a/b/c）をターゲットとしルートテーブルを修正します。
最終的には下図のルートテーブル設定になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629414/25c78dd5-24b7-61e3-22e8-5543be5a0916.png)


## nftablesの設定をする

iptablesでNAT設定可能ですが、より高性能なnftablesがリリースされ、iptalesよりnftablesを使用することが推奨されています。[^2]
そのため、nftablesをインストールし、Red Hatのドキュメントを参考に設定を行います。[^3]

LinuxではデフォルトでIPv4転送がオフになっているため、IP転送をONにします。
インスタンスが再起動されても転送されるよう、カーネルパラメータ1に永続的に設定します。[^4]

```text
# sysctl -w net.ipv4.ip_forward=1 >> /etc/sysctl.conf
```


NATに利用するインターフェイス名を確認するために`ifconfig`コマンドを入力します。
出力されたインターフェイス一覧で（ローカル）IPアドレスが付与されているインターフェイス名を記録します。
```text
# ifconfig
ens5: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 9001
inet 172.16.0.238  netmask 255.255.255.0  broadcast 172.16.0.255
...
```

nftablesのインストールとマスカレードNATを下記コマンドで設定します。
oifanameについては実際の`ifconfig`で確認したインターフェイス名を入力します。

```text
# dnf install -y nftables

# nft add table ipv4-masquerade
# nft -- add chain ipv4-masquerade prerouting { type nat hook prerouting priority -100 \; }
# nft add chain ipv4-masquerade postrouting { type nat hook postrouting priority 100 \; }
# nft add rule ipv4-masquerade postrouting oifname "ens5" masquerade
```

nftablesの設定を永続化させるために、設定ファイルを作成し起動時に読み込まれるようincludeします。

```text
# touch /etc/nftables/ipv4-masquerade.nft
# nft list table ipv4-masquerade > /etc/nftables/ipv4-masquerade.nft
# echo include "/etc/nftables/ipv4-masquerade.nft" >> /etc/sysconfig/nftables.conf
```

nftablesを起動し、自動起動に登録します。

```text
# systemctl start nftables
# systemctl enable nftabels
```

以上でNATインスタンス構築は完了です。
プライベートサブネットにEC2を立ち上げて、セッションマネージャーより接続することで、インターネット接続の確認できます。

# 費用

## 損益分岐
NATゲートウェイを構築した場合は、時間当たりの料金が高価ですが、インターネット転送量は抑えられます。
EC2インスタンスでは時間当たりの料金は安価ですが、インターネット転送費用が高価なため、データ転送量を判断材料とするとよいと思います。

||時間費用|転送費用|
|---|---|---|
|NATゲートウェイ|0.062 USD|0.062USD|
|NATインスタンス|0.0054 USD|0.114USD|

1AZ構成の場合、損益分岐点はデータ転送量800GB/月あたりです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/629414/eb71ea58-6405-1353-5c09-99f9fe693fb8.png)

## 最小コスト

EC2スポットインスタンスで起動することで、EC2の時間費用を更に70%程度削減できます。
NATを利用する状況としては、セッションマネージャー接続、ウイルス定義ファイル更新、セキュリティバッチ取得等、データ転送量がそれほど大きくならないことを考慮し、以下条件で最小コストを算出しました。

```text
・インスタンスタイプ　：t4g.nano
・起動タイプ　　　　　：スポットインスタンス
・起動台数　　　　　　：1台
・インスタンス起動時間：730時間/月
・データ転送量　　　　：10GB/月
```

```math
0.0054(USD/h) \times 730(h) \times 30(\%) + 0.114(USD/GB) \times 10(GB) \
= 1.18(USD) + 1.14(USD) \
= 2.32(USD)
```

以上より、約300円程度でNATを利用することが可能となります。

不明な点は加筆修正しますので、コメントいただければと思います。
[NetCabb@Twitter - https://twitter.com/NetCabb](https://twitter.com/NetCabb)

[^1]: 【AWS】Amazon Linux 2 のサポートはいつ終了するのですか? https://aws.amazon.com/jp/amazon-linux-2/faqs/
[^2]: 【Red Hat】iptables から nftables への移行 https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/securing_networks/getting-started-with-nftables_securing-networks#doc-wrapper
[^3]: 【Red Hat】nftables を使用したマスカレードの設定 https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/securing_networks/configuring-masquerading-using-nftables_configuring-nat-using-nftables
[^4]: 【Red Hat】sysctl でカーネルパラメーターを永続的に設定 https://access.redhat.com/documentation/ja-jp/red_hat_enterprise_linux/8/html/managing_monitoring_and_updating_the_kernel/configuring-kernel-parameters-permanently-with-sysctl_configuring-kernel-parameters-at-runtime