みなさん、こんにちは。AWS CLI が好きなテクニカルサポート課の市野です。
さて、再現性などの検証目的で、新たな VPC 自体の準備をして検証に臨むことが多々あるのですが、リソースの消し忘れや検証の長期化で高額になりがちな NAT ゲートウェイの課金問題を回避したく、NAT インスタンスの構築が簡単にできたらいいのに、とつねづね思っていました。
ただ、NAT インスタンスの構築のための AMI は Amazon Linux の頃のままで止まっており、できれば古い AMI は使いたくないなということで、なるべく最新の Amazon Linux 2 を利用しつつ、いつかの自分が楽になるように、手順をまとめてみました。
手順
以下の手順は、Cloudshell で実行する想定をしています。
事前準備:最新の Amazon Linux 2 の AMI ID の取得
以下のコマンドで、実行時点での最新版の Amazon Linux 2 の AMI ID の取得をしています。
AMI_ID=$(aws ec2 describe-images \ --owners amazon \ --filters "Name=architecture,Values=x86_64" \ "Name=name,Values=amzn2-ami-kernel-*" \ --query 'Images[].[Name, ImageId]' --output text | sort | tail -n 1 | awk -F ' ' '{print $2}') \ && echo ${AMI_ID}
NAT インスタンス用 EC2インスタンスの構築
userdata の作成と内容確認
NAT 処理の実現は iptables で行うため、iptables のインストールと NAT のための設定、そして iptables の永続化の処理をするための userdata を作成する。
USERDATA=${HOME}/userdata.txt cat << EOF > ${USERDATA} #!/bin/sh yum -y update yum -y upgrade yum -y install iptables-services iptables -L iptables -F echo 1 > /proc/sys/net/ipv4/ip_forward echo net.ipv4.ip_forward=1 >> /etc/sysctl.conf iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE iptables -t nat -L service iptables save systemctl enable iptables --now EOF cat ${USERDATA}
NAT インスタンス用 EC2インスタンスの作成
変数の設定
インスタンスタイプやキーペアなどの情報は、環境に応じて適宜設定します。
INSTANCE_TYPE="t2.micro" KEY_NAME="test-key" SUBNET_ID="subnet-xxxxxxxxxxxxxxxxx" TAG_VALUE="NAT-Instance"
構築処理の実施
なお、本手順では該当の NAT インスタンスに対するセキュリティグループの設定を割愛していますが、正確には、以下の通信が行える必要があります。
- インバウンド:該当の NAT インスタンスを経由するインスタンスからのすべてのトラフィック
- アウトバウンド:0.0.0.0/0 へのすべてのトラフィック
aws ec2 run-instances \ --instance-type ${INSTANCE_TYPE} \ --key-name ${KEY_NAME} \ --subnet-id ${SUBNET_ID} \ --user-data file://${USERDATA} \ --tag-specifications "ResourceType=instance,Tags=[{Key=Name,Value=${TAG_VALUE}}]" \ --associate-public-ip-address \ --image-id ${AMI_ID}
NAT インスタンスの ENI の送信先チェックの無効化
NAT インスタンスのインスタンス ID の取得
INSTANCE_ID=$(aws ec2 describe-instances \ --filters "Name=tag-value,Values=NAT-Instance" \ --query "Reservations[].Instances[].[LaunchTime, InstanceId]" \ --output text | sort | tail -n 1 | awk -F ' ' '{print $2}') \ && echo ${INSTANCE_ID}
【注意!】
一応、tag の値に重複があった場合に備え、tag の値で取得してソートした結果を取得していますが、状況に応じて適宜調整が必要です。
NAT インスタンスの ENI の送信先チェックの無効化
aws ec2 modify-instance-attribute \ --no-source-dest-check \ --instance-id ${INSTANCE_ID}
プライベートサブネット側 ルートテーブルへの反映
変数の設定
ROUTE_TABLE_ID="rtb-xxxxxxxxxxxxxxxxx" DESTINATION_CIDR_BLOCK="0.0.0.0/0"
ルートテーブルへのルートの作成
プライベートサブネット用のルートテーブルには、インターネット向けのルート設定が存在しない前提で、create-route
サブコマンドの実行を行なっています。
aws ec2 create-route \ --route-table-id ${ROUTE_TABLE_ID} \ --destination-cidr-block ${DESTINATION_CIDR_BLOCK} \ --instance-id ${INSTANCE_ID}
【注意!】
なお、前述の通り、既存のインターネット向けのルートが存在しない前提のコマンドとなっています。
既存のルートがある場合は、replace-route
サブコマンドの利用への切り替えの検討が必要です。
終わりに
上記の通り、やっていることは複雑ではありませんが、手順の内容は、あくまで検証用途として必要最低限 NAT インスタンスとして動作すれば良い、という観点で作成しています。
本番環境ではもちろん NAT ゲートウェイのご利用が望ましいことは言うまでもありませんが、検証用途や一時利用でない目的で NAT インスタンスのご利用を検討される場合は、ご留意ください。
市野 和明 (記事一覧)
マネージドサービス部・テクニカルサポート課
お客様から寄せられたご質問や技術検証を通じて得られた気づきを投稿していきます。
情シスだった前職までの経験で、UI がコロコロ変わる AWS においては GUI で手順を残していると画面構成が変わってしまって後々まごつくことが多かった経験から、極力変わりにくい AWS CLI での記事が多めです。
X(Twitter):@kazzpapa3(AWS Community Builder)