EC2 運用 — security group, key pair, SSM
EC2 運用の日常の道具たち。Security Group ルールの設計、NACL との違い、key pair の限界と SSM Session Manager、IMDSv2、そして AMI でインスタンスの骨格を固める方法まで整理します。
第8章 EC2 と VPC の基礎 で EC2 を1台立ち上げる図をつかみました。本章はその EC2 を扱う方法です。セキュリティルールはどう設計し、接続はどう行い、同じインスタンスを何度も立ち上げるには何を固めるべきかを扱います。
運用 EC2 の仕事は、おおむね3つに要約されます。第一に、Security Group で誰が入ってこられるかを制御します。第二に、接続は昔は SSH と key pair、最近は SSM Session Manager で行います。第三に、AMI で骨格を固めて同じインスタンスを素早く再生成します。この3つを一本につなぐと、EC2 運用の日常が単純になります。
ここで整理する SG パターンは 第13章 ALB / NLB と ACM のロードバランサーのセキュリティルールへ、AMI と ASG は 第15章 ECS と Fargate のコンテナ運用へつながります。
Security Group の構造 #
Security Group (SG) はインスタンス(正確には ENI)に付く stateful なファイアウォールです。インスタンス1台に SG を複数付けられ、SG 1つを複数のインスタンスで共有できます。
Inbound vs Outbound #
SG のルールは2方向です。
| Inbound | Outbound | |
|---|---|---|
| 何を制御 | 入ってくるトラフィック | 出ていくトラフィック |
| デフォルト | すべて塞ぐ | すべて許可 |
| よく触る | よく | ほぼない |
デフォルト値を覚えます。Inbound はデフォルト遮断、Outbound はデフォルト許可です。そのため 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 の ID —
sg-0abc...で、これが本当に強力です。
SG を SG で指す #
運用で核心となるパターンは、SG が別の SG を指すことです。
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 パターン #
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 や内部リソースから適用します。
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 ← DNSNACL — もう1つの層 #
VPC の2つ目のファイアウォールは NACL (Network Access Control List) です。サブネット単位で動きます。
| Security Group | NACL | |
|---|---|---|
| 適用単位 | インスタンス (ENI) | サブネット |
| Stateful | そうである | そうでない (応答も明示許可が必要) |
| ルール種別 | Allow only | Allow + Deny |
| 評価順 | すべてのルール | 番号順 (低い番号が先) |
| 日常で | 毎日触る | ほぼ触らない |
NACL はあまり使いません。デフォルト NACL がすべてのトラフィックを許可し、SG が十分に細かいためです。NACL を触る場合は次のとおりです。
- 特定の IP 帯域を遮断するとき(Deny が必要なとき — SG には Deny がありません)。
- 攻撃を受けているとき、一時的に遮断するとき。
- コンプライアンス要求でサブネット単位の明示遮断が必要なとき。
NACL の stateless の落とし穴 #
NACL は stateless なので、応答トラフィックも明示的に許可しなければなりません。
Inbound Allow TCP 1024-65535 0.0.0.0/0 ← ephemeral port 応答
Outbound Allow TCP 80 0.0.0.0/01024-65535 が ephemeral port 領域です。これを抜かすと応答が戻ってきません。SG では stateful なので自動ですが、NACL は明示が必要です。
Key pair の限界 #
昔から EC2 の SSH 接続は key pair で行いました。
# キーペアを作る
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 キーを一度だけ使う方式です。SG に 22 ポート許可は依然として必要です。コンソールの「Connect」ボタンがこれを使います。
SSM Session Manager — キーなしの接続 #
SSM (AWS Systems Manager) の Session Manager は EC2 接続の新しい標準です。22 ポートも開けず、キーもなしで EC2 の中のシェルへ入ります。
[自分のコンピュータ] ──HTTPS──▶ [SSM Endpoint] ◀──HTTPS──[EC2 内の SSM Agent]
│
▼
IAM 権限を確認EC2 の中で動く SSM Agent が AWS API へ outbound 接続を作り、そのチャネルを通じてコンソールのシェル入力が流れます。方向が逆(EC2 が outbound)なので、SG inbound の 22 ポートが不要です。
Session Manager のセットアップ #
- SSM Agent がインストールされた AMI — Amazon Linux 2023 / Ubuntu の最新はデフォルトで含まれます。
- EC2 の IAM Role に
AmazonSSMManagedInstanceCoreポリシーを付けます。 - outbound インターネット または VPC Endpoint — Private サブネットの EC2 でも SSM が可能です。
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 -L | start-session で可能 |
運用では Session Manager がほぼ常に正解です。詳しい IAM 設定は 第2章 IAM、セキュリティは 第6章 セキュリティ基本 を参照します。
CloudShell と混同しません。 第5章 CloudShell と IAM Identity Center の CloudShell は AWS コンソールの中のブラウザ端末で、自分の IAM 資格で
aws cliを使う方式です。Session Manager は EC2 インスタンスの中のシェルです。
EC2 のメタデータサービス (IMDS) #
EC2 の中で自分のインスタンスの情報(インスタンス ID、リージョン、IAM ロールの資格情報など)を受け取るサービスが IMDS (Instance Metadata Service) です。
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-id169.254.169.254 という link-local アドレスが、EC2 の中でのみ応答するメタデータエンドポイントです。IAM Role の一時的な資格情報もここで受け取ります。aws cli が EC2 の中で自動でその資格を使う理由です。
IMDSv1 vs IMDSv2 #
昔はトークンなしで GET で受け取りました(IMDSv1)。SSRF 攻撃でトークンを抜き取る事故が多く、IMDSv2 に変わりました。PUT でトークンを受け取り、それで GET します。新しいインスタンスは IMDSv2 のみを有効にすることが推奨されます。
aws ec2 modify-instance-metadata-options \
--instance-id i-0abc... \
--http-tokens required \
--http-endpoint enabledAMI 作り — 骨格を固める #
同じセットアップのインスタンスを何度も素早く立ち上げるには2つの道があります。1つは AMI を作ることで、もう1つは空の AMI で立ち上げてセットアップスクリプトを自動実行する User data 方式です。
AMI 作り #
コンソールでインスタンスを右クリックして「イメージの作成」をするか、CLI で作ります。
aws ec2 create-image \
--instance-id i-0abc... \
--name "my-app-2026-05-24" \
--description "Node 20 + nginx + my-app v1.2.3" \
--no-reboot # オプション — 再起動なしで (ディスクの一貫性は少し下がる可能性)作られた AMI はインスタンスの EBS スナップショットとメタデータです。その AMI で新しいインスタンスを立ち上げると、同じディスク状態で始まります。AMI はリージョン単位なので、別のリージョンでは copy-image を使います。
User data — 起動スクリプト #
AMI の代わりに空の OS イメージで立ち上げ、起動スクリプトでセットアップするパターンです。AMI より柔軟で、変更の追跡も容易です。
#!/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/myappUser data はインスタンスの初回起動時に一度実行されます。ログは /var/log/cloud-init-output.log に残ります。
Golden AMI vs User data #
| Golden AMI | User data | |
|---|---|---|
| 起動速度 | 速い | 遅い (スクリプト実行時間) |
| 変更管理 | AMI を新しくビルド | スクリプト修正 |
| 再現性 | 非常に高い | 外部依存(yum repo、S3)が変わり得る |
| 適合 | ASG の速いスケール / 安定 | 開発 / 速い変更 |
運用では両方を一緒に使います。Golden AMI で OS と依存を埋め込み、User data でアプリのバージョンだけを差し込む形です。
Auto Scaling Group — 自動復旧 #
インスタンスが死んだら新しく立ち上げて ALB に自動で接続してくれる機能が ASG (Auto Scaling Group) です。
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)基準です。
コンテナワークロードなら 第15章 ECS と Fargate がより滑らかな代替です。ECS がコンテナ単位の ASG を吸収します。
よく出会う落とし穴 #
- 「なぜ ALB が EC2 に届かないのか?」 — 上から下へ確認します。(1) ALB SG outbound が EC2 SG inbound と一致するか、(2) EC2 SG inbound に ALB SG が source として入っているか、(3) EC2 の OS 内のファイアウォール(
firewalld、ufw)もそのポートを許可するか、(4) ALB target group の health check 経路が 200 を応答するか、(5) EC2 がそのポートで listen 中か(ss -tlnp)。大部分は (1) または (2) で、SG 項目を IP で書いているなら SG 自体に変えるのが運用の正解です。 - キーがないのに EC2 の中に入る必要がある — Session Manager が ON になっていれば
aws ssm start-sessionを使います。OFF なら、インスタンスを停止して EBS を切り離し、別の EC2 にマウントした後に~/.ssh/authorized_keysを修正して再接続するか、EBS スナップショットを取って新しいキーで新しいインスタンスを立ち上げます。 - Outbound all のままにしてデータ漏洩 — EC2 が侵害されたとき outbound がすべて開いていると、攻撃者が任意の IP へデータを送ります。DB サーバーや内部システムは outbound も狭めるのが最も安全です。
- NACL の任意遮断で応答が来ない — NACL の stateless の性質を忘れて outbound だけ許可すると、inbound 応答が塞がれます。ほぼ常に NACL はデフォルト値のままにして SG だけを触るのが安全です。
- IMDSv1 のまま運用 — 古い AMI や旧セットアップが IMDSv1 のままで運用中なら、SSRF 攻撃面になります。すべてのインスタンスに
--http-tokens requiredを適用します。 - AMI が大きすぎて起動が遅くなる — 長く運用したインスタンスをそのまま AMI にして 5GB 以上になると、起動時間が増えます。AMI を作る前にログ / キャッシュ / 一時ファイルを片付け(
yum clean allなど)、cloud-init cleanで次の起動に再び init が回るようにし、swap と journal を空にします。
練習問題 #
- §「3-tier Web アプリの SG 設計」の4つの SG (alb · app · db · bastion) を見ずに再び描き、各 inbound ルールの source が IP か SG かを表示してください。そのうえで、ALB の IP が変わってもルールを直さなくてよい理由を §「SG を SG で指す」を根拠に一文で説明してみてください。
- key pair と Session Manager の比較表を見て、§「key pair モデルの限界」の5項目のうち Session Manager がそれぞれどう解決するかをつなげてみてください。第6章 セキュリティ基本 の最小権限とどう噛み合うかも一行書いておいてください。
- 同じセットアップのインスタンスを自動復旧したい状況で Golden AMI と User data を一緒に使うなら、それぞれに何を入れるか(OS · 依存 · アプリバージョン)を分けて書いてみてください。この分担は 第15章 ECS と Fargate でコンテナイメージとタスク定義として再び現れます。
一行まとめ: SG はインスタンス単位の stateful ファイアウォールで、SG が SG を指すパターンが IP より強力、NACL はサブネット単位の stateless でほぼ触らない。接続は 22 ポートもキーも使わない SSM Session Manager が新しい標準で、IMDSv2 の強制で SSRF を防ぐ。骨格は Golden AMI と User data を一緒に使って固め、ASG が自動復旧を担う。
次の章 #
EC2 の基本は整理できました。次の 第10章 S3 では、EC2 と一緒によく扱うオブジェクトストレージへ移ります。バケットの形、ポリシーと Public Access Block、静的サイトホスティング、presigned URL のような日常のパターンを整理します。