AWS中級 #2 EC2 運用 — security group、key pair、SSM

読了 9分

#1 EC2 と VPC の基礎 で EC2 を 1 台立ち上げる絵を掴みました。今回はその EC2 を 扱う方法 を整理します。セキュリティルールはどう設計し、接続はどう行い、同じインスタンスを何度も立ち上げるには何を固めるべきかを見ていきます。

運用 EC2 の 80% の仕事は次の 3 つです。

  1. Security Group で入ってこられる相手を制御
  2. 接続 — 昔は SSH + key pair、今は SSM Session Manager
  3. AMI で骨格を固めて同じインスタンスを高速に再生成

この 3 つを 1 本の線で通せば EC2 運用の日常がシンプルになります。

Security Group の形 #

Security Group (SG) はインスタンス (正確には ENI) に紐づく stateful ファイアウォール。インスタンス 1 台に SG を 複数 アタッチでき、SG 1 つを 複数のインスタンス が共有することも可能。

Inbound vs Outbound #

SG のルールは 2 方向:

InboundOutbound
何を制御入ってくるトラフィック出ていくトラフィック
デフォルトすべて遮断すべて許可
よく触るほぼ触らない

デフォルトを覚えておきましょう。Inbound は既定で遮断、Outbound は既定で許可。なので SG 作業の 99% は Inbound ルール追加。

ルールの形 #

web サーバー SG の inbound ルール例
Protocol  Port      Source              Description
TCP       80        0.0.0.0/0           HTTP from anywhere
TCP       443       0.0.0.0/0           HTTPS from anywhere
TCP       22        198.51.100.10/32    SSH from my home IP

各ルールは (プロトコル、ポート、ソース) の組み合わせ。ソース (Source) には 2 種類が入ります:

  • CIDR ブロック0.0.0.0/0 (全 IP)、10.0.0.0/16 (VPC 内部)、198.51.100.10/32 (単一 IP)
  • 別の SG の IDsg-0abc... ← これが本当に強力

SG が SG を指す #

運用の核心パターンは SG が他の SG を指すこと

ALB → アプリ EC2 パターン
ALB SG  (sg-alb)
  Inbound:  TCP 443 from 0.0.0.0/0

App SG  (sg-app)
  Inbound:  TCP 8080 from sg-alb     ← IP ではなく SG そのもの

ALB の IP が変わっても (実際 ALB は複数の IP を動的に割り当てる) SG 指定は自動的に追従。運用インフラのルール保守がぐっと楽になります。

よくある SG 設計 #

3-tier web アプリ SG 設計
ALB SG (sg-alb)
  in:  443 ← 0.0.0.0/0
  out: all

App SG (sg-app)
  in:  8080 ← sg-alb              ← ALB だけ入れる
       22   ← sg-bastion          ← Bastion から SSH (旧式)
  out: all

DB SG  (sg-db)
  in:  5432 ← sg-app              ← アプリサーバーだけ DB アクセス
  out: all (または閉じる)

Bastion SG (sg-bastion)
  in:  22 ← 198.51.100.10/32      ← 自分の IP のみ
  out: all

ルールが 「SG → SG」 で流れるのが核心。IP ではありません。

Outbound を絞る場合 #

デフォルトは outbound すべて許可ですが、侵害された際のデータ流出を抑えるため outbound も狭めるパターンがあります。通常は運用環境の DB / 内部用途から適用。

絞った outbound の例
App SG outbound:
  TCP 5432 → sg-db                 ← DB のみ
  TCP 443  → 0.0.0.0/0             ← 外部 API 呼び出し
  TCP 53   → 0.0.0.0/0             ← DNS
  UDP 53   → 0.0.0.0/0             ← DNS

NACL — もう 1 層 #

VPC のもう 1 つのファイアウォールが NACL (Network Access Control List)。サブネット単位で動きます。

Security GroupNACL
適用単位インスタンス (ENI)サブネット
Stateful❌ (応答も明示許可が必要)
ルール種別Allow onlyAllow + Deny
評価順すべてのルール番号順 (低い番号が先)
日常で毎日触るほぼ触らない

NACL は あまり使いません。 既定 NACL がすべてのトラフィックを許可していて、SG が十分に細かいから。NACL を触る場合:

  • 特定 IP 帯の遮断 (Deny が必要 — SG には Deny がない)
  • 攻撃を受けたときの一時遮断
  • コンプライアンス要件でサブネット単位の明示遮断

NACL の stateless の罠 #

NACL は stateless なので応答トラフィックも明示的に許可する必要があります。

NACL ルール例 — TCP 80 outbound が応答を受け取るには
Inbound  Allow  TCP  1024-65535  0.0.0.0/0   ← ephemeral port 応答
Outbound Allow  TCP  80          0.0.0.0/0

1024-65535ephemeral port の領域です。これを書き忘れると応答が戻りません。SG は stateful で自動なのに、NACL は明示が必要です。

Key pair の場と限界 #

昔から EC2 への SSH 接続は key pair で行ってきました。

