はじめに
配送アプリケーションのパブリックアクセス経路はすでに動作していますが、用意済みのアクセスルールでは、すべての IPv4 送信元から HTTP を許可しています。アプリケーションに専用のセキュリティグループを割り当て、想定するクライアントとポートだけを許可します。実際のリクエストで、送信元・ポートの制限とステートフルな応答がアクセスに与える影響を確認します。
先に「パブリックサブネットをインターネットに接続する」を完了してください。この新しい環境には専用のネットワーク、パブリックアドレス、ルート、アプリケーションが用意され、以前の VM は再利用しません。CLI は設定済みです。用意済みのリソースと、演習に無関係な参照ネットワークを維持してください。削除する練習用リソースは、新しく作るセキュリティグループだけです。
認定試験との関連
この実験では、次の試験項目を実践します。
- Cloud Practitioner (CLF-C02) · タスク 3.5:VPC のセキュリティグループによるアクセス制御。
- Solutions Architect – Associate (SAA-C03) · タスク 1.2:ネットワークの送信元、ポート、プロトコルに対する基本的なアプリケーションセキュリティ制御。
- CloudOps Engineer – Associate (SOA-C03) · タスク 5.1 と 5.3:基本的なセキュリティグループ設定と接続性への影響の確認。
- Security – Specialty (SCS-C03) · タスク 3.3:セキュリティグループで必要なトラフィックを許可・拒否する基礎演習。
空の練習用セキュリティグループを関連付ける
このステップでは、動作中のアプリケーションを確認し、広いアクセスを許可するグループを自分の空のグループに置き換えます。
コマンドは Terminal で実行し、その隣の AWS View をクリックします。ビューは CLI と同じリソース状態を読み取ります。application-network、そのパブリック・プライベートサブネット、プライベートアドレス 10.20.1.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 内の用意済みアプリケーションインターフェイスを選びます。
ENI_ID=$(aws ec2 describe-network-interfaces \
--filters "Name=vpc-id,Values=$VPC_ID" Name=tag:Name,Values=application-interface \
--query 'NetworkInterfaces[0].NetworkInterfaceId' \
--output text)
セキュリティグループは、関連付けたリソースのネットワークインターフェイスで許可するトラフィックを制御します。インバウンドルールはアプリケーションに到着する通信、アウトバウンドルールはアプリケーションが開始する通信を許可します。後で元に戻せるよう、唯一の用意済みグループの ID を保存します。[0] は、この1グループだけのリストの最初の項目を選びます。
SUPPLIED_GROUP_ID=$(aws ec2 describe-network-interfaces \
--network-interface-ids "$ENI_ID" \
--query 'NetworkInterfaces[0].Groups[0].GroupId' \
--output text)
ルールを変更せずに読み取ります。
aws ec2 describe-security-groups \
--group-ids "$SUPPLIED_GROUP_ID" \
--query 'SecurityGroups[].{ID:GroupId,Inbound:IpPermissions,Outbound:IpPermissionsEgress}' \
--output json
用意済みグループは 0.0.0.0/0、つまりすべての IPv4 送信元からのインバウンド TCP ポート 80 と、すべてのアウトバウンド通信を許可します。HTTP はリクエストとレスポンスを使い、ポートは受信サービスを識別します。このアプリケーションは TCP ポート 80 と 8081 で HTTP を提供しますが、用意済みルールが許可するのは 80 だけです。
AWS View で Request application · client A、続けて Request application · client B をクリックします。どちらもポート 80 で Success と Application online を返します。クライアント A は 198.51.100.10、B は 198.51.100.20 を使います。Request port 8081 をクリックすると、このポートは許可されていないため、クライアント A のリクエストは失敗します。
同じ VPC に別のグループを作ります。--group-name は名前、--description は用途を指定します。引用符で囲んだタグ指定は、所有を識別するタグを1つの引数で追加します。新しい ID を保存します。
GROUP_ID=$(aws ec2 create-security-group \
--group-name parcel-web \
--description "Parcel HTTP access" \
--vpc-id "$VPC_ID" \
--tag-specifications 'ResourceType=security-group,Tags=[{Key=Name,Value=parcel-web},{Key=Project,Value=parcel}]' \
--query 'GroupId' \
--output text)
新しいグループにはインバウンドの許可がなく、すべてのアウトバウンド通信が許可されます。セキュリティグループにあるのは許可ルールで、明示的な拒否ルールではありません。許可ルールに一致しない通信はブロックされます。
--groups はインターフェイスのグループ一覧を置き換えます。新しいグループだけを関連付けます。広いアクセスを許可するグループも残すと、両方の許可が合算され、両クライアントのアクセスが引き続き許可されます。
aws ec2 modify-network-interface-attribute \
--network-interface-id "$ENI_ID" \
--groups "$GROUP_ID"
変更に成功すると出力はありません。自分のグループだけが関連付いていることを確認します。
aws ec2 describe-network-interfaces \
--network-interface-ids "$ENI_ID" \
--query 'NetworkInterfaces[].{ID:NetworkInterfaceId,Groups:Groups}' \
--output json
AWS View に parcel-web と Inbound · none が表示されます。A と B から新しいリクエストを送ると、両方とも Connection failed になります。パブリックアドレスとルートは残っていますが、空のグループはインバウンドリクエストを許可しません。保存した ID を維持するため、この Terminal は開いたままにしてください。
想定する HTTP クライアントだけを許可する
このステップでは、クライアント A にポート 80 へのアクセスを許可し、もう一方の送信元とポートはブロックされることを確認します。
インバウンドルールはプロトコル、ポート範囲、送信元を指定します。--protocol tcp は TCP、--port 80 はこの1ポート、--cidr 198.51.100.10/32 はクライアント A の IPv4 アドレスだけを選びます。/32 は1つの IPv4 アドレスを含み、0.0.0.0/0 より限定的です。
用意済みグループではなく、自分のグループにルールを追加します。
aws ec2 authorize-security-group-ingress \
--group-id "$GROUP_ID" \
--protocol tcp \
--port 80 \
--cidr 198.51.100.10/32
応答は成功を示し、新しいルール ID が含まれる場合があります。すべてのインバウンドルールを読み取ります。
aws ec2 describe-security-groups \
--group-ids "$GROUP_ID" \
--query 'SecurityGroups[].IpPermissions' \
--output json
TCP ルールが1つあり、FromPort と ToPort は両方 80、送信元は 198.51.100.10/32 です。AWS View も同じ送信元とポートを表示します。
Request application · client A をクリックします。結果は Success、送信元 198.51.100.10、宛先ポート 80、本文 Application online です。これは用意済みアプリケーションからの実際のレスポンスです。
次に Request application · client B と Request port 8081 をクリックします。両方とも Connection failed です。最初は送信元が不一致、次は A からでもポートが不一致です。パブリックアドレスとルートが経路を提供し、セキュリティグループがその経路を使える通信を決めます。
一時的なポート許可を試して削除する
このステップでは、2つ目の待受ポートが専用ルールのある場合だけ到達可能になることを示し、一時的な許可を削除します。
用意済みアプリケーションはポート 8081 でも HTTP を提供します。許可する送信元はそのままに、このポート用の一時的なルールを追加します。
aws ec2 authorize-security-group-ingress \
--group-id "$GROUP_ID" \
--protocol tcp \
--port 8081 \
--cidr 198.51.100.10/32
ルールをもう一度読み取ります。
aws ec2 describe-security-groups \
--group-ids "$GROUP_ID" \
--query 'SecurityGroups[].IpPermissions' \
--output json
TCP ルールは 80 と 8081 の2つになり、どちらもクライアント A のみを許可します。AWS View に両方が表示されます。Request port 8081 をクリックすると、結果は Success、宛先ポート 8081、本文 Application online に変わります。2つ目のサービスは動作しており、以前の失敗はアクセスルールの制限だったと確認できます。

