インフラエンジニアに贈るAmazon VPC入門 #4 インターネット接続(後編)

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

シリーズの目次は<a href="/series/vpcfor-infra-engineer/">こちら</a><br>
<a href="/cloud/vpcfor-infra-engineer-3/">前回</a>からだいぶ間があいてしまいましたが、GW中に記事を書く時間がとれたので続編書きます!! 

前回のあらすじ

前回は、VPCからインターネットに接続するための機能をご紹介ということで、インターネットゲートウェイとElastic IPを紹介しました。ざっくり以下にまとめます。

  • VPC→インターネット : インターネットゲートウェイ経由で接続できる(ただしIPマスカレードはないため、インターネット→VPCへの接続はできない)
  • インターネット→VPC : Elastic IPをインターネットゲートウェイで持ち、Static NATを構成して仮想マシンにトラフィックを転送する

Elastic IP(Static NAT)はインターネットに公開するサーバー向け、今回紹介するNATインスタンスは、仮想マシンからインターネットに接続するクライアント向けとご紹介しました。では、NATインスタンスでどのようにインターネット接続を提供するのか、見ていきましょう。

NATインスタンスの動作

NATインスタンスは、IPマスカレードによってVPCの仮想マシンにインターネット接続を提供します。実際の動作は、仮想ルーター、Elastic IPを組み合わせる複雑な動きになります。
仮想マシンからNATインスタンスを介してインターネットに接続する一連の動きを、以下に示します。

vpc_nat1

  1. 仮想マシンのルーティングテーブルにより、デフォルトゲートウェイの仮想ルーターにトラフィックを転送
  2. 仮想マシンの所属するVPCサブネットのルーティングテーブルにより、仮想ルーターがNATインスタンスにトラフィックを転送
  3. NATインスタンスでIPマスカレード処理を実行(送信元IPアドレスをNATインスタンスのIPアドレスに変更)
  4. NATインスタンスのルーティングテーブルにより、デフォルトゲートウェイの仮想ルーターにトラフィックを転送
  5. NATインスタンスの所属するVPCサブネットのルーティングテーブルにより、仮想ルーターがインターネットゲートウェイにトラフィックを転送
  6. インターネットゲートウェイでStatic NAT処理を実行(送信元IPアドレスをNATインスタンスのEIPに変更)
  7. インターネットゲートウェイがインターネットの接続先にトラフィックを転送

個人的には、このNATインスタンスの実装は、あまり好きではありません。動きがややこしいですし、ユーザーが自分でNATインスタンスの管理をしなければならないのも煩雑な印象を受けます。VPCのネットワークサービスの一つとして提供される機能であれば、ユーザーからはなるべく抽象化され仮想マシンとして意識されないようにするべきと考えます。

ただ、ユーザーから仮想マシンとして見える分、機能・実装が具体的に把握できる点やカスタマイズ性が高い点は良いとも思っています。

NATインスタンスの実装とカスタマイズ

NATインスタンスの実装

一言で言ってしまうと、仮想マシンでは、Linuxパケットフィルタ(iptables)のNATテーブルでIPマスカレードを動作させています。 例として、標準のNATインスタンス(Amazonの仮想マシンイメージ(AMI)として提供)のコマンドの実行結果を紹介します。

[ec2-user@ip-XX-XX-XX-XX ~]$ sudo iptables -t nat -L -v -n
Chain PREROUTING (policy ACCEPT 1 packets, 64 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 30 packets, 2443 bytes)
 pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 0 packets, 0 bytes)
 pkts bytes target     prot opt in     out     source               destination
   30  2443 MASQUERADE  all  --  *      eth0    XX.XX.0.0/16        0.0.0.0/0

IPマスカレードが動作している様子がわかります。一般的なLinuxルーターと雰囲気が異なるのは、NATインスタンスには仮想NIC(ENI)が1つしか構成されないため、outのインターフェース名ではなくsourceのネットワークアドレス(実行例では、NATインスタンスの所属するVPCサブネットのアドレス)でIPマスカレードの対象を特定しているところでしょうか。

