プライベートサブネットにアウトバウンドアクセスを提供する

AWSBeginner
オンラインで実践に進む

はじめに

配送アプリケーションはプライベートサブネットで動作し、パブリックアドレスを持たずに外部サービスへ接続する必要があります。パブリック NAT ゲートウェイと送信ルートを作成し、実際の HTTP リクエストで送信元アドレス変換と、外部から開始される受信接続の隔離を確認します。

先に Control Application Access with Security Groups を完了してください。この新しい環境は独自のアプリケーション、パブリック・プライベートサブネット、パブリックの Internet ルート、安全ルールを提供し、CLI も設定済みです。これらと無関係な参照ネットワークを保持してください。自分の NAT ゲートウェイ、Elastic IP、プライベートのデフォルトルートだけを作成し、最後に削除します。

認定試験との関連

この実験では以下の試験分野を実践します。

プライベートアプリケーションの確認と NAT アドレスの割り当て

提供されたネットワークを調べ、送信経路がない状態を確認し、これから作成する NAT ゲートウェイのアドレスを割り当てます。

CLI コマンドには Terminal を使い、その隣で AWS View を開きます。ビューは同じリソース状態を読み取ります。アプリケーションは public-subnet ではなく private-subnet にあり、プライベート IPv4 アドレスは 10.20.2.10 です。

cd /home/labex/project

Name タグでアプリケーション VPC を選択します。--filters は結果を絞り、--query は ID を選択し、$(...) はシェル変数に保存します。

VPC_ID=$(aws ec2 describe-vpcs \
  --filters Name=tag:Name,Values=application-network \
  --query 'Vpcs[0].VpcId' \
  --output text)

この VPC のパブリックサブネットを選択します。NAT ゲートウェイはここで Internet への経路を持ちます。

PUBLIC_SUBNET_ID=$(aws ec2 describe-subnets \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=public-subnet \
  --query 'Subnets[0].SubnetId' \
  --output text)

プライベートサブネットの既存のルートテーブルを選択します。サブネットとの関連付けを維持したまま、このテーブルのデフォルトルートを変更します。

PRIVATE_RT_ID=$(aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=private-routes \
  --query 'RouteTables[0].RouteTableId' \
  --output text)

提供された両方のテーブルを確認します。[]. の後の投影は各テーブルから読みやすいフィールドを選択します。

aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=$VPC_ID" \
  --query 'RouteTables[].{Name:Tags[?Key==`Name`].Value|[0],Routes:Routes,Associations:Associations}' \
  --output json

名前付きの両テーブルには VPC の local ルートがあります。名前のないメインテーブルが表示されても変更しないでください。名前付きテーブルは明示的にサブネットへ関連付けられているため、選択した private-routes を使用します。パブリックテーブルは 0.0.0.0/0 を Internet ゲートウェイへルーティングしますが、プライベートテーブルにデフォルトルートはありません。プライベートサブネットには Internet ゲートウェイへの直接のルートがありません。パブリック NAT ゲートウェイは、プライベートアプリケーションがゲートウェイのパブリックアドレスで IPv4 接続を開始できるようにします。自身の Internet ルートが提供済みのパブリックサブネットに配置します。

AWS View で Request outbound service をクリックします。外部サービス 198.51.100.20:9000 へのルートがないため、プライベートアプリケーションの HTTP リクエストは Connection failed になります。Request private application from outside もクリックします。外部から 10.20.2.10:80 への新規 HTTP 接続も失敗します。アプリケーションのプライベートアドレスは維持されます。

Elastic IP アドレスは割り当てられたパブリック IPv4 アドレスです。VPC ドメインで割り当て、練習リソースを識別できるタグを付けます。引用符で囲まれた --tag-specifications の値は、リソースの種類とタグを記述する単一の引数です。

ALLOCATION_ID=$(aws ec2 allocate-address \
  --domain vpc \
  --tag-specifications 'ResourceType=elastic-ip,Tags=[{Key=Name,Value=parcel-nat-address},{Key=Project,Value=parcel}]' \
  --query 'AllocationId' \
  --output text)

割り当てたアドレスを確認します。

aws ec2 describe-addresses \
  --allocation-ids "$ALLOCATION_ID" \
  --query 'Addresses[].{Allocation:AllocationId,PublicIP:PublicIp,Domain:Domain}' \
  --output table

結果には割り当て ID、パブリック IPv4 アドレス、ドメイン vpc が含まれます。後の通信比較のためパブリックアドレスを記録してください。これは将来の NAT のアドレスなのでアプリケーションへ関連付けません。保存した ID を使えるよう、この Terminal は開いたままにします。

