VPC エンドポイントで S3 にプライベート接続する

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

はじめに

プライベートな配送アプリケーションは NAT 経由で S3 のマニフェストを読み取っています。一般的な Internet アクセスなしで動くサービス専用経路が必要です。S3 ゲートウェイエンドポイントを作成し、実際の要求を比較して、誤った関連付けを診断し、提供されたネットワークを復元します。

先に Give a Private Subnet Outbound Access を完了してください。この新しい環境は独立したアプリケーション、S3 オブジェクト、パブリックとプライベートのサブネット、NAT ゲートウェイ、安全規則を提供します。CLI は設定済みです。これらと参照ネットワークを維持し、自分のエンドポイントだけを作成・削除してください。一時的に削除するプライベート NAT デフォルトルートは復元します。

認定試験との関連

次の試験範囲に対する基礎演習です。

プライベートアプリケーション用の S3 エンドポイントを作成する

現在の NAT 経路を確認し、S3 のアドレス範囲を調べて、プライベートテーブル用のエンドポイントを作成します。

Terminal でコマンドを実行し、隣に AWS View を開きます。アプリケーションのアドレスは 10.20.2.10 です。提供された parcel-delivery-storage バケットの message.txt には Parcel manifest ready が入っています。

cd /home/labex/project

Name タグで VPC を選択します。フィルターはリソースを選び、クエリは ID を取り出し、$(...) はそれを変数に保存します。

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

プライベートとパブリックのテーブル ID を保存します。サブネットとの関連付けは正しく設定済みです。

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)
PUBLIC_RT_ID=$(aws ec2 describe-route-tables \
  --filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=public-routes \
  --query 'RouteTables[0].RouteTableId' \
  --output text)

両方のルートと関連付けを読み取ります。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes,Associations:Associations}' \
  --output json

プライベートの 0.0.0.0/0 は提供された NAT を、パブリックのデフォルトルートは Internet ゲートウェイを指します。両方に local が残ります。復元用に NAT ID を保存します。

NAT_ID=$(aws ec2 describe-nat-gateways \
  --filter "Name=vpc-id,Values=$VPC_ID" Name=state,Values=available \
  --query 'NatGateways[0].NatGatewayId' \
  --output text)

要求結果と比較するためアドレスを確認します。

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

AWS View の Read storage object をクリックします。Success とマニフェストが返り、Source address は NAT のパブリックアドレスです。Request outbound service も同じ NAT アドレスで成功します。最後にこの初期動作へ戻します。

AWS マネージドプレフィックスリストはリージョン内のサービスのネットワーク範囲をまとめます。S3 ゲートウェイエンドポイントは関連テーブルにそのリストへのルートを追加します。アプリケーションにパブリックアドレスを付けたり、一般的な Internet 接続を提供したりはしません。S3 リストと IPv4 範囲を確認します。

PREFIX_ID=$(aws ec2 describe-prefix-lists \
  --filters Name=prefix-list-name,Values=com.amazonaws.us-east-1.s3 \
  --query 'PrefixLists[0].PrefixListId' \
  --output text)
aws ec2 get-managed-prefix-list-entries \
  --prefix-list-id "$PREFIX_ID" \
  --query 'Entries[].Cidr' \
  --output json

us-east-1 の S3 用エンドポイントを作り、プライベートテーブルだけに関連付けます。--vpc-endpoint-type Gateway はルートベースの種類、--service-name はリージョンのサービス、--route-table-ids はアプリケーションのテーブルを指定します。タグで自分の練習リソースを識別します。

ENDPOINT_ID=$(aws ec2 create-vpc-endpoint \
  --vpc-id "$VPC_ID" \
  --vpc-endpoint-type Gateway \
  --service-name com.amazonaws.us-east-1.s3 \
  --route-table-ids "$PRIVATE_RT_ID" \
  --tag-specifications 'ResourceType=vpc-endpoint,Tags=[{Key=Name,Value=parcel-s3-endpoint},{Key=Project,Value=parcel}]' \
  --query 'VpcEndpoint.VpcEndpointId' \
  --output text)

状態と関連付けを読み取ります。

aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids "$ENDPOINT_ID" \
  --query 'VpcEndpoints[].{ID:VpcEndpointId,State:State,Type:VpcEndpointType,Service:ServiceName,Tables:RouteTableIds}' \
  --output json

State が available になったら進みます。未完了なら数秒待ち、同じクエリを繰り返してください。種類は Gateway、サービスは S3、関連テーブルはプライベートだけです。変数を保持するため Terminal は開いたままにします。

再度 Read storage object をクリックします。内容は同じですが、送信元は 10.20.2.10 です。S3 プレフィックスルートは NAT デフォルトより具体的なので、S3 はエンドポイントを、通常の外向き通信は NAT を使います。

NAT デフォルトルートなしで S3 を読み取る

一般的な外向き経路を削除し、サービス専用経路を検証します。

プライベート NAT デフォルトルートだけを削除します。NAT 本体、アドレス、パブリックルート、エンドポイントは維持します。

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

local と S3 の DestinationPrefixListId ルートは残り、デフォルトルートはありません。GatewayId はエンドポイント ID、状態は active です。このルートはエンドポイント関連付けで管理するため、通常のルートコマンドで編集・削除しません。