key pair の作成 + SSH 接続
# キーペア作成
aws ec2 create-key-pair --key-name my-key --query 'KeyMaterial' --output text > my-key.pem
chmod 400 my-key.pem

# インスタンス起動時に key 指定
aws ec2 run-instances --key-name my-key ...

# 接続
ssh -i my-key.pem ec2-user@<public-ip>

EC2 が起動するとき、インスタンスの ~/.ssh/authorized_keys に自動でキーが書き込まれて SSH が可能になります。

key pair の限界 #

key pair モデルは運用規模が大きくなると破綻します。

  • キー紛失 — 失くすと再生成不可。インスタンス作り直し、または EBS をマウントして手動追加
  • キー共有のリスク — チームメンバーに渡す必要があるが、一度漏れたら回収不能
  • 監査が難しい — 誰がいつ入ったか別途ロギングが必要
  • インターネットに 22 ポート露出 — 攻撃面
  • MFA 不可 — キーがあれば通る

EC2 Instance Connect #

コンソールが作る一時的な SSH キーを 1 度だけ使う方式。SG への 22 ポート許可は依然必要。コンソールの「Connect」ボタンがこれを使います。

SSM Session Manager — キーなし接続 #

SSM (AWS Systems Manager)Session Manager は EC2 接続の新しい標準。22 ポートも開けず、キーも使わずに EC2 内のシェルへ入っていきます。

Session Manager の流れ
[自分の PC] ──HTTPS──▶ [SSM Endpoint] ◀──HTTPS──[EC2 内の SSM Agent]
                   IAM 権限を確認

EC2 内で動く SSM Agent が AWS API へ outbound 接続を作り、そのチャネルを通じてコンソールのシェル入力が流れます。方向が逆 (EC2 が outbound) なので SG inbound 22 ポートが不要。

Session Manager のセットアップ #

  1. SSM Agent が入った AMI — Amazon Linux 2023 / Ubuntu 最新は標準で入っている
  2. EC2 の IAM RoleAmazonSSMManagedInstanceCore ポリシー
  3. outbound インターネット または VPC Endpoint (Private サブネットの EC2 でも SSM 可能)
コンソールの代わりに CLI で接続
aws ssm start-session --target i-0abc1234def567890

# ポートフォワーディングも可能
aws ssm start-session --target i-0abc... \
  --document-name AWS-StartPortForwardingSession \
  --parameters '{"portNumber":["80"],"localPortNumber":["8080"]}'

key pair vs Session Manager #

key pair (SSH)Session Manager
22 ポート開ける必要あり開けなくてよい
キー管理自分で不要
認証SSH キーIAM (MFA 可)
監査ログ別途CloudTrail / S3 が自動
Private サブネットBastion 必要VPC Endpoint で直接
ポートフォワードssh -Lstart-session で可

運用は Session Manager がほぼ常に正解。詳しい IAM 設定は 基礎 #2、セキュリティ設定は 基礎 #6 を参照。

CloudShell と混同しないでください。 基礎 #5 CloudShell は AWS コンソール内のブラウザターミナル (自分の IAM 認証で aws cli を使う方式) です。Session Manager は EC2 インスタンス内のシェルです。

EC2 のメタデータサービス (IMDS) #

EC2 内から自インスタンスの情報 (インスタンス ID、リージョン、IAM ロールの認証情報など) を取得できる仕組みが IMDS (Instance Metadata Service) です。