パブリック NAT ゲートウェイの作成

パブリックサブネットに NAT を配置し、作成だけではプライベートアプリケーションのルートが設定されないことを確認します。

NAT は既存のパブリックサブネットと割り当て済み Elastic IP を必要とします。--subnet-id は配置先、--allocation-id はパブリックアドレス、--connectivity-type public は Internet 向けゲートウェイを選択します。リソース種類 natgateway で所有タグを適用し、生成された ID を保存します。

NAT_ID=$(aws ec2 create-nat-gateway \
  --subnet-id "$PUBLIC_SUBNET_ID" \
  --allocation-id "$ALLOCATION_ID" \
  --connectivity-type public \
  --tag-specifications 'ResourceType=natgateway,Tags=[{Key=Name,Value=parcel-nat},{Key=Project,Value=parcel}]' \
  --query 'NatGateway.NatGatewayId' \
  --output text)

作成要求はゲートウェイの準備前に戻ることがあります。CLI の waiter は指定された条件を満たすまで状態を繰り返し読み取ります。ルート追加前に available を待ちます。

aws ec2 wait nat-gateway-available --nat-gateway-ids "$NAT_ID"

waiter は成功すると出力なしで終了します。状態、サブネット、アドレスの関連付けを確認します。

aws ec2 describe-nat-gateways \
  --nat-gateway-ids "$NAT_ID" \
  --query 'NatGateways[].{ID:NatGatewayId,State:State,Subnet:SubnetId,Addresses:NatGatewayAddresses}' \
  --output json

State は available、Subnet は選択したパブリックサブネットと一致し、NatGatewayAddresses に割り当て ID とパブリックアドレスが含まれます。PrivateIp はパブリックサブネットの 10.20.1.0/24 内のアドレスです。これは NAT インターフェースのプライベートアドレスで、Elastic IP やアプリケーションのアドレスとは異なります。NAT は独立したリソースであり、プライベートアプリケーションがこのアドレスを取得したわけではありません。

AWS View に NAT が表示されます。再度 Request outbound service をクリックしてください。プライベートテーブルにデフォルトルートがないため、まだ失敗します。ゲートウェイの作成は利用可能な次のホップを提供するだけで、プライベートサブネットで自動選択しません。パブリックテーブルの既存 Internet ゲートウェイルートは変更されません。

NAT 経由でプライベートの送信トラフィックをルーティング

プライベートのデフォルトルートを追加し、アプリケーションのプライベートアドレスと外部サービスが観測した送信元を比較します。

ルートは宛先範囲の次のホップを選びます。0.0.0.0/0 は、より具体的なルートに一致しない IPv4 宛先に一致します。--nat-gateway-id は Internet ゲートウェイではなく自分の NAT を選択します。保存したプライベートテーブルだけに追加します。

aws ec2 create-route \
  --route-table-id "$PRIVATE_RT_ID" \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id "$NAT_ID"

応答は作成成功を示します。プライベートテーブルのルートを読み取ります。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" \
  --query 'RouteTables[].Routes' \
  --output json

ローカルルートは残ります。新しいデフォルトルートは自分の NatGatewayId を持ち、状態は active です。パケットは、プライベートアプリケーション → パブリックサブネットの NAT → Internet ゲートウェイ → 外部サービスの順に進みます。

AWS View にプライベートのデフォルトルートが表示されたら Request outbound service をクリックします。Success が返り、本文は外部 HTTP サービスが実際に観測した送信元 IPv4 アドレスです。割り当てたパブリックアドレスと比較します。

aws ec2 describe-addresses \
  --allocation-ids "$ALLOCATION_ID" \
  --query 'Addresses[0].PublicIp' \
  --output text

両者は一致します。ネットワークアドレス変換(NAT)はアプリケーションのプライベート送信元をゲートウェイのパブリックアドレスへ置き換え、接続を追跡して開始元に応答を返します。アプリケーション自身のアドレスは 10.20.2.10 のままです。

プライベートアプリケーションが NAT ルートで外部サービスへ接続

AWS View の例:アプリケーションは 10.20.2.10 のまま、プライベートのデフォルトルートは使用可能な NAT を選び、HTTP 本文は割り当てたパブリックアドレスを示します。生成されるリソース ID やアドレスは異なる場合があります。

Request private application from outside をクリックします。引き続き Connection failed です。送信接続とその応答によって、プライベートアプリケーションへのパブリック受信経路は作られません。NAT は、このアプリケーションへの外部から開始される Internet 接続を受け付けません。

欠落したプライベートルートの診断と復元