また、OS起動時のこのルールの追加は割と原始的な仕組みで、RedHat系ディストリビューションでのiptablesのお作法(/etc/sysconfig/iptablesファイル)ではなく、/etc/rc.localファイルからiptablesコマンドを叩くスクリプトを呼び出すようになっています。

  • /etc/rc.local
#!/bin/sh
#
# This script will be executed *after* all the other init scripts.
# You can put your own initialization stuff in here if you don't
# want to do the full Sys V style init stuff.

touch /var/lock/subsys/local

# Configure PAT
/usr/local/sbin/configure-pat.sh
  • /usr/local/sbin/configure-pat.sh
#!/bin/bash

# Configure the instance to run as a Port Address Translator (PAT) to provide
# Internet connectivity to private instances.
#

set -x
echo "Determining the MAC address on eth0"
ETH0_MAC=`/sbin/ifconfig  | /bin/grep eth0 | awk '{print tolower($5)}' | grep '^[0-9a-f]\{2\}\(:[0-9a-f]\{2\}\)\{5\}$'`
if [ $? -ne 0 ] ; then
   echo "Unable to determine MAC address on eth0" | logger -t "ec2"
   exit 1
fi
echo "Found MAC: ${ETH0_MAC} on eth0" | logger -t "ec2"


VPC_CIDR_URI="http://169.254.169.254/latest/meta-data/network/interfaces/macs/${ETH0_MAC}/vpc-ipv4-cidr-block"
echo "Metadata location for vpc ipv4 range: ${VPC_CIDR_URI}" | logger -t "ec2"


VPC_CIDR_RANGE=`curl --retry 3 --retry-delay 0 --silent --fail ${VPC_CIDR_URI}`
if [ $? -ne 0 ] ; then
   echo "Unable to retrive VPC CIDR range from meta-data. Using 0.0.0.0/0 instead. PAT may not function correctly" | logger -t "ec2"
   VPC_CIDR_RANGE="0.0.0.0/0"
else
   echo "Retrived the VPC CIDR range: ${VPC_CIDR_RANGE} from meta-data" |logger -t "ec2"
fi

echo 1 >  /proc/sys/net/ipv4/ip_forward && \
   echo 0 >  /proc/sys/net/ipv4/conf/eth0/send_redirects && \
   /sbin/iptables -t nat -A POSTROUTING -o eth0 -s ${VPC_CIDR_RANGE} -j MASQUERADE

if [ $? -ne 0 ] ; then
   echo "Configuration of PAT failed" | logger -t "ec2"
   exit 0
fi

echo "Configuration of PAT complete" |logger -t "ec2"
exit 0
[ec2-user@ip-XX-XX-XX-XX etc]$

それからもう一つ、注意するべき設定としてAWS特有のSource/Dest. Checkがあります。仮想マシンが送受信するトラフィックの宛て先IPアドレス、送信元IPアドレスをチェックし、仮想マシンのIPアドレスでなければフィルタするはたらきを持ちます *1。既定値がEnable(有効)なので、NATインスタンスとして使用するためにはDisable(無効)に変更する必要があります。

vpc_nat2

NATインスタンスのT具体的な構築手順は、横田さんの記事をご覧ください。

カスタマイズ

IPマスカレードの機能を提供しSource/Dest. CheckをDisableにすれば、好みの仮想マシン(EC2インスタンス)をNATインスタンスとして使うことも可能です。また、AWSの他の機能と組み合わせる構成もアリです。先人の実装例を以下に示します。

まとめと次回予告

今回は、仮想マシンにインターネット接続を提供する仕組みとして、NATインスタンスの動作、実装を紹介しました。NATインスタンス自体はただのLinuxなので、簡単に実装を確認したり、必要に応じてカスタマイズができることを理解いただけたのではないでしょうか。
次回は先送りになっていました、DNSを取り上げます!

脚注

  1. Linux OSで言うところのnet.ipv4.ip_forwardを、仮想マシンの外部から制御するイメージです。