IMDSv2 — トークンを取得してメタデータ照会
TOKEN=$(curl -X PUT http://169.254.169.254/latest/api/token \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 21600")

curl -H "X-aws-ec2-metadata-token: $TOKEN" \
  http://169.254.169.254/latest/meta-data/instance-id

169.254.169.254 という link-local アドレスが EC2 内だけで応答するメタデータのエンドポイントです。IAM Role の一時認証情報もここから渡されます — aws cli が EC2 内で自動的にその認証情報を使うのはこのためです。

IMDSv1 vs IMDSv2 #

昔はトークンなしの GET で取得 (IMDSv1)。SSRF 攻撃でトークンを抜かれる事故が多発し IMDSv2 に移行 — PUT でトークン取得、それを使って GET。新規インスタンスは IMDSv2 のみ有効化 が推奨。

IMDSv2 強制
aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc... \
  --http-tokens required \
  --http-endpoint enabled

AMI を作る — 骨格を固める #

同じセットアップのインスタンスを 何度も高速に 立ち上げたいなら 2 通り。

  1. AMI 作成 — 現在のインスタンスをスナップショットして新 AMI に
  2. User data + IaC — 空 AMI で起動して、セットアップスクリプトを自動実行

AMI 作成 #

コンソールでインスタンス右クリック → 「イメージの作成」、または:

AMI 作成
aws ec2 create-image \
  --instance-id i-0abc... \
  --name "my-app-2026-04-19" \
  --description "Node 20 + nginx + my-app v1.2.3" \
  --no-reboot     # オプション — 再起動なし (ディスク整合性が少し落ちる可能性)

できた AMI は:

  • インスタンスの EBS スナップショット + メタデータ
  • その AMI で新インスタンスを立てると同じディスク状態でスタート
  • リージョン単位 — 別リージョンでは copy-image

User data — 起動スクリプト #

AMI の代わりに 空の OS イメージで立ち上げ、起動スクリプトでセットアップ するパターン。AMI より柔軟で、変更追跡もしやすい。

User data 例 — Amazon Linux 2023
#!/bin/bash
yum update -y
yum install -y nginx
systemctl enable --now nginx

# アプリコードを取得
aws s3 cp s3://my-bucket/app.tar.gz /tmp/
tar -xzf /tmp/app.tar.gz -C /opt/myapp

User data はインスタンス初回起動時に 1 回実行。ログは /var/log/cloud-init-output.log

Golden AMI vs User data #

Golden AMIUser data
起動速度速い遅い (スクリプト実行時間)
変更管理AMI 再ビルドスクリプト修正
再現性非常に高い外部依存 (yum repo, S3) が変わる可能性
方式ASG の高速スケール / 安定開発 / 高速変更

運用では 両方を併用 します — Golden AMI で OS / 依存を固め、User data でアプリバージョンだけ差し込む形。

Auto Scaling Group — 自動復旧 #

インスタンスが死んだら 新しく立ち上げて ALB に自動接続 してくれるのが ASG (Auto Scaling Group) です。

ASG の構造
Launch Template (インスタンステンプレート: AMI、タイプ、SG、key、user data)
   ┌─────────┐
   │   ASG   │  desired=2  min=2  max=10
   └─────────┘
        ├─── EC2 (AZ a)  ← health check 失敗 → terminate + 新規起動
        ├─── EC2 (AZ b)
        └─── EC2 (AZ b)

基本だけ:

  • Launch Template — どんな EC2 を起動するか定義 (AMI、タイプ、SG、IAM、user data)
  • Desired / Min / Max — 常に維持する数、最小、最大
  • Health Check — EC2 自体 (EC2) または ALB target group (ELB) 基準

詳しい ASG は 上級 #1 ECS / Fargate のほうがなめらかな代替 — ECS がコンテナ ASG を吸収します。

よくハマる罠 #

1) 「なぜ ALB が EC2 に届かないの?」 #

チェックリスト (上から下):

  1. ALB SG outbound と EC2 SG inbound が一致
  2. EC2 SG inbound に ALB SG が source として入っている
  3. EC2 の OS 内ファイアウォール (firewalldufw) もそのポート許可
  4. ALB target group の health check パス が 200 応答
  5. EC2 がそのポートで listen 中 (ss -tlnp)

たいてい 1) または 2)。SG を IP で書いていたら SG 自体に置き換えるのが運用の正解。

2) 「キーがないけど EC2 内に入る必要がある」 #

  • Session Manager が有効なら → aws ssm start-session
  • 有効でないなら → インスタンス停止 → EBS デタッチ → 別 EC2 にマウント → ~/.ssh/authorized_keys を編集 → 再接続
  • または EBS スナップショットを取って新キーで新インスタンス起動

3) Outbound all のまま → データ流出 #

EC2 が侵害された際 outbound が全開だと、攻撃者が 任意の IP へデータ送信。DB サーバー / 内部用途は outbound も絞る のがベスト。

4) NACL の任意遮断で応答が来ない #

NACL が stateless であることを忘れて outbound だけ許可 → inbound 応答が塞がる。ほぼ常に NACL はデフォルト、SG だけ触るのが安全。

5) IMDSv1 のまま #

古い AMI / 旧設定が IMDSv1 のまま運用 → SSRF 攻撃面。すべてのインスタンスに --http-tokens required

6) AMI が大きすぎて起動が遅い #

長く運用したインスタンスをそのまま AMI にして 5GB+ になるケース。起動時間が伸びます。AMI 作成前に:

  • ログ / キャッシュ / 一時ファイル整理 (yum clean all 等)
  • cloud-init clean (次回起動時に init 再実行)
  • swap / journal をクリア

まとめ #

今回押さえたこと:

  • SG = インスタンス単位 stateful ファイアウォール。SG → SG パターンが IP より強力
  • 既定は inbound 遮断 + outbound 許可。Outbound を絞ればデータ流出防御
  • NACL はサブネット単位 stateless。ほぼ触りません。Stateless なので応答 ephemeral port も許可必要
  • key pair は旧標準。キー紛失 / 共有 / 22 ポート露出が限界
  • SSM Session Manager が新標準。22 ポートもキーも使わず IAM で認証、監査ログ自動
  • IMDSv2 を強制 — SSRF 防御
  • AMI で骨格を固め + User data で起動時セットアップ、通常は両方併用
  • ASG が自動復旧。Launch Template + desired/min/max + health check
  • 罠 — ALB→EC2 5 ステップ点検、キーなし復旧、outbound all、NACL stateless、IMDSv1、巨大 AMI

次回 — S3 #

EC2 のポジションは整いました。次は EC2 とよく一緒に扱う オブジェクトストレージ に進みます。

#3 S3 — 静的ホスティング、presigned URL では、バケットの形、ポリシーと public access block、静的サイトホスティング、presigned URL のような日常パターンを整理します。

X