ルートを一つ削除して失敗を観察し、NAT を再作成せず接続を復元します。

ゲートウェイが利用可能でも、クライアントに利用できるルートがないことがあります。NAT とパブリック Internet ルートを維持し、プライベートのデフォルトルートだけを削除します。

aws ec2 delete-route --route-table-id "$PRIVATE_RT_ID" --destination-cidr-block 0.0.0.0/0

成功した削除には出力がありません。プライベートテーブルを確認します。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" \
  --query 'RouteTables[].Routes' \
  --output json

VPC のローカルルートだけが残ります。AWS View は利用可能な NAT を示しますが、プライベートのデフォルトルートはありません。Request outbound service をクリックすると、新しいリクエストは失敗します。以前の成功は過去の記録であり、新しいリクエストの結果ではありません。

同じゲートウェイへの同じルートを復元します。

aws ec2 create-route \
  --route-table-id "$PRIVATE_RT_ID" \
  --destination-cidr-block 0.0.0.0/0 \
  --nat-gateway-id "$NAT_ID"

再びルートを読み取ります。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" \
  --query 'RouteTables[].Routes' \
  --output json

有効なデフォルトルートが戻ります。AWS View で新しい Request outbound service を送ると成功し、同じ NAT パブリックアドレスを返します。Request private application from outside は失敗し続けます。この観察でゲートウェイの可用性と完全なクライアント経路を区別できます。

練習用 NAT 経路の削除とアドレスの解放

自分のルートと NAT を削除し、パブリックアドレスを解放して、提供されたプライベートネットワークが維持されていることを確認します。

次のホップを削除する前にプライベートのデフォルトルートを削除します。逆順では、削除済みゲートウェイへのルートが残る可能性があります。

aws ec2 delete-route --route-table-id "$PRIVATE_RT_ID" --destination-cidr-block 0.0.0.0/0

成功した削除には出力がありません。自分の NAT だけを削除します。

aws ec2 delete-nat-gateway --nat-gateway-id "$NAT_ID"

応答は要求したゲートウェイを識別します。アドレス解放前に削除 waiter を使います。

aws ec2 wait nat-gateway-deleted --nat-gateway-ids "$NAT_ID"

waiter は成功すると出力なしで戻ります。NAT の削除はネットワークインターフェースを削除し、Elastic IP の関連付けを解除しますが、割り当てを解放しません。解放前にアドレスを確認します。

aws ec2 describe-addresses \
  --allocation-ids "$ALLOCATION_ID" \
  --query 'Addresses[].{Allocation:AllocationId,PublicIP:PublicIp,Association:AssociationId}' \
  --output json

割り当てとパブリックアドレスは残り、Association は null です。アドレスは割り当て済みですが、接続されていません。この独立したリソースを解放します。

aws ec2 release-address --allocation-id "$ALLOCATION_ID"

解放成功時には出力がありません。削除可能なタグに頼らず、ゲートウェイの完全な一覧を読みます。

aws ec2 describe-nat-gateways \
  --query 'NatGateways[].{ID:NatGatewayId,State:State,Subnet:SubnetId}' \
  --output table

ゲートウェイは deleted 状態で一覧に残る場合がありますが、活動中の練習 NAT はあってはいけません。削除記録が残っていても転送はできません。アドレスの完全な一覧を確認します。

aws ec2 describe-addresses \
  --query 'Addresses[].{Allocation:AllocationId,PublicIP:PublicIp}' \
  --output table

練習アドレスの割り当てはありません。次にプライベートルートを読みます。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" \
  --query 'RouteTables[].Routes' \
  --output json

VPC のローカルルートは維持され、デフォルトルートはありません。提供されたアプリケーション、サブネット、安全ルール、パブリック Internet ゲートウェイ、参照ネットワークは維持されています。一覧取得の失敗は削除の証明にはなりません。

AWS View で Request outbound service をクリックします。意図的に NAT 経路を削除したため再び失敗します。Request private application from outside も遮断されたままです。結果は初期のプライベートネットワーク状態と一致します。

このステップの完了チェックを実行してください。

まとめ

パブリックアドレスを割り当て、パブリックサブネットに NAT を配置し、プライベートアプリケーションの送信リクエストをルーティングしました。外部サービスは変換後の NAT アドレスを観測し、外部から開始される受信接続は遮断されたままでした。プライベートのデフォルトルートを削除・復元することで、ゲートウェイの可用性だけでは接続できない理由を確認しました。

その後ルートと NAT を削除し、アドレスを解放して、初期プライベートネットワークの維持を検証しました。