Read storage object の新しい要求は Parcel manifest ready と 10.20.2.10 を返します。Request outbound service は失敗します。198.51.100.20:9000 は S3 プレフィックス外で、デフォルト経路もないためです。Request private application from outside も失敗します。エンドポイントは S3 のプライベート接続だけを提供します。

NAT デフォルトルートなしで S3 を読むプライベートアプリケーション

例ではプライベートテーブルに local と S3 プレフィックスだけがあり、0.0.0.0/0 はありません。実際の応答は元のマニフェストと送信元 10.20.2.10 を含みます。NAT は利用可能ですが、この S3 経路には入りません。生成 ID やアドレスは異なる場合があります。

誤ったテーブルへの関連付けを観察する

エンドポイントをアプリケーションのテーブルから外し、利用可能でも到達不能になる理由を確認します。

エンドポイントとテーブルの関連付けは、サブネットとテーブルの関連付けとは別です。前者だけを変更します。

aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id "$ENDPOINT_ID" \
  --add-route-table-ids "$PUBLIC_RT_ID" \
  --remove-route-table-ids "$PRIVATE_RT_ID"

Return: true が返ります。エンドポイントを確認します。

aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids "$ENDPOINT_ID" \
  --query 'VpcEndpoints[].{State:State,Tables:RouteTableIds}' \
  --output json

状態は available ですが、パブリックテーブルだけです。両テーブルを確認します。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes,Associations:Associations}' \
  --output json

自動 S3 ルートはパブリック側に移り、プライベート側には local だけが残ります。元のサブネット関連付けは変わりません。同じ VPC にあるだけで、すべてのサブネットが同じエンドポイント経路を使えるわけではありません。

AWS View に変更が表示されたら Read storage object をクリックします。新しい要求は Connection failed と Storage unavailable です。アプリケーションのテーブルに S3 経路がありません。Request outbound service も失敗します。以前の成功は過去の結果です。このステップのチェックのため故障を残し、次で修復します。

プライベートなサービス経路を復元する

再作成、パブリックアドレス追加、NAT デフォルト復元なしで関連付けを修復します。

同じエンドポイントをプライベートに戻し、パブリックとの関連を外します。

aws ec2 modify-vpc-endpoint \
  --vpc-endpoint-id "$ENDPOINT_ID" \
  --add-route-table-ids "$PRIVATE_RT_ID" \
  --remove-route-table-ids "$PUBLIC_RT_ID"

関連付けを確認します。

aws ec2 describe-vpc-endpoints \
  --vpc-endpoint-ids "$ENDPOINT_ID" \
  --query 'VpcEndpoints[].{State:State,Tables:RouteTableIds}' \
  --output json

プライベートだけが表示されるはずです。ルートを確認します。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes}' \
  --output json

プライベート S3 ルートが自動復元され、パブリック側から消えます。パブリック Internet ルートは残り、プライベートのデフォルトは依然ありません。

新しい Read storage object は元のマニフェストと 10.20.2.10 を返します。S3 エンドポイントは一般的な Internet を提供しないので Request outbound service は失敗したままです。Request private application from outside も遮断されます。私有アドレスと提供された安全規則は保たれます。

エンドポイントを削除して NAT の初期状態に戻す

自分のエンドポイントと自動ルートを削除し、提供 NAT へのプライベートデフォルトルートを戻します。

自分のエンドポイントだけを削除します。

aws ec2 delete-vpc-endpoints --vpc-endpoint-ids "$ENDPOINT_ID"

Unsuccessful は空でなければなりません。削除可能なタグで絞らず、全エンドポイント一覧を確認します。

aws ec2 describe-vpc-endpoints \
  --query 'VpcEndpoints[].{ID:VpcEndpointId,State:State,Tables:RouteTableIds}' \
  --output json

deleted の記録が残る場合がありますが、活動中の練習エンドポイントは残せません。削除記録は転送しません。deleting なら数秒待って同じクエリを繰り返します。両テーブルを読み取ります。

aws ec2 describe-route-tables \
  --route-table-ids "$PRIVATE_RT_ID" "$PUBLIC_RT_ID" \
  --query 'RouteTables[].{ID:RouteTableId,Routes:Routes}' \
  --output json

両方から S3 プレフィックスが消えているはずです。Read storage object はプライベート側が local だけの間、失敗します。隠れた代替経路を残していないことを確認できます。

保存した NAT ID へデフォルトルートを戻します。提供 NAT、アドレス、アプリケーション、S3 データを削除しないでください。

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

local と活動中の NAT デフォルトが初期状態に一致します。一覧取得の失敗は削除証明ではありません。認証済みクエリが成功し、不在または deleted と自動ルート削除を確認する必要があります。

再度 Read storage object をクリックすると NAT 経由で元のマニフェストが返り、Source address は NAT のパブリックアドレスになります。Request outbound service も同じアドレスで成功し、Request private application from outside は遮断されたままです。VPC、サブネット、NAT、安全規則、S3 オブジェクト、参照ネットワークを維持します。

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

まとめ

S3 エンドポイントで、私有送信元を保持する実際の読み取りを確認しました。NAT デフォルト削除後も S3 は利用でき、他の宛先は遮断されました。誤ったパブリック関連付けで失敗し、私有関連付けの修復でアプリケーションや安全規則を変えず復旧しました。

エンドポイントと自動ルートを削除し、NAT を復元しました。