AWS View の例:限定的なインバウンドルールが2つ存在し、A はポート 8081 でアプリケーションの応答を受け取ります。生成されるリソース ID は環境によって異なります。
この演習で必要なのはポート 80 だけです。ルールの取り消しは、その許可を削除します。同じプロトコル、ポート、送信元を指定し、一時的なルールだけを削除します。
aws ec2 revoke-security-group-ingress \
--group-id "$GROUP_ID" \
--protocol tcp \
--port 8081 \
--cidr 198.51.100.10/32
応答は成功を示します。変更後のルールを問い合わせます。
aws ec2 describe-security-groups \
--group-ids "$GROUP_ID" \
--query 'SecurityGroups[].IpPermissions' \
--output json
A のポート 80 ルールだけが残ります。AWS View から 8081 ルールが消えたら、再度 Request port 8081 をクリックします。今度は失敗します。A の 80 は引き続き成功し、B の 80 は引き続き失敗します。アプリケーションやルートは置き換えず、1つのポート許可だけを変更しました。
ステートフルな HTTP 応答を観察する
このステップでは、自分のグループの既定アウトバウンドルールを削除し、許可されたインバウンド HTTP への応答が引き続き機能することを確認します。
セキュリティグループはステートフルです。許可されたインバウンドリクエストへの応答は、新しい接続を許可するアウトバウンドルールがなくてもアプリケーションから送信できます。アウトバウンドルールはアプリケーションが開始する通信を制御し、この HTTP 応答を許可するためには必要ありません。
現在のアウトバウンド許可を読み取ります。
aws ec2 describe-security-groups \
--group-ids "$GROUP_ID" \
--query 'SecurityGroups[].IpPermissionsEgress' \
--output json
新しいグループには、すべての通信に対する既定の宛先 0.0.0.0/0 があります。次のコマンドの --ip-permissions は、ルール指定の JSON リストを引用符で囲んだ1つの引数として受け取ります。IpProtocol の -1 はすべてのプロトコル、IpRanges はアウトバウンドルールの宛先を表します。その既定ルールを正確に削除します。
aws ec2 revoke-security-group-egress \
--group-id "$GROUP_ID" \
--ip-permissions '[{"IpProtocol":"-1","IpRanges":[{"CidrIp":"0.0.0.0/0"}]}]'
応答は成功を示します。両方向のルールを読み取ります。
aws ec2 describe-security-groups \
--group-ids "$GROUP_ID" \
--query 'SecurityGroups[].{Inbound:IpPermissions,Outbound:IpPermissionsEgress}' \
--output json
インバウンドは A のポート 80 だけを許可し、アウトバウンドは空です。AWS View は Outbound · none を表示します。再度 Request application · client A をクリックすると、Success と Application online が返ります。応答は許可済みのインバウンド接続に属するためです。
Request application · client B と Request port 8081 を再確認します。両方とも失敗します。ステートフルな応答は、別の送信元やポートへの新しいインバウンドアクセスを許可しません。このテストは応答の動作を確認し、アプリケーションが開始する新しいアウトバウンド接続はテストしません。

AWS View の例:インバウンドは A のポート 80 だけを許可し、アウトバウンドは空ですが、実際の HTTP 応答は成功します。生成されるリソース ID は環境によって異なります。
用意済みグループを復元し、自分のグループを削除する
このステップでは、アプリケーションの元の関連付けを復元し、自分の練習用セキュリティグループだけを削除します。
ネットワークインターフェイスに関連付けられたグループは削除できません。まず、保存した用意済みグループで自分のグループを置き換えます。用意済みグループを削除・編集しないでください。
aws ec2 modify-network-interface-attribute \
--network-interface-id "$ENI_ID" \
--groups "$SUPPLIED_GROUP_ID"
関連付けを確認します。
aws ec2 describe-network-interfaces \
--network-interface-ids "$ENI_ID" \
--query 'NetworkInterfaces[].{ID:NetworkInterfaceId,Groups:Groups}' \
--output json
元の supplied-application だけが関連付いています。使わなくなった自分のグループを削除します。
aws ec2 delete-security-group --group-id "$GROUP_ID"
削除成功時に出力はありません。取り外せるタグに依存せず、不在を確認するためにグループの全一覧を問い合わせます。
aws ec2 describe-security-groups \
--query 'SecurityGroups[].{ID:GroupId,Name:GroupName,VPC:VpcId}' \
--output table
parcel-web は存在しません。用意済みグループと既定グループ、VPC、サブネット、アプリケーションインターフェイス、パブリックアドレス、ルートは残っています。一覧取得の失敗は、削除の証明になりません。
AWS View に再び supplied-application が表示されます。A と B のリクエストボタンをクリックすると、両方のポート 80 リクエストは初期状態と同じ Success を返します。変更していない用意済みグループは 80 だけを許可するため、Request port 8081 は失敗します。
このステップの完了チェックを実行してください。
まとめ
専用セキュリティグループを作成・関連付けし、A の TCP ポート 80 だけを許可しました。2つ目のポートの一時許可をテストして取り消し、アウトバウンド許可がなくてもステートフルな HTTP 応答が返ることを確認しました。実際のリクエストで許可・拒否通信を区別し、最後に用意済みグループを復元して自分の練習用グループだけを削除しました。
次の「プライベートサブネットにアウトバウンドアクセスを提供する」では、外部からの要求していないアクセスを許可せず、プライベートアプリケーションのアウトバウンド経路を構築します。



