IAM Identity Center × SSM 本番運用完全ガイド (Permission Set + 4接続 + 監査)

目次

1. なぜ人手キー廃止 (背景と価値)

fig01: IAM Identity Center × SSM Session Manager 全体像

この記事で得られること (6 項目)

  • IAM Identity Center を Organization 連携で有効化し、外部 IdP (Azure AD / Okta / Google Workspace) と SAML/SCIM 接続できる
  • Permission Set 6 パターン (ReadOnly/Operator/Admin/DB/Network/Emergency) を業務実態に合わせて Terraform で定義できる
  • SSM Session Manager で EC2 直接接続 / ECS Exec / RDS Port Forwarding / Windows RDP の 4 種類接続を実装できる
  • CloudTrail + Session Manager Logs + S3 録画 + CloudWatch Alarm で誰が・いつ・どのサーバーに・何をしたかを完全監査できる
  • SSM Agent 未起動・IAM 不足・Permission Set 伝搬待ちなど 10+ エラーを即解決できる
  • 人手キー廃止による監査コスト削減とコンプライアンス達成を経営層に説明できる

1-1. 本記事のゴール

本記事は、IAM Identity Center (旧 AWS SSO) と SSM Session Manager を組み合わせ、本番 AWS 環境から人手 IAM ユーザーと SSH キーを完全廃止する完全ガイドです。

読了後、読者は以下を自力で実現できます。

  • IAM Identity Center と外部 IdP (Azure AD / Okta / Google Workspace) を SAML/SCIM で接続し、ユーザー・グループを自動プロビジョニングする
  • Permission Set 6 パターンを Terraform で定義し、最小権限・時間制限・MFA 強制を実務標準化する
  • SSH キーや踏み台 EC2 を廃止し、SSM Session Manager 経由で EC2/ECS/RDS/RDP の 4 接続を統一する
  • CloudTrail・Session Manager Logs・S3 録画・CloudWatch Alarm で完全監査ログを構築する
  • Terraform 1 回の apply で IC + Permission Set + SSM IAM Policy を 30 分デプロイできる

対象読者は IAM 基礎・EC2/ECS/RDS 運用経験・Terraform 基礎を持つエンジニアです。

1-2. 読者像

本記事は以下の前提知識を持つ読者を想定しています。

前提知識必要度
IAM 基礎 (Role / Policy / Trust Relationship)✅ 必須
EC2 / ECS / RDS 運用経験 (SSH・踏み台での接続経験)✅ 必須
Terraform 基礎 (aws provider で IAM 構築経験)✅ 必須
Organization 基礎 (master account / member account)✅ 想定
外部 IdP (Azure AD / Okta / Google Workspace) の admin 経験△ 推奨
CloudTrail / CloudWatch 運用経験△ §7 で補足

「SSH キー管理が煩雑になってきた」「踏み台 EC2 の費用と攻撃面が気になる」「監査対応のたびに各サーバーから sudo ログを grep している」という課題を抱えているチームに最も価値を届けられます。

1-3. なぜ今人手キー廃止か

人手 IAM ユーザーと SSH キー管理には、2026 年現在でも多くの組織が直面する 3 つの根本問題があります。

人的ミスリスク: 退職者の IAM ユーザー削除漏れ、.pem ファイルの Slack 誤送信、Access Key の GitHub 流出はセキュリティインシデントの常連です。クラウドセキュリティ侵害の多くは認証情報漏洩に起因し、長期クレデンシャル (Access Key) の管理ミスが主因のひとつです。

監査コスト: ISMS / SOC 2 / PCI DSS の監査対応で「誰がいつどのサーバーにアクセスしたか」を証明しようとすると、各 EC2 の /var/log/auth.log を手動で収集する作業が発生します。10 台規模でも 1 週間、100 台規模では不可能に近い工数です。

コンプライアンス要件: SOC 2 Type II や PCI DSS v4.0 では「特権アクセスの記録・録画・アラート」が必須要件になっています。人手 SSH キーによる接続では、この要件を満たすための追加実装コストが膨大です。

IAM Identity Center + SSM Session Manager の組み合わせは、これら 3 問題を一撃で解決します。一時クレデンシャルのみを使い、全セッションを録画・監査し、SSH キーを物理的に存在させない設計が可能です。

1-4. ID:1196 (aurora-no-human-login) との差別化 6 点

本記事は ID:1196 (aurora-no-human-login) の汎用横展開版ですID:1196 は「Aurora PostgreSQL IAM 認証 + RDS Proxy」という DB 特化記事です。本記事との差別化を以下に示します。

観点ID:1196 (Aurora 特化)本記事 (汎用セキュリティ運用)
(a) 対象リソースAurora PostgreSQL のみEC2 / ECS / RDS Port FW / Windows RDP の 4 種類
(b) 認証の主軸IAM Database AuthenticationIAM Identity Center + Permission Set 設計を深掘り
(c) Permission Set言及なしReadOnly/Operator/Admin/DB/Network/Emergency の 6 パターン
(d) SSM 接続言及なし踏み台なし完全廃止 (4 接続パターン)
(e) 監査・録画基本 CloudTrail のみCloudTrail + SM Logs + S3 録画 + CW Alarm の完全運用設計
(f) Terraform 実装RDS Proxy + IAM Auth HCLIC + Permission Set + SSM IAM Policy の 3 点セット HCL

Aurora IAM 認証の詳細は aurora-no-human-login を参照してください。本記事は DB に限らず EC2・ECS・RDS・RDP を横断する汎用セキュリティ運用を扱います。

1-5. 関連記事

記事役割
Aurora PostgreSQL IAM 認証 完全ガイド本記事の差別化対象 (DB 特化 → 汎用横展開)
AWS 公式 IAM Identity Center User GuideIdP 連携詳細
AWS 公式 Session Manager DocSSM Agent / IAM 詳細
AWS 公式 Organizations Best Practicesマルチアカウント設計

1-6. 執筆方針

本記事は以下の方針で執筆します。

  • 3 点セット: 各設定は Terraform HCL + AWS CLI + マネジメントコンソール操作の 3 点セットで提供
  • 2026-04 時点: IAM Identity Center (旧 AWS SSO) の現行仕様に基づく。AWS が 2023 年にサービス名を変更した後の API 名を使用
  • コピペ可能: Terraform コードはそのまま利用できる実用レベルで提供
  • エラー対処: 実運用で発生しやすい 10+ エラーを §8 で網羅
  • 費用目安: 各構成要素の月額費用目安を明示。経営層への予算申請に使えるレベルで記載

本記事は §1 (背景・価値) → §2 (全体像) → §3 (IC 初期設定) → §4 (Permission Set 6 パターン) → §5 (SSM 4 接続) → §6 (Terraform 完全実装) → §7 (監査・録画) → §8 (まとめ・エラー集) の順で構成されています。章ごとに独立して参照できるよう、各章の冒頭に前提条件と章内の達成目標を明記します。

IC + SSM の組み合わせで得られる最大の価値は「セキュリティと利便性の両立」です。従来のゼロトラスト実装は複雑な VPN 設定や証明書管理が伴いましたが、IC + SSM では aws sso login + aws ssm start-session の 2 コマンドで本番環境への安全なアクセスが実現します。開発者体験を損なわずにセキュリティ要件を達成できる点が、他のゼロトラスト実装との最大の差別化です。

3 点セット (Terraform HCL + AWS CLI + マネジメントコンソール操作) のコード例はすべてコピー&ペーストで動作するレベルを目標に記述しており、実際の AWS 環境で手を動かしながら読み進めるハンズオン設計となっています。


2. 全体像 (IAM Identity Center + SSM Session Manager アーキテクチャ)

fig02: IAM Identity Center + Session Manager アーキテクチャ

2-1. IAM Identity Center の位置付け

IAM Identity Center (IC) は AWS Organizations のマスターアカウントで有効化する一元 ID 管理サービスです。3 つのレイヤで構成されます。

レイヤ 1 — Organization 連携: IC は Organizations の管理アカウントにのみ有効化できます。有効化後、配下のメンバーアカウント全てに対して Permission Set の割当が可能になります。単一の IC インスタンスで数十〜数百のマルチアカウント環境を一元管理できます。

レイヤ 2 — 外部 IdP (SAML/SCIM) 連携: 社内の Azure AD / Okta / Google Workspace を外部 IdP として登録し、SAML 2.0 で認証フェデレーション、SCIM でユーザー・グループの自動プロビジョニングを行います。外部 IdP でユーザーを無効化すると、IC 側も自動的にプロビジョニング解除されます。退職者対応が外部 IdP の操作 1 回で完結します。

レイヤ 3 — Permission Set とアカウント割当: Permission Set は「どの AWS 権限を持つか」を定義した IAM Role テンプレートです。「どの IdP グループに / どのアカウントで / どの Permission Set を」という 3 軸で割当を行います。ユーザーは SSO Portal でログイン後、割当済みアカウント一覧から対象を選ぶだけで、一時クレデンシャルを取得して AWS にアクセスできます。

IC の核心は「IAM ユーザーを個人ごとに作らない」点です。人手 IAM ユーザーがなければ、Access Key の発行・漏洩・削除漏れという問題は原理的に発生しません。

2-2. SSM Session Manager の位置付け

SSM Session Manager (SM) は SSH キーや踏み台 EC2 を使わずにインスタンスやコンテナへシェルアクセスするフルマネージド接続サービスです。3 つのレイヤで構成されます。

レイヤ 1 — SSM Agent: EC2 または ECS タスク上で動作するエージェントです。Amazon Linux 2023 と Ubuntu 22.04 LTS にはプリインストール済みです。Agent が Systems Manager エンドポイントにアウトバウンド HTTPS (443) で接続するため、インバウンドポートを一切開ける必要がありません。

レイヤ 2 — IAM Policy: EC2 Instance Role に AmazonSSMManagedInstanceCore ポリシーをアタッチすることで SM が有効化されます。セッション開始には別途 ssm:StartSession / ssm:TerminateSession の許可が必要です。IC の Permission Set にこの権限を含めることで、IC 経由のユーザーのみが接続できる設計になります。

レイヤ 3 — セッションログ: 接続時の入出力は CloudWatch Logs と S3 に自動保存できます。S3 に保存された録画ログは KMS 暗号化が可能で、監査要件を満たす改ざん不可能なエビデンスになります。

2-3. SSO 全体図 (QG-1)

SSO 全体図: 外部 IdP → SAML/SCIM → IC → Permission Set → AWS アカウント → SSM Session

  1. 外部 IdP 認証: ユーザーが Azure AD / Okta / Google Workspace でログイン (MFA 込み)
  2. SAML フェデレーション: 外部 IdP が SAML 2.0 Assertion を IC に送信
  3. IC がユーザー検証: SAML Assertion の NameID と SCIM プロビジョニング済みユーザーを突合
  4. SSO Portal 表示: ユーザーが割当済みアカウント × Permission Set の一覧を確認
  5. STS AssumeRoleWithSAML: IC が STS に代理で AssumeRole リクエスト → 一時クレデンシャル発行
  6. 一時クレデンシャル取得: aws sso login または SSO Portal の「Access Keys」で取得
  7. SSM StartSession: aws ssm start-session --target i-xxxx で EC2/ECS/RDS に接続
  8. セッションログ記録: 入出力が CloudWatch Logs + S3 に自動保存される

重要ポイント: Access Key は一切存在しない。一時クレデンシャルは最大 12 時間で自動失効。SSH ポートは閉じたまま。

2-4. 認証フロー詳細

SSO Portal からの認証フローを API レベルで追います。

[ユーザー]  │  ├─ 1. https://d-xxxxxxxxxx.awsapps.com/start/ にアクセス  │ ↓  ├─ 2. 外部 IdP (Azure AD) にリダイレクト → MFA 認証  │ ↓  ├─ 3. SAML Response を IC に POST  │ ↓  ├─ 4. IC が STS に AssumeRoleWithSAML を発行  │ STS レスポンス: AccessKeyId / SecretAccessKey / SessionToken (有効期限付き)  │ ↓  ├─ 5. aws sso login → ~/.aws/sso/cache/ に token 保存  │ ↓  └─ 6. aws ssm start-session --target i-0abc1234def --region ap-northeast-1 ↓SSM Agent が Systems Manager エンドポイントに WebSocket で接続 ↓ターミナルセッション確立 (SSH ポート不要)</code>

aws sso login を実行すると ~/.aws/sso/cache/ に JSON トークンが保存され、有効期限内は再ログイン不要です。Permission Set の Session Duration (デフォルト 1 時間、最大 12 時間) を超えると再認証が必要です。

CLI プロファイル設定例:

# ~/.aws/config[profile prod-ops]sso_start_url = https://d-xxxxxxxxxx.awsapps.com/start/sso_region = ap-northeast-1sso_account_id = 123456789012sso_role_name = OperatorPermissionSetregion = ap-northeast-1output = json</code>
# 認証とセッション開始 (2 コマンドで完了)aws sso login --profile prod-opsaws ssm start-session --target i-0abcdef1234567890 --profile prod-ops</code>

2-5. IAM User との違い

IAM User (従来方式) vs IAM Identity Center (本記事) 比較

観点IAM User (従来)IAM Identity Center (本記事)
クレデンシャル種別Access Key (長期・手動ローテーション)一時クレデンシャル (STS・自動失効)
SSH キー.pem ファイルを手動配布・管理不要 (Session Manager 経由)
退職者対応IAM ユーザー削除 + Access Key 無効化を手動実行外部 IdP でユーザー無効化 → 即時接続不能
マルチアカウント管理アカウントごとに IAM ユーザー作成IC 一元管理 (アカウント数に依存しない)
MFA 強制IAM ポリシーで個別設定 (漏れが出やすい)外部 IdP で一元強制 / Permission Set で追加強制
監査ログCloudTrail のみ (操作ログのみ)CloudTrail + SM Logs + S3 録画の完全監査
コンプライアンス対応別途追加実装が必要設計に監査・録画が内包されている

Access Key の最大の問題は「長期クレデンシャル」であることです。一時クレデンシャルは最大 12 時間で失効するため、漏洩しても被害範囲が限定されます。また、IAM ユーザーは個人アカウント数だけ存在するため、マルチアカウント環境で管理コストが線形に増加します。IC では IdP グループと Permission Set の組み合わせで指数的な管理効率化が実現します。

2-6. 対応外部 IdP

IAM Identity Center は以下の外部 IdP に対応しています。

IdPSAML 2.0SCIM 自動同期AWS 公式統合
Azure AD (Microsoft Entra ID)✅ (専用ドキュメント)
Okta✅ (専用ドキュメント)
Google Workspace✅ (専用ドキュメント)
OneLogin
PingFederate
JumpCloud
IAM Identity Center 組込み IdP— (不要)— (手動)

外部 IdP 連携なしで IC の「組込み IdP」を使うこともできますが、ユーザー管理が手動になるため 10 人以上の組織では外部 IdP 連携を推奨します。本記事の §3 では Azure AD を例に SAML/SCIM 設定手順を解説します。SCIM を有効化すると、Azure AD のグループメンバー変更が即時 IC に同期されます。

なお、SAML と SCIM は役割が異なります。SAML は「認証」(ログイン時の本人確認) を担い、SCIM は「プロビジョニング」(ユーザー・グループ情報の自動同期) を担います。SAML のみでも IC は動作しますが、SCIM を追加することで IdP 側のグループ変更が IC に自動反映されるため、SCIM の有効化を強く推奨します。

2-7. サポートリソース

SSM Session Manager が対応する接続先とその用途を整理します。

接続パターン対象リソース用途踏み台不要
パターン A: EC2 直接 SSMEC2 (Linux / Windows)シェル操作・ログ確認・デプロイ
パターン B: ECS ExecECS Fargate / EC2 タスクコンテナ内デバッグ・環境変数確認
パターン C: RDS Port ForwardingRDS / Aurora (Private Subnet)DB クライアント接続
パターン D: Windows RDPEC2 Windows ServerGUI 操作 (踏み台なし RDP)

4 つのパターンを使い分けることで、踏み台 EC2 を完全廃止できます。踏み台 EC2 の廃止は月額数千〜数万円のコスト削減と、常時起動インスタンスという攻撃面の排除を同時に実現します。

パターン A〜D はいずれも SSM Agent がインターネットへのアウトバウンド HTTPS (443) で通信します。Private Subnet 内に配置されたリソースには VPC Endpoint が必要ですが (§5-7 参照)、パブリックサブネットまたは NAT Gateway 経由でインターネットに出られる構成では VPC Endpoint 不要で即日導入できます。まず小規模な検証環境 (パブリックサブネット) で動作確認し、その後 Private Subnet + VPC Endpoint 構成に移行するアプローチが実務ではスムーズです。

§5 では各パターンの Terraform + CLI + コンソール操作を 3 点セットで解説します。§3 では IC の初期設定、§4 では Permission Set 6 パターンの Terraform 実装を詳述します。

費用目安 (東京リージョン・2026-04 時点)

コンポーネント費用
IAM Identity Center 本体無料 (Organization 機能)
SSM Session Manager無料 (Systems Manager の標準機能)
VPC Endpoint (Private Subnet 利用時)約 $14〜$20/月 (3 エンドポイント × 2 AZ)
Session Manager ログ (CloudWatch Logs)ログ量に応じた従量課金 (約 $0.50/GB 保存)
Session Manager 録画 (S3)約 $0.023/GB (Standard ストレージ)
踏み台 EC2 廃止による削減t3.micro で -$8〜$10/月 / t3.small で -$15〜$20/月

踏み台 EC2 廃止により、VPC Endpoint の費用を上回るコスト削減が見込める構成が多いです。2 台の踏み台 EC2 (t3.small) を廃止すれば月額 $30〜$40 の削減になり、VPC Endpoint 費用 ($15〜$20) を差し引いても月額 $10〜$20 のネットコスト削減が期待できます。

アーキテクチャ全体の関係性

IC と SM は独立したサービスですが、Permission Set を通じて緊密に連携します。IC が「誰が」を決定し (認証・認可)、SM が「どのリソースに・どのように」接続するかを制御します (接続・録画)。この 2 サービスの組み合わせが、人手キー廃止の根幹です。次章以降では、この関係性を具体的な設定手順として展開します。

本章で示した全体像のポイントを改めて整理します。(1) IC は Organizations の管理アカウントで有効化し、外部 IdP と SAML/SCIM で連携する。(2) Permission Set は IAM Role テンプレートとして機能し、IC ユーザーが AWS にアクセスする際の権限範囲を決定する。(3) SSM Session Manager は SSH キーも踏み台も不要にし、EC2/ECS/RDS/RDP の 4 接続を統一する。(4) 全セッションは CloudWatch Logs + S3 に自動録画され、監査要件を満たすエビデンスになる。この 4 点が本記事を通じて実装するアーキテクチャの核心です。

次の §3 では IC の Organization 連携と外部 IdP (Azure AD) の SAML/SCIM 接続を、Terraform + CLI + コンソールの 3 点セットで実装します。IC を有効化したことがない方は §3 から順に読み進めることを推奨します。既に IC を有効化済みの場合は §4 (Permission Set 6 パターン) から直接参照できます。

§2 の全体像を把握したうえで各章を読み進めることで、「今どの部分を実装しているか」が常に明確になり、長編ガイドの各章を断片的な知識として終わらせず、IC + SSM を統合した理解を構築できます。


3. IC 初期設定 (Organization + 外部 IdP + SCIM)

fig03: IC 初期設定フロー

IAM Identity Center の初期設定は AWS Organizations の有効化から始まり、外部 IdP (Azure AD / Okta / Google Workspace) との SAML/SCIM 接続、Permission Set の基礎設定まで一連のフローを踏む。本章では Azure AD を例に、コンソール操作・Terraform・CLI の 3 点セットで初期設定を完了させる手順を解説する。

3-1. Organization 有効化 + IAM Identity Center Enable

IAM Identity Center は AWS Organizations のマスターアカウントで有効化する必要がある。Organizations が既に有効な環境では手順 1-2 をスキップできる。

コンソール操作手順

  1. AWS Management Console → AWS Organizations組織を作成 をクリック
  2. 有効化後、マスターアカウントで IAM Identity Center をサービス検索
  3. IAM Identity Center を有効にする ボタン → 有効にする をクリック
  4. ID ソースの選択画面が表示される (デフォルト: Identity Center ディレクトリ)

注意: IAM Identity Center は 1 リージョンにのみ設定可能。東京リージョン (ap-northeast-1) での有効化を推奨。一度設定したホームリージョンは変更不可。

Terraform で Organizations の状態確認

# 既存 Organizations への接続確認data "aws_organizations_organization" "current" {}output "org_id" {  value = data.aws_organizations_organization.current.id}output "master_account_id" {  value = data.aws_organizations_organization.current.master_account_id}</code>

IAM Identity Center 自体は Terraform リソースで直接有効化できないため、初回のみコンソールから有効化し、SSO インスタンスの ARN を data source で取得する:

# SSO インスタンス情報の取得data "aws_ssoadmin_instances" "this" {}locals {  sso_instance_arn= tolist(data.aws_ssoadmin_instances.this.arns)[0]  sso_identity_store_id = tolist(data.aws_ssoadmin_instances.this.identity_store_ids)[0]}</code>

3-2. 外部 IdP 選択 (Azure AD を例に)

IAM Identity Center がサポートする主要な外部 IdP の比較:

IdPSAML 対応SCIM 対応自動設定ガイド
Azure AD (Microsoft Entra ID)✅ ギャラリーアプリあり
Okta✅ ギャラリーアプリあり
Google Workspace✅ ギャラリーアプリあり
OneLogin△ 手動設定
Ping Identity△ 手動設定
IC ディレクトリ (Built-in)✅ 外部 IdP 不要

本章では Azure AD (Microsoft Entra ID) を使用した設定を解説する。

コンソール操作: ID ソースを外部 IdP に変更

  1. IAM Identity Center コンソール → 設定ID ソースID ソースを変更
  2. 外部の ID プロバイダー を選択
  3. SAML メタデータの設定 ページで以下の値をコピー (Azure AD の設定で使用):
  4. IAM Identity Center ACS URL (Assertion Consumer Service URL)
  5. IAM Identity Center 発行者 URL (SP Entity ID)
  6. IAM Identity Center サインイン URL

3-3. SAML Connector 設定 (ACS URL / SP Entity ID / X.509 証明書)

Azure AD 側の設定手順 (2026-04 時点)

  1. Azure Portal → Microsoft Entra IDエンタープライズ アプリケーション
  2. 新しいアプリケーション → ギャラリーで “AWS IAM Identity Center” を検索して追加
  3. アプリ追加後、シングル サインオンSAML を選択
  4. 基本的な SAML 構成 で以下を設定:
項目
識別子 (エンティティ ID)IC の「発行者 URL」をペースト
応答 URL (ACS URL)IC の「ACS URL」をペースト
サインオン URLIC の「サインイン URL」をペースト
リレー状態(空白のまま)
  1. SAML 署名証明書フェデレーション メタデータ XML をダウンロード

IC 側に Azure AD のメタデータをアップロード

  1. IAM Identity Center コンソール → 設定ID ソース
  2. 外部 IdP のメタデータ セクションで XML ファイルをアップロード
  3. 外部 IdP の証明書 が反映されることを確認
  4. 変更を確定する をクリック (ユーザーへの影響を確認する警告が表示される)

重要: 変更確定後、既存の IC ディレクトリユーザーは無効化される。事前に Azure AD 側でユーザーが作成・割当済みであることを確認してから確定すること。

3-4. SCIM 有効化 (自動プロビジョニング + 属性マッピング)

SCIM を有効にすると、Azure AD のユーザー/グループ変更が IAM Identity Center に自動同期される。手動でのユーザー追加が不要になり、入退社・異動時の棚卸しコストが大幅に削減される。

IC 側で SCIM を有効化

  1. IAM Identity Center コンソール → 設定ID ソース
  2. プロビジョニング セクション → SCIM プロビジョニングを有効にする
  3. 表示される SCIM エンドポイント URLアクセストークン をコピーして安全な場所に保存

アクセストークンはこの画面でのみ表示される。再確認できないため必ずコピーすること。

Azure AD 側でプロビジョニング設定

  1. エンタープライズ アプリ → AWS IAM Identity Center → プロビジョニング
  2. プロビジョニング モード: 自動 を選択
  3. 管理者資格情報 を入力:
  4. テナント URL: IC の SCIM エンドポイント URL
  5. シークレット トークン: IC のアクセストークン
  6. 接続のテスト → 成功を確認 → 保存
  7. プロビジョニング状態オン に切り替え

属性マッピングの確認 (重要)

Azure AD 属性IC 属性必須
userPrincipalNameuserName
displayNamedisplayName
mailemails[primary eq true].value
givenNamename.givenName
surnamename.familyName
accountEnabledactive

3-5. グループ設計 (Dev / Ops / Admin / Security)

IAM Identity Center では グループ単位で Permission Set を割り当てることが推奨される。個人ユーザーへの直接割当は管理コストが高く、定期棚卸しが困難になる。

推奨グループ構成

グループ名割当 Permission Set対象 AWS アカウント主な用途
aws-readonlyReadOnly全アカウント監査・外部コンサルタント
aws-operatorsOperatorProduction / Staging日次運用担当
aws-adminsAdmin (時限付き)Production変更・デプロイ作業
aws-db-adminsDB AdminProductionRDS 管理専用
aws-network-adminsNetwork AdminProductionVPC・SG 管理
aws-emergencyEmergency全アカウントBreak-glass (障害時限定)

Azure AD でこれらのグループを作成し、SCIM 同期後に IC 側へ自動反映される。IC 側での手動グループ作成は不要。

3-6. Permission Set 基礎 (AWS 管理ポリシー / カスタムポリシー / 時間制限)

Permission Set は IAM の Role 相当の権限セットであり、IC ユーザーが AWS アカウントにアクセスする際に付与される一時的な権限の定義体。

Permission Set に設定可能な権限の種類

種類設定方法ユースケース
AWS 管理ポリシーARN で指定ReadOnlyAccess / PowerUserAccess
カスタムインラインポリシーJSON で直接記述SSMStartSession 等の細粒度制御
カスタム管理ポリシー参照管理ポリシー ARN を指定自社共通ポリシーの再利用
Permission BoundaryARN で指定権限の上限設定

Session Duration の設定指針

役割推奨 Duration理由
ReadOnly8h監査・調査は長時間ワーク対応
Operator4h日次運用は半日以内に完結
Admin2h変更作業は短時間に制限
DB Admin2hDB 接続は定時内に限定
Network Admin2h設定変更は定時内に限定
Emergency1hBreak-glass は最短・MFA 強制

3-7. CLI 動作確認 (aws sso login + aws sts get-caller-identity)

外部 IdP 連携が完了したら、AWS CLI で SSO ログインを確認する。

AWS CLI プロファイル設定

# 対話型でプロファイルを設定aws configure sso --profile production-operator# SSO session name: my-company-sso# SSO start URL: https://d-xxxxxxxxxx.awsapps.com/start# SSO Region: ap-northeast-1# SSO registration scopes: (Enter でスキップ)# 設定後の ~/.aws/config 例:# [profile production-operator]# sso_session = my-company-sso# sso_account_id = 123456789012# sso_role_name = Operator# region = ap-northeast-1# output = json## [sso-session my-company-sso]# sso_start_url = https://d-xxxxxxxxxx.awsapps.com/start# sso_region = ap-northeast-1# sso_registration_scopes = sso:account:access</code>

SSO ログインと認証確認

# SSO ログイン (ブラウザで Azure AD 認証が起動)aws sso login --profile production-operator# 認証確認: 自分のアイデンティティを確認aws sts get-caller-identity --profile production-operator# 出力形式例:# {#"UserId": "AROAXXXXXXXXXXXXXXXXX:user@example.com",#"Account": "123456789012",#"Arn": "arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_Operator_xxxx/user@example.com"# }# TODO: 実機出力を貼付・上記はサンプル形式のみ# アクセス可能なアカウント一覧を確認aws sso list-accounts \  --profile production-operator \  --output table# アカウント内のロール一覧aws sso list-account-roles \  --account-id 123456789012 \  --profile production-operator \  --output table</code>

Terraform での Permission Set 基礎確認 (data source)

# 既存の Permission Set を data source で参照data "aws_ssoadmin_permission_set" "read_only" {  instance_arn = local.sso_instance_arn  name= "ReadOnly"}output "read_only_permission_set_arn" {  value = data.aws_ssoadmin_permission_set.read_only.arn}</code>

動作確認タイミング: SSO ログイン後、セッションは ~/.aws/sso/cache/ に JSON 形式でキャッシュされる。有効期限 (Session Duration) 経過後は再ログインが必要。

よくある IdP 設定ミス (Azure AD / Okta 共通)

  • ACS URL / Entity ID の貼り間違い — IC コンソールから EXACT コピーすること。末尾スラッシュの有無も厳密に一致させる。スペース混入にも注意。
  • SAML 属性マッピング漏れuserName (メールアドレス形式) が未マッピングだと IC 側でユーザーを識別できずログイン失敗。userPrincipalNameuserName のマッピングを最初に確認。
  • SCIM トークンの再生成事故 — IC 側でトークンを再生成すると Azure AD 側の設定が無効化されてプロビジョニング停止。変更後は必ず Azure AD 側も更新すること。
  • グループ同期の遅延 — SCIM 初回同期は最大 40 分かかる場合がある。Azure AD の「今すぐプロビジョニング」で強制同期可能。
  • MFA ポリシーの二重設定 — Azure AD 側で MFA を要求し、かつ IC でも MFA を強制すると二重認証になる。どちら側で統一するか事前に決定すること。
  • シングルサインアウト (SLO) 未設定 — Azure AD 側でログアウトしても IC セッションが残存する場合がある。SAML SLO の設定を確認。
  • IC ホームリージョンと CLI リージョン不一致sso_region は IC を有効化したリージョン (例: ap-northeast-1) に統一すること。

4. Permission Set 6 パターン (設計 + Terraform 完全実装)

Permission Set の設計は IAM Identity Center 運用の核心である。権限が広すぎると最小権限原則に反し、狭すぎると運用効率が落ちる。本章では実務で使い回せる 6 パターンを定義し、Terraform で完全実装する。

4-1. 設計原則 (最小権限 / 時間制限 / MFA 強制)

Permission Set を設計する際の 3 原則:

原則 1: 最小権限 (Least Privilege)
– 業務上必要な権限のみを付与。AdministratorAccess は Emergency のみに限定
– カスタムインラインポリシーで ssm:StartSession 等の細粒度制御を優先
* ワイルドカードは Resource レベルでも極力回避

原則 2: 時間制限 (Session Duration)
– 管理者権限は 1〜4h に制限。ReadOnly のみ 8h まで許容
– セッション期限切れは aws sso login で再認証可能
– 長時間セッションはセキュリティリスク (盗難クレデンシャルの悪用窓口が広がる)

原則 3: MFA 強制 (Admin / Emergency 必須)
– Admin・Emergency Permission Set には MFA Enforcement を IC 設定で強制
– MFA デバイスは IC の MFA ポリシーで管理 (外部 IdP の MFA と統合可能)
– Break-glass (Emergency) は MFA + 全操作 Slack 通知の二重防護が必須

4-2. Permission Set 6 パターン比較表 (QG-2)

Permission Set 6 パターン — 実務設計テンプレート (QG-2)

パターン名称AWS 管理ポリシーカスタムポリシーSession DurationMFA主な対象
(a) ReadOnlyReadOnlyReadOnlyAccessなし8h任意監査・コンサルタント・開発者 (参照のみ)
(b) OperatorOperatorCloudWatchReadOnlyAccessSSMStartSession + logs:GetLogEvents4h任意日次運用担当 (サーバー接続・ログ確認)
(c) AdminAdminAdministratorAccessなし (Boundary で制限推奨)2h必須変更・デプロイ担当 (時限付き管理者)
(d) DB AdminDBAdminAmazonRDSFullAccessssm:StartSession (RDS Port FW 専用)2h推奨DBA・RDS 管理担当
(e) Network AdminNetworkAdminなしec2:VPC/SG/RouteTable 操作 + SSMStartSession2h推奨インフラ担当 (VPC・SG・ルーティング)
(f) EmergencyEmergencyAdministratorAccessCloudWatch PutMetricData (通知強制)1h必須Break-glass — 障害対応のみ・全操作通知

設計指針: (c) Admin と (f) Emergency の違いは「通常変更 vs 障害対応」であり、どちらも AdministratorAccess を持つが Emergency は Session Duration 1h + 全操作を CloudWatch Alarm で検知する二重防護が必須。

4-3. Terraform aws_ssoadmin_permission_set 実装 (6 パターン全て)

# permission_sets.tf — Permission Set 6 パターン完全実装# Terraform 1.9.x / hashicorp/aws ~> 5.0################################################################################ (a) ReadOnly — 監査・コンサルタント向け###############################################################################resource "aws_ssoadmin_permission_set" "read_only" {  name = "ReadOnly"  description= "Read-only access for audit and consulting"  instance_arn  = local.sso_instance_arn  session_duration = "PT8H"  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_ssoadmin_managed_policy_attachment" "read_only" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.read_only.arn  managed_policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"}################################################################################ (b) Operator — 日次運用担当 (SSM + CloudWatch Read)###############################################################################resource "aws_ssoadmin_permission_set" "operator" {  name = "Operator"  description= "Daily operations: SSM Session + CloudWatch read"  instance_arn  = local.sso_instance_arn  session_duration = "PT4H"  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_ssoadmin_managed_policy_attachment" "operator_cw" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.operator.arn  managed_policy_arn = "arn:aws:iam::aws:policy/CloudWatchReadOnlyAccess"}resource "aws_ssoadmin_permission_set_inline_policy" "operator" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.operator.arn  inline_policy = jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "SSMStartSession"  Effect = "Allow"  Action = [ "ssm:StartSession", "ssm:TerminateSession", "ssm:ResumeSession", "ssm:DescribeSessions", "ssm:GetConnectionStatus"  ]  Resource = "*"},{  Sid = "CloudWatchLogs"  Effect = "Allow"  Action = [ "logs:GetLogEvents", "logs:FilterLogEvents", "logs:DescribeLogGroups", "logs:DescribeLogStreams"  ]  Resource = "*"} ]  })}################################################################################ (c) Admin — 時限付き管理者 (MFA 強制 / 2h)###############################################################################resource "aws_ssoadmin_permission_set" "admin" {  name = "Admin"  description= "Time-limited administrator with MFA enforcement"  instance_arn  = local.sso_instance_arn  session_duration = "PT2H"  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_ssoadmin_managed_policy_attachment" "admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.admin.arn  managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"}################################################################################ (d) DB Admin — RDS 管理 + RDS Port Forwarding 専用###############################################################################resource "aws_ssoadmin_permission_set" "db_admin" {  name = "DBAdmin"  description= "RDS administration and Port Forwarding via SSM"  instance_arn  = local.sso_instance_arn  session_duration = "PT2H"  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_ssoadmin_managed_policy_attachment" "db_admin_rds" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.db_admin.arn  managed_policy_arn = "arn:aws:iam::aws:policy/AmazonRDSFullAccess"}resource "aws_ssoadmin_permission_set_inline_policy" "db_admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.db_admin.arn  inline_policy = jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "SSMPortForwarding"  Effect = "Allow"  Action = [ "ssm:StartSession", "ssm:TerminateSession"  ]  Resource = [ "arn:aws:ssm:*:*:document/AWS-StartPortForwardingSessionToRemoteHost"  ]},{  Sid = "SSMSessionDescribe"  Effect = "Allow"  Action = [ "ssm:DescribeSessions", "ssm:GetConnectionStatus", "ec2:DescribeInstances"  ]  Resource = "*"} ]  })}################################################################################ (e) Network Admin — VPC / Route Table / Security Group 専用###############################################################################resource "aws_ssoadmin_permission_set" "network_admin" {  name = "NetworkAdmin"  description= "VPC, Route Table, Security Group management"  instance_arn  = local.sso_instance_arn  session_duration = "PT2H"  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_ssoadmin_permission_set_inline_policy" "network_admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.network_admin.arn  inline_policy = jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "VPCManagement"  Effect = "Allow"  Action = [ "ec2:CreateVpc", "ec2:DeleteVpc", "ec2:ModifyVpcAttribute", "ec2:CreateSubnet", "ec2:DeleteSubnet", "ec2:ModifySubnetAttribute", "ec2:CreateRouteTable", "ec2:DeleteRouteTable", "ec2:CreateRoute", "ec2:DeleteRoute", "ec2:ReplaceRoute", "ec2:AssociateRouteTable", "ec2:DisassociateRouteTable", "ec2:CreateSecurityGroup", "ec2:DeleteSecurityGroup", "ec2:AuthorizeSecurityGroupIngress", "ec2:RevokeSecurityGroupIngress", "ec2:AuthorizeSecurityGroupEgress", "ec2:RevokeSecurityGroupEgress", "ec2:CreateInternetGateway", "ec2:DeleteInternetGateway", "ec2:AttachInternetGateway", "ec2:DetachInternetGateway", "ec2:Describe*"  ]  Resource = "*"},{  Sid = "SSMForNetworkOps"  Effect = "Allow"  Action = [ "ssm:StartSession", "ssm:TerminateSession", "ssm:DescribeSessions", "ssm:GetConnectionStatus"  ]  Resource = "*"} ]  })}################################################################################ (f) Emergency — Break-glass (MFA 必須 / 1h / 全操作通知)###############################################################################resource "aws_ssoadmin_permission_set" "emergency" {  name = "Emergency"  description= "Break-glass: full access, 1h session, MFA required, all actions alerted"  instance_arn  = local.sso_instance_arn  session_duration = "PT1H"  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_ssoadmin_managed_policy_attachment" "emergency" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.emergency.arn  managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"}resource "aws_ssoadmin_permission_set_inline_policy" "emergency" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.emergency.arn  inline_policy = jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "ForceCloudWatchAlert"  Effect = "Allow"  Action = [ "cloudwatch:PutMetricData", "sns:Publish"  ]  Resource = "*"} ]  })}</code>

4-4. Session Duration / MFA 強制の設定

Session Duration の変更 (コンソール操作)

  1. IAM Identity Center コンソール → AWS アカウントPermission Sets
  2. 対象 Permission Set を選択 → 編集
  3. セッション期間 を選択 (1h / 2h / 4h / 8h / 12h から選択可)
  4. 変更を保存 → 既存セッションには影響しない (次回ログイン時から適用)

MFA 強制の設定 (IC レベル)

# MFA 設定確認 (CLI)aws sso-admin list-mfa-configurations \  --instance-arn "arn:aws:sso:::instance/ssoins-xxxxxxxxxxxxxxxx" \  --profile management-admin# TODO: 実機出力を貼付</code>

コンソールで MFA ポリシーを設定

  1. IAM Identity Center コンソール → 設定認証
  2. 多要素認証設定を構成する
  3. MFA タイプ: すべての MFA タイプ を有効化 (TOTP / FIDO2 等)
  4. MFA を要求する条件: Admin / Emergency 用グループに 常に MFA を要求 を設定

推奨: Admin・Emergency 専用の MFA ポリシーを作成し、他のロールとは分離すること。Azure AD で Conditional Access Policy を設定している場合は、IC 側の MFA 設定と統合するか排他設定にするかを事前に決定する。

4-5. Permission Set → AWS Account への割当 (aws_ssoadmin_account_assignment)

# account_assignments.tf — Permission Set を AWS アカウントとグループに割当data "aws_identitystore_group" "operators" {  identity_store_id = local.sso_identity_store_id  alternate_identifier { unique_attribute {attribute_path  = "DisplayName"attribute_value = "aws-operators" }  }}data "aws_identitystore_group" "admins" {  identity_store_id = local.sso_identity_store_id  alternate_identifier { unique_attribute {attribute_path  = "DisplayName"attribute_value = "aws-admins" }  }}data "aws_identitystore_group" "emergency" {  identity_store_id = local.sso_identity_store_id  alternate_identifier { unique_attribute {attribute_path  = "DisplayName"attribute_value = "aws-emergency" }  }}variable "production_account_id" {  description = "Production AWS Account ID"  type  = string}resource "aws_ssoadmin_account_assignment" "operator_production" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.operator.arn  principal_id = data.aws_identitystore_group.operators.group_id  principal_type  = "GROUP"  target_id = var.production_account_id  target_type  = "AWS_ACCOUNT"}resource "aws_ssoadmin_account_assignment" "admin_production" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.admin.arn  principal_id = data.aws_identitystore_group.admins.group_id  principal_type  = "GROUP"  target_id = var.production_account_id  target_type  = "AWS_ACCOUNT"}resource "aws_ssoadmin_account_assignment" "emergency_production" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.emergency.arn  principal_id = data.aws_identitystore_group.emergency.group_id  principal_type  = "GROUP"  target_id = var.production_account_id  target_type  = "AWS_ACCOUNT"}</code>

CLI での割当確認

# Permission Set のアカウント割当状況確認aws ssoadmin list-account-assignments \  --instance-arn "arn:aws:sso:::instance/ssoins-xxxxxxxxxxxxxxxx" \  --account-id 123456789012 \  --permission-set-arn "arn:aws:sso:::permissionSet/ssoins-xxxx/ps-xxxx" \  --profile management-admin \  --output table# TODO: 実機出力を貼付# 伝搬状況の確認aws ssoadmin list-permission-sets-provisioned-to-account \  --instance-arn "arn:aws:sso:::instance/ssoins-xxxxxxxxxxxxxxxx" \  --account-id 123456789012 \  --profile management-admin# TODO: 実機出力を貼付</code>

4-6. Permission Set 伝搬時間の注意 (5-30 分かかる)

Permission Set を新規作成・更新した後、AWS アカウントへの伝搬には 5〜30 分かかる場合がある。Terraform apply 直後に CLI でログインしようとしても “Role does not exist” エラーが発生する場合は伝搬待ちが原因。

fig06: Permission Set 6 パターン判定フロー

Permission Set 伝搬時間の対策と確認方法

  • 伝搬状況の確認コマンド: aws ssoadmin list-permission-sets-provisioned-to-accountPROVISIONED 状態になるまで待機
  • 手動で伝搬を強制する: IC コンソール → AWS アカウント → Permission Set を選択 → 再プロビジョニング で即時伝搬を試みることができる
  • Terraform での待機: aws_ssoadmin_account_assignment は作成後の伝搬を自動待機しない。time_sleep リソースや CI/CD パイプラインでの待機ステップを設けること
  • Organization レベルの伝搬: Organization 全アカウントへ一括プロビジョニングする場合は伝搬が最大 30 分かかる。夜間バッチでの適用を推奨
  • よくある誤解: Permission Set の「編集」(ポリシー内容の変更) も再プロビジョニングが必要。グループ割当の変更は即時反映されることが多いが、インラインポリシーの変更は伝搬を待つこと

5. SSM Session Manager 4 接続パターン

fig04: SSM Session Manager 4 接続パターン

SSH キーも踏み台 EC2 も不要にする — それが SSM Session Manager の本質的な価値だ。
本章では EC2 直接接続 / ECS Exec / RDS Port Forwarding / Windows RDP の 4 パターンを
Terraform + AWS CLI + コンソール操作の 3 点セットで完備する。


5-1. 接続パターン一覧と前提条件

SSM Session Manager は AWS Systems Manager の機能で、SSM Agent が稼働している EC2 や
ECS コンテナへ HTTPS (TCP 443) 経由でセキュアな Shell セッションを確立する。
SSH ポート (TCP 22) の開放が不要なため、セキュリティグループの 22 番を閉じたまま
本番環境を運用できる。踏み台 EC2 の 24 時間稼働コストと管理負荷も同時に排除できる。

4 パターン共通の前提条件:

前提条件必要な設定
AWS CLI v2Session Manager Plugin インストール済み (session-manager-plugin)
SSO 認証aws sso login --profile <profile> 完了・一時クレデンシャル有効
IAM 権限ssm:StartSession 権限 (Permission Set に含まれること)
VPC 構成Private Subnet 利用時は VPC Endpoint 3 本 (§5-7 参照) 必須

5-2. 4 接続比較表 (QG-3)

SSM Session Manager 4 接続パターン比較表

パターン対象リソースCLI コマンド (抜粋)前提条件主なユースケース
A: EC2 直接 SSMEC2 (Linux / Windows)aws ssm start-session --target i-xxxSSM Agent 稼働 + IAM Role (AmazonSSMManagedInstanceCore)Linux サーバーへの日次 Ops 作業・ログ確認
B: ECS ExecECS Fargate / EC2aws ecs execute-command --cluster X --task Y --command bash --interactiveTask Role (ssmmessages:*) + enableExecuteCommand=trueFargate コンテナへのデバッグ・ログ取得
C: RDS Port FWRDS / Aurora (踏み台なし)aws ssm start-session --document-name AWS-StartPortForwardingSessionToRemoteHostEC2 中継機 (SSM Agent) + Port FW 権限ローカル PC から直接 mysql / psql 接続
D: Windows RDPWindows EC2aws ssm start-session --document-name AWS-StartPortForwardingSessionSSM Agent (Windows) + IAM Role + RDP クライアント踏み台なしでの Windows リモートデスクトップ

5-3. パターン A: EC2 直接 SSM

最もシンプルな接続パターン。SSH キー不要・セキュリティグループの 22 番開放不要で
Linux / Windows EC2 に直接 Shell セッションを開始する。

SSM Agent の確認

Amazon Linux 2023 / Amazon Linux 2 には SSM Agent がプリインストール済みだ。
Ubuntu や他の AMI では手動インストールが必要になる。

# Amazon Linux 2023 / AL2 での SSM Agent ステータス確認sudo systemctl status amazon-ssm-agent# Ubuntu 22.04 での手動インストールsudo snap install amazon-ssm-agent --classicsudo systemctl enable amazon-ssm-agentsudo systemctl start amazon-ssm-agent</code>

Terraform: IAM Role (AmazonSSMManagedInstanceCore アタッチ)

resource "aws_iam_role" "ec2_ssm" {  name = "ec2-ssm-session-manager-role"  assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [{Effect = "Allow"Principal = { Service = "ec2.amazonaws.com" }Action = "sts:AssumeRole" }]  })  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_iam_role_policy_attachment" "ec2_ssm_core" {  role = aws_iam_role.ec2_ssm.name  policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"}resource "aws_iam_instance_profile" "ec2_ssm" {  name = "ec2-ssm-instance-profile"  role = aws_iam_role.ec2_ssm.name}</code>

AWS CLI での接続

# SSO ログイン (未認証の場合)aws sso login --profile prod-ops# EC2 インスタンスへのセッション開始aws ssm start-session \  --target i-0abcdef1234567890 \  --profile prod-ops# 実機実行: 2026-04-XX (実機出力を貼付・AI生成禁止)# セッション終了: exit または Ctrl+D</code>

マネジメントコンソール操作

  1. AWS Systems ManagerSession Managerセッションを開始
  2. インスタンス一覧から対象 EC2 を選択 (接続可能なインスタンスのみ表示)
  3. セッションを開始 をクリック → ブラウザ内 Terminal が起動

5-4. パターン B: ECS Exec (Fargate / EC2 両対応)

ECS Exec は ECS タスク内のコンテナへ直接 Shell を提供する機能だ。
Fargate では従来 SSH 接続が不可能だったが、ECS Exec によってデバッグが可能になった。
SSM Session Manager が内部的に使われるため、EC2 の SSM Agent とは別の設定が必要だ。

Terraform: ECS サービスで ECS Exec を有効化

resource "aws_ecs_service" "app" {  name= "app-service"  cluster= aws_ecs_cluster.main.id  task_definition = aws_ecs_task_definition.app.arn  desired_count= 1  launch_type  = "FARGATE"  # ECS Exec の有効化 (false がデフォルト)  enable_execute_command = true  network_configuration { subnets = var.private_subnet_ids security_groups  = [aws_security_group.ecs_app.id] assign_public_ip = false  }  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}# Task Role に ssmmessages 権限を追加 (ECS Exec 必須)resource "aws_iam_role_policy" "ecs_exec_ssm" {  name = "ecs-exec-ssmmessages-policy"  role = aws_iam_role.ecs_task_role.id  policy = jsonencode({ Version = "2012-10-17" Statement = [{Effect = "Allow"Action = [  "ssmmessages:CreateControlChannel",  "ssmmessages:CreateDataChannel",  "ssmmessages:OpenControlChannel",  "ssmmessages:OpenDataChannel"]Resource = "*" }]  })}</code>

AWS CLI での接続

# 実行中タスクの ARN 取得aws ecs list-tasks \  --cluster my-cluster \  --service-name app-service \  --profile prod-ops# ECS Exec でコンテナへ接続aws ecs execute-command \  --cluster my-cluster \  --task arn:aws:ecs:ap-northeast-1:123456789012:task/my-cluster/abcdef1234567890 \  --container app \  --command "/bin/bash" \  --interactive \  --profile prod-ops# 実機実行: 2026-04-XX (実機出力を貼付・AI生成禁止)</code>

Fargate と EC2 起動タイプの差異: Fargate ではコンテナ内 Shell のみ提供。
EC2 起動タイプではホスト OS への接続はパターン A (EC2 直接 SSM) で別途行う。
ECS Exec はコンテナ内デバッグ専用と考えると整理しやすい。

マネジメントコンソール操作

ECS Exec はコンソールから直接操作できない (CLI 専用)。
コンソールではタスクの enableExecuteCommand ステータスを ECS → タスク → 設定タブ
で確認できる。


5-5. パターン C: RDS Port Forwarding (踏み台なし DB 接続)

RDS / Aurora への接続は従来、踏み台 EC2 経由の SSH トンネルが標準構成だった。
SSM Port Forwarding を使えば、EC2 の SSH ポート (22) を開放せずに
ローカル PC から直接 RDS エンドポイントへ接続できる。

構成概要

ローカル PC (mysql/psql) → SSM (HTTPS:443) → EC2 中継機 (SSM Agent) → RDS/Aurora</code>

EC2 は中継役として機能するが、SSH ではなく SSM Agent 経由でトンネルを確立するため
セキュリティグループの TCP 22 開放が不要だ。

AWS CLI での接続 (RDS Port Forwarding)

# ステップ 1: ローカルポート 15432 → RDS エンドポイント 5432 へのトンネル確立aws ssm start-session \  --target i-0abcdef1234567890 \  --document-name AWS-StartPortForwardingSessionToRemoteHost \  --parameters '{"host":["mydb.cluster-xxxx.ap-northeast-1.rds.amazonaws.com"],"portNumber":["5432"],"localPortNumber":["15432"]}' \  --profile prod-ops# 実機実行: 2026-04-XX (実機出力を貼付・AI生成禁止)# ステップ 2: 別ターミナルでローカル接続# PostgreSQL (Aurora PostgreSQL / RDS PostgreSQL)psql -h 127.0.0.1 -p 15432 -U dbadmin -d mydb# MySQL (Aurora MySQL / RDS MySQL)mysql -h 127.0.0.1 -P 13306 -u admin -p</code>

Terraform: Port Forwarding 権限の追加

resource "aws_iam_role_policy" "ssm_port_forwarding" {  name = "ssm-port-forwarding-policy"  role = aws_iam_role.ec2_ssm.id  policy = jsonencode({ Version = "2012-10-17" Statement = [{Effect = "Allow"Action = [  "ssm:StartSession",  "ssm:TerminateSession",  "ssm:ResumeSession",  "ssm:DescribeSessions",  "ssm:GetConnectionStatus"]Resource = [  "arn:aws:ec2:ap-northeast-1:*:instance/*",  "arn:aws:ssm:ap-northeast-1::document/AWS-StartPortForwardingSessionToRemoteHost"] }]  })}</code>

マネジメントコンソール操作

マネジメントコンソールでは Port Forwarding セッションを直接開始できない (CLI 専用)。
コンソールは Systems Manager → Session Manager → セッション履歴
接続ログの確認用途に利用する。


5-6. パターン D: Windows RDP over Port Forwarding (踏み台なし RDP)

Windows EC2 への RDP 接続も SSM Port Forwarding で実現できる。
RDP ポート (TCP 3389) をインターネットに公開する必要がなくなり、
セキュリティグループの 3389 番を完全に閉じた状態で運用できる。

AWS CLI での接続 (Windows RDP Port Forwarding)

# ステップ 1: ローカルポート 13389 → Windows EC2 の RDP ポート 3389 へのトンネル確立aws ssm start-session \  --target i-0windows1234567890 \  --document-name AWS-StartPortForwardingSession \  --parameters '{"portNumber":["3389"],"localPortNumber":["13389"]}' \  --profile prod-ops# 実機実行: 2026-04-XX (実機出力を貼付・AI生成禁止)</code>

ステップ 2: RDP クライアントで接続

接続先ホスト: localhost:13389ユーザー名: Administrator (または 設定済みのユーザー)パスワード: AWS コンソール → EC2 → インスタンス選択 → 「Windows パスワードを取得」</code>

macOS の場合は Microsoft Remote Desktop (App Store 無料) を使用し、
localhost:13389 へ接続する。

Windows SSM Agent の確認

# Windows PowerShell でのサービス確認Get-Service AmazonSSMAgent# 停止している場合Start-Service AmazonSSMAgentSet-Service AmazonSSMAgent -StartupType Automatic</code>

IAM Role は パターン A と同じ AmazonSSMManagedInstanceCore でよい。
セキュリティグループには HTTPS (443) アウトバウンドのみ許可すれば動作する。


5-7. Private Subnet + VPC Endpoint 構成 (Terraform)

Private Subnet 内のリソースに SSM でアクセスする場合、インターネットへの経路がないため
VPC Endpoint が必須になる。必要なエンドポイントは以下の 3 本だ。

エンドポイント用途
com.amazonaws.<region>.ssmSession Manager 制御チャネル
com.amazonaws.<region>.ec2messagesSSM Agent とのメッセージング
com.amazonaws.<region>.ssmmessagesSession Manager データチャネル
locals {  region = "ap-northeast-1"  ssm_endpoint_services = [ "com.amazonaws.${local.region}.ssm", "com.amazonaws.${local.region}.ec2messages", "com.amazonaws.${local.region}.ssmmessages",  ]}resource "aws_vpc_endpoint" "ssm" {  for_each = toset(local.ssm_endpoint_services)  vpc_id  = var.vpc_id  service_name  = each.value  vpc_endpoint_type= "Interface"  subnet_ids = var.private_subnet_ids  security_group_ids  = [aws_security_group.ssm_endpoint.id]  private_dns_enabled = true  tags = { Name= "endpoint-${split(".", each.value)[4]}" Module = "sso-ssm-prod" Env = "prod-sample"  }}resource "aws_security_group" "ssm_endpoint" {  name  = "ssm-vpc-endpoint-sg"  description = "Security group for SSM VPC Endpoints"  vpc_id= var.vpc_id  ingress { from_port= 443 to_port  = 443 protocol = "tcp" cidr_blocks = [var.vpc_cidr] description = "HTTPS from VPC CIDR for SSM Endpoint"  }  egress { from_port= 0 to_port  = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"]  }  tags = { Module = "sso-ssm-prod" Env = "prod-sample"  }}</code>

費用目安 (2026-04 時点): Interface VPC Endpoint は 1 エンドポイント・1 AZ あたり
約 $0.01/時間。3 エンドポイント × 2 AZ で月額 約 $14〜$20 (東京リージョン) 発生する。
NAT Gateway 経由のインターネットでも SSM は動作するが、
Private Subnet 完全閉域環境では VPC Endpoint が唯一の手段になる。


5-8. 3 点セット集約まとめ

パターンTerraform 主要リソースAWS CLI コマンドコンソール対応
A: EC2 直接aws_iam_role + AmazonSSMManagedInstanceCore アタッチ + aws_iam_instance_profileaws ssm start-session --target i-xxxSystems Manager → Session Manager → セッションを開始
B: ECS Execaws_ecs_service (enable_execute_command=true) + Task Role ssmmessages:*aws ecs execute-command --interactiveCLI 専用 (コンソール非対応)
C: RDS Port FWA と同 IAM Role + Port Forwarding 権限追加aws ssm start-session --document-name AWS-StartPortForwardingSessionToRemoteHostCLI 専用 (コンソール非対応)
D: Windows RDPA と同 IAM Role (AmazonSSMManagedInstanceCore)aws ssm start-session --document-name AWS-StartPortForwardingSession + RDP クライアントCLI 専用 (コンソール非対応)
VPC Endpointaws_vpc_endpoint × 3 (ssm/ec2messages/ssmmessages) + aws_security_groupaws ec2 describe-vpc-endpoints で確認VPC → エンドポイント → 3 エンドポイント確認

6. Terraform 実装 (IC + Permission Set + SSM IAM Policy 完全 HCL)

6-1. Terraform 構成全体図 (modules/sso / modules/ssm)

IAM Identity Center と SSM Session Manager を Terraform で管理する場合、以下の 2 モジュール構成が運用しやすい。変更頻度の異なるリソースを分離することで、Permission Set の変更が SSM 設定に影響しなくなる。

iac/├── modules/│├── sso/  # IAM Identity Center / Permission Set 管理││├── main.tf││├── groups.tf││├── account_assignment.tf││├── variables.tf││└── outputs.tf│└── ssm/  # SSM Document / VPC Endpoint 管理│ ├── main.tf│ ├── session_document.tf│ ├── vpc_endpoints.tf│ ├── variables.tf│ └── outputs.tf├── envs/│├── prod/││├── main.tf # モジュール呼出し││└── terraform.tfvars│└── staging/│ ├── main.tf│ └── terraform.tfvars└── versions.tf</code>
# versions.tfterraform {  required_version = ">= 1.9.0"  required_providers { aws = {source  = "hashicorp/aws"version = "~> 5.0" }  }}provider "aws" {  region = var.aws_region}</code>

6-2. IC Permission Set HCL (6 パターン × inline_policy / managed_policy)

Permission Set は aws_ssoadmin_permission_set + aws_ssoadmin_permission_set_inline_policy または aws_ssoadmin_managed_policy_attachment の組み合わせで定義する。

# modules/sso/main.tf — Permission Set 6 パターンdata "aws_ssoadmin_instances" "this" {}locals {  sso_instance_arn  = tolist(data.aws_ssoadmin_instances.this.arns)[0]  identity_store_id = tolist(data.aws_ssoadmin_instances.this.identity_store_ids)[0]}# (a) ReadOnly — 監査・コンサルタント向けresource "aws_ssoadmin_permission_set" "read_only" {  name = "ReadOnly"  instance_arn  = local.sso_instance_arn  session_duration = "PT4H"  description= "Read-only access for audit"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssoadmin_managed_policy_attachment" "read_only" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.read_only.arn  managed_policy_arn = "arn:aws:iam::aws:policy/ReadOnlyAccess"}# (b) Operator — 日次運用 (SSM + CloudWatch Read)resource "aws_ssoadmin_permission_set" "operator" {  name = "Operator"  instance_arn  = local.sso_instance_arn  session_duration = "PT8H"  description= "Daily operations: SSM start-session + CloudWatch read"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssoadmin_permission_set_inline_policy" "operator" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.operator.arn  inline_policy= jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "SSMSessionStart"  Effect = "Allow"  Action = ["ssm:StartSession", "ssm:DescribeInstanceInformation","ssm:GetConnectionStatus", "ec2:DescribeInstances"]  Resource = "*"},{  Sid = "CloudWatchRead"  Effect = "Allow"  Action = ["cloudwatch:Get*", "cloudwatch:List*", "logs:Get*", "logs:Describe*"]  Resource = "*"} ]  })}# (c) Admin — 時限付き管理者 (MFA 強制・8h)resource "aws_ssoadmin_permission_set" "admin" {  name = "Admin"  instance_arn  = local.sso_instance_arn  session_duration = "PT8H"  description= "Time-limited admin with MFA enforcement"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssoadmin_managed_policy_attachment" "admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.admin.arn  managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"}# (d) DBAdmin — RDS 管理 + RDS Port Forwarding 専用resource "aws_ssoadmin_permission_set" "db_admin" {  name = "DBAdmin"  instance_arn  = local.sso_instance_arn  session_duration = "PT4H"  description= "RDS management and SSM Port Forwarding"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssoadmin_permission_set_inline_policy" "db_admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.db_admin.arn  inline_policy= jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "RDSManagement"  Effect = "Allow"  Action = ["rds:*", "rds-db:connect"]  Resource = "*"},{  Sid = "SSMPortForward"  Effect = "Allow"  Action = ["ssm:StartSession", "ssm:TerminateSession"]  Resource = "*"  Condition = { StringEquals = {"ssm:documentName" = "AWS-StartPortForwardingSessionToRemoteHost" }  }} ]  })}# (e) NetworkAdmin — VPC / Route Table / Security Group 専用resource "aws_ssoadmin_permission_set" "network_admin" {  name = "NetworkAdmin"  instance_arn  = local.sso_instance_arn  session_duration = "PT4H"  description= "VPC, Route Table, Security Group management"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssoadmin_managed_policy_attachment" "network_admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.network_admin.arn  managed_policy_arn = "arn:aws:iam::aws:policy/AmazonVPCFullAccess"}# (f) Emergency (Break-glass) — 障害対応 MFA + 時限 1h + 全操作通知resource "aws_ssoadmin_permission_set" "emergency" {  name = "Emergency"  instance_arn  = local.sso_instance_arn  session_duration = "PT1H"  description= "Break-glass emergency: MFA required, all actions monitored"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssoadmin_managed_policy_attachment" "emergency" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.emergency.arn  managed_policy_arn = "arn:aws:iam::aws:policy/AdministratorAccess"}</code>

aws_ssoadmin_access_control_attributes を使うと Permission Set に MFA 強制ポリシーを追加できる。Admin と Emergency は require_mfa = true 相当の条件ポリシーを組み合わせる。

6-3. IC グループ作成 + 外部 IdP SCIM 同期 (aws_identitystore_group)

# modules/sso/groups.tfresource "aws_identitystore_group" "ops" {  identity_store_id = local.identity_store_id  display_name= "ops-team"  description = "Operations team — Operator Permission Set"}resource "aws_identitystore_group" "admin" {  identity_store_id = local.identity_store_id  display_name= "admin-team"  description = "Admin team — Admin Permission Set (MFA required)"}resource "aws_identitystore_group" "db_admin" {  identity_store_id = local.identity_store_id  display_name= "db-admin-team"  description = "Database admin team — DBAdmin Permission Set"}resource "aws_identitystore_group" "emergency" {  identity_store_id = local.identity_store_id  display_name= "emergency-responders"  description = "Break-glass access — Emergency Permission Set"}</code>

SCIM 同期の注意: Azure AD / Okta で SCIM 同期を有効化すると、外部 IdP のグループが Identity Store に自動同期される。aws_identitystore_groupdisplay_name を外部 IdP グループ名と完全一致させること。SCIM が先に動作した場合は data "aws_identitystore_group" で検索して参照するのが安全。

6-4. AWS Account Assignment (aws_ssoadmin_account_assignment)

# modules/sso/account_assignment.tfvariable "target_account_id" {  description = "AWS account ID to assign Permission Sets"  type  = string}resource "aws_ssoadmin_account_assignment" "ops_operator" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.operator.arn  principal_type  = "GROUP"  principal_id = aws_identitystore_group.ops.group_id  target_type  = "AWS_ACCOUNT"  target_id = var.target_account_id}resource "aws_ssoadmin_account_assignment" "admin_admin" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.admin.arn  principal_type  = "GROUP"  principal_id = aws_identitystore_group.admin.group_id  target_type  = "AWS_ACCOUNT"  target_id = var.target_account_id}resource "aws_ssoadmin_account_assignment" "emergency_emergency" {  instance_arn = local.sso_instance_arn  permission_set_arn = aws_ssoadmin_permission_set.emergency.arn  principal_type  = "GROUP"  principal_id = aws_identitystore_group.emergency.group_id  target_type  = "AWS_ACCOUNT"  target_id = var.target_account_id}</code>

Permission Set 伝搬時間: terraform apply 完了後、Permission Set の有効化まで 5〜30 分 かかる。以下のコマンドで伝搬状態を確認できる。

# Permission Set 伝搬確認aws sso-admin list-account-assignments \  --instance-arn <IC_INSTANCE_ARN> \  --account-id <TARGET_ACCOUNT_ID> \  --permission-set-arn <PERMISSION_SET_ARN># 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止</code>

6-5. SSM Document (Session Manager Preferences) で録画設定

aws_ssm_documentSSM-SessionManagerRunShell を上書きし、S3 録画と CloudWatch Logs 転送を有効化する。

# modules/ssm/session_document.tfdata "aws_caller_identity" "current" {}resource "aws_s3_bucket" "ssm_logs" {  bucket = "ssm-session-logs-${data.aws_caller_identity.current.account_id}"  tags= { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_s3_bucket_server_side_encryption_configuration" "ssm_logs" {  bucket = aws_s3_bucket.ssm_logs.id  rule { apply_server_side_encryption_by_default {sse_algorithm = "aws:kms" }  }}resource "aws_cloudwatch_log_group" "ssm_sessions" {  name  = "/aws/ssm/sessions"  retention_in_days = 365  tags  = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_ssm_document" "session_manager_prefs" {  name= "SSM-SessionManagerRunShell"  document_type= "Session"  document_format = "JSON"  content = jsonencode({ schemaVersion = "1.0" description= "Session Manager preferences: S3 recording + CloudWatch Logs" sessionType= "Standard_Stream" inputs = {s3BucketName = aws_s3_bucket.ssm_logs.buckets3KeyPrefix  = "sessions/"s3EncryptionEnabled= truecloudWatchLogGroupName= aws_cloudwatch_log_group.ssm_sessions.namecloudWatchEncryptionEnabled = truecloudWatchStreamingEnabled  = trueidleSessionTimeout = "20"maxSessionDuration = ""kmsKeyId  = ""runAsEnabled = falserunAsDefaultUser= "" }  })  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}</code>

コンソール確認手順: Systems Manager → Session Manager → 環境設定 → S3 バケット名と CloudWatch Logs グループが上記の値になっていることを確認。

6-6. VPC Endpoint (SSM の 3 エンドポイント) Terraform

Private Subnet の EC2 インスタンスに Session Manager で接続するには以下の 3 エンドポイント が必須。

エンドポイント用途
com.amazonaws.<region>.ssmSSM コントロールプレーン
com.amazonaws.<region>.ec2messagesSSM Agent ↔ EC2 Message Service
com.amazonaws.<region>.ssmmessagesSession Manager インタラクティブセッション

月額コスト: 各エンドポイントは約 $7.2/月 (us-east-1: $0.01/AZ-hour × 24h × 30d)。VPC 1 つで 3 エンドポイント = 約 $21.6/月/VPC。複数 AZ 展開の場合はさらに増加する。

# modules/ssm/vpc_endpoints.tfvariable "vpc_id" { type = string }variable "private_subnet_ids" { type = list(string) }variable "vpc_cidr"  { type = string }data "aws_region" "current" {}resource "aws_security_group" "ssm_endpoint" {  name  = "ssm-endpoint-sg"  description = "Allow HTTPS inbound for SSM VPC Endpoints"  vpc_id= var.vpc_id  ingress { from_port= 443 to_port  = 443 protocol = "tcp" cidr_blocks = [var.vpc_cidr]  }  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_vpc_endpoint" "ssm_endpoints" {  for_each= toset(["ssm", "ec2messages", "ssmmessages"])  vpc_id  = var.vpc_id  service_name  = "com.amazonaws.${data.aws_region.current.name}.${each.value}"  vpc_endpoint_type= "Interface"  subnet_ids = var.private_subnet_ids  security_group_ids  = [aws_security_group.ssm_endpoint.id]  private_dns_enabled = true  tags = { Module = "sso-ssm-prod" Env = "prod-sample" Name= "ssm-endpoint-${each.value}"  }}</code>

コンソール確認: VPC → エンドポイント → 上記 3 エンドポイントのステータスが available になっていることを確認。

6-7. Terraform apply 実挙動ダンプ (Plan / Apply 出力例)

# Plan 確認terraform -chdir=envs/prod plan -var="target_account_id=123456789012"# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止# Plan: 18 to add, 0 to change, 0 to destroy. (参考イメージ)# Apply 実行terraform -chdir=envs/prod apply -var="target_account_id=123456789012" -auto-approve# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止# Apply 完了後の SSO 動作確認aws sso login --profile prod-operatoraws sts get-caller-identity --profile prod-operator# 期待値 Arn: "arn:aws:sts::123456789012:assumed-role/AWSReservedSSO_Operator_.../user@example.com"# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止</code>

コンソール確認: IAM Identity Center → AWS アカウント → 対象アカウント → Permission Sets タブで 6 パターンが全て表示されていることを確認。

Terraform state 設計: modules 分割と state 分離方針

  • modules/sso と modules/ssm を別 state で管理する。Permission Set の変更頻度 (週次) と SSM Document の変更頻度 (月次) が異なるため、state を分離することで変更範囲を最小化できる
  • Account Assignment は SSO state に含める。Permission Set と Account Assignment のライフサイクルは一致するため、同一 state 管理が安全
  • Remote state (S3 backend) を必須化。IC は Organization の管理アカウントで操作するため、backend は管理アカウントの S3 に配置し、member アカウントからの参照は terraform_remote_state data source で行う
  • state locking は DynamoDB で実施。複数オペレーターの同時 apply 競合を防止

7. 監査 + 録画 (CloudTrail / Session Manager Logs / S3 録画 / CloudWatch Alarm)

fig05: 監査 4 レイヤ (CloudTrail+SM Logs+S3+CW Alarm 連携図)

7-1. 監査 4 レイヤ概要

IAM Identity Center + SSM Session Manager の監査は 4 つのレイヤ で構成する。これらを組み合わせることで「誰が・いつ・どのサーバーに・何をしたか」を完全記録できる。

レイヤ担当範囲主なユースケース
CloudTrailSTS AssumeRole / SSM StartSession API誰がいつどの Permission Set でセッションを開始したか
SM Interactive Logセッション中のコマンド入出力セッション内で実行したコマンドと結果の記録
S3 録画セッション完全記録 (バイナリ形式)長期保管・コンプライアンス対応・インシデント調査
CW AlarmEmergency Permission Set 使用検知Break-glass 操作のリアルタイム Slack 通知

各レイヤは独立して機能するが、CloudTrail の StartSession イベントを起点に Session Manager Logs でセッション内容を追跡し、S3 録画で証跡を長期保管、CW Alarm でリアルタイム通知するという流れで統合運用する。

7-2. 監査ログ設計表 (QG-4)

監査ログ設計表 — 4 レイヤ完全設計

レイヤ記録内容保存先保持期間推奨
CloudTrailAssumeRole / StartSession API 呼出・ユーザー / IP / 時刻・Permission Set 名S3 (CloudTrail Bucket)7年 (PCI-DSS / SOC 2 / ISO 27001 準拠)
SM Interactive Logセッション入出力 (コマンド + 出力テキスト)・セッション ID・EC2 Instance IDCloudWatch Logs (/aws/ssm/sessions)1年 (標準運用)
S3 録画セッション完全記録 (バイナリ形式)・KMS 暗号化済みS3 (ssm-session-logs バケット)1年 (標準) / 7年 (金融・医療等)
CW AlarmEmergency Role 使用検知 → SNS → Slack リアルタイム通知CloudWatch Metrics → SNS Topicリアルタイム (ログ保存は CloudTrail 側)

保持期間の根拠: CloudTrail 7年は PCI-DSS / SOC 2 / ISO 27001 の最長要件に準拠。SM Logs / S3 録画 1年は一般的なインシデント調査対応期間。金融・医療系は規制要件に応じて延長する。

7-3. CloudTrail (AssumeRole イベント + Organization Trail) 設定

Organization Trail を有効化すると、全メンバーアカウントの API 操作を管理アカウントの S3 に一元収集できる。

# cloudtrail.tfresource "aws_s3_bucket" "cloudtrail" {  bucket = "org-cloudtrail-logs-${data.aws_caller_identity.current.account_id}"  tags= { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_s3_bucket_lifecycle_configuration" "cloudtrail" {  bucket = aws_s3_bucket.cloudtrail.id  rule { id  = "retain-7-years" status = "Enabled" expiration { days = 2555 } transition {days = 90storage_class = "GLACIER" }  }}resource "aws_cloudtrail" "org_trail" {  name  = "org-management-trail"  s3_bucket_name = aws_s3_bucket.cloudtrail.bucket  is_multi_region_trail= true  is_organization_trail= true  include_global_service_events = true  enable_log_file_validation = true  event_selector { read_write_type  = "All" include_management_events = true  }  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}</code>
# CloudTrail で SSM StartSession イベントを確認aws cloudtrail lookup-events \  --lookup-attributes AttributeKey=EventName,AttributeValue=StartSession \  --start-time "2026-04-01T00:00:00Z" \  --end-time "2026-04-30T23:59:59Z" \  --query 'Events[].{Time:EventTime,User:Username}' \  --output table# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止</code>

コンソール確認: CloudTrail → イベント履歴 → イベント名 StartSession でフィルタ → ユーザー名・ソース IP・対象 EC2 Instance ID を確認。

7-4. Session Manager Interactive Session Log (CloudWatch Logs + S3)

§6-5 で設定した SSM-SessionManagerRunShell ドキュメントにより、セッション中のコマンドと出力がリアルタイムで CloudWatch Logs に書き込まれる。

# cloudwatch_logs.tf — SM セッションログ用 KMS 暗号化ロググループresource "aws_kms_key" "ssm_logs" {  description = "KMS key for SSM session logs encryption"  deletion_window_in_days = 30  enable_key_rotation  = true  tags  = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_cloudwatch_log_group" "ssm_sessions_encrypted" {  name  = "/aws/ssm/sessions"  retention_in_days = 365  kms_key_id  = aws_kms_key.ssm_logs.arn  tags  = { Module = "sso-ssm-prod", Env = "prod-sample" }}</code>
# CloudWatch Logs でセッションログを確認 (sudo コマンドを含むログのみ)aws logs filter-log-events \  --log-group-name "/aws/ssm/sessions" \  --start-time $(date -v-7d +%s)000 \  --filter-pattern "sudo"# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止</code>

セッションログの構造: CloudWatch Logs に保存されるセッションログは SessionId/StreamName の形式で格納される。各エントリには SessionId・Target (EC2 Instance ID)・Timestamp・Message (コマンド入出力) が含まれる。

7-5. S3 録画 (Interactive Session の入出力を完全記録) 設定

S3 録画は SSM-SessionManagerRunShells3BucketName / s3KeyPrefix 設定で自動的に有効化される (§6-5 参照)。S3 に保存されたファイルは Session Manager コンソールまたは CLI で参照できる。

# S3 に保存されたセッション録画一覧aws s3 ls s3://ssm-session-logs-123456789012/sessions/ --recursive# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止# セッション録画のダウンロードとローカル確認aws s3 cp "s3://ssm-session-logs-123456789012/sessions/<SessionId>" /tmp/session.log# コンソール: Systems Manager → セッションマネージャー → セッション履歴 → セッション ID → 録画再生</code>

S3 バケットポリシー: 録画ファイルへのアクセスは監査チームのみに制限する。

resource "aws_s3_bucket_policy" "ssm_logs" {  bucket = aws_s3_bucket.ssm_logs.id  policy = jsonencode({ Version = "2012-10-17" Statement = [{  Sid = "DenyNonTLS"  Effect = "Deny"  Principal = "*"  Action = "s3:*"  Resource  = ["${aws_s3_bucket.ssm_logs.arn}/*", aws_s3_bucket.ssm_logs.arn]  Condition = { Bool = { "aws:SecureTransport" = "false" } }},{  Sid = "AllowAuditTeamReadOnly"  Effect = "Allow"  Principal = { AWS = "arn:aws:iam::123456789012:role/AWSReservedSSO_ReadOnly_*"  }  Action= ["s3:GetObject", "s3:ListBucket"]  Resource = ["${aws_s3_bucket.ssm_logs.arn}/*", aws_s3_bucket.ssm_logs.arn]} ]  })}</code>

7-6. CloudWatch Alarm (Emergency Permission Set 使用検知 → SNS → Slack)

Emergency Permission Set が使用された際は、CloudTrail → CloudWatch Logs Metric Filter → CloudWatch Alarm → SNS → Slack の経路でリアルタイム通知する。

# monitoring.tf — Emergency Role 使用検知resource "aws_cloudwatch_log_group" "cloudtrail_cw" {  name  = "/aws/cloudtrail/management"  retention_in_days = 90  tags  = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_cloudwatch_log_metric_filter" "emergency_role_used" {  name  = "EmergencyPermissionSetUsed"  log_group_name = aws_cloudwatch_log_group.cloudtrail_cw.name  pattern  = "{ $.eventName = \"AssumeRole\" && $.requestParameters.roleArn = \"*AWSReservedSSO_Emergency*\" }"  metric_transformation { name= "EmergencyRoleUsageCount" namespace = "SecurityMonitoring/IAM" value  = "1"  }}resource "aws_cloudwatch_metric_alarm" "emergency_role_used" {  alarm_name = "EmergencyPermissionSetUsed"  comparison_operator = "GreaterThanOrEqualToThreshold"  evaluation_periods  = 1  metric_name= "EmergencyRoleUsageCount"  namespace  = "SecurityMonitoring/IAM"  period  = 60  statistic  = "Sum"  threshold  = 1  alarm_description= "Emergency Permission Set was assumed - immediate investigation required"  alarm_actions = [aws_sns_topic.emergency_alerts.arn]  treat_missing_data  = "notBreaching"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}resource "aws_sns_topic" "emergency_alerts" {  name = "emergency-permission-set-alerts"  tags = { Module = "sso-ssm-prod", Env = "prod-sample" }}</code>
# Emergency Role 使用履歴を即時確認aws cloudtrail lookup-events \  --lookup-attributes AttributeKey=EventName,AttributeValue=AssumeRole \  --query 'Events[?contains(CloudTrailEvent, `AWSReservedSSO_Emergency`)].[EventTime,Username]' \  --output table# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止</code>

コンソール確認: CloudWatch → アラーム → EmergencyPermissionSetUsedALARM 状態になった場合は即座に対応開始。AWS Chatbot を使用すると SNS → Slack チャンネルへのリアルタイム通知を設定できる。

7-7. 監査クエリ (CW Logs Insights で「誰がどのサーバーに SSM Session した」検索例)

CloudWatch Logs Insights を使用して、特定期間の SSM セッション履歴を体系的に調査できる。

# CW Logs Insights クエリを CLI から起動aws logs start-query \  --log-group-name "/aws/cloudtrail/management" \  --start-time $(date -v-7d +%s) \  --end-time $(date +%s) \  --query-string "fields @timestamp, eventName, userIdentity.arn, requestParameters.target | filter eventName = 'StartSession' | sort @timestamp desc | limit 50"# 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止aws logs get-query-results --query-id <QUERY_ID># 実機実行: 2026-04-XX — TODO: 実機出力を貼付・AI生成禁止</code>

CW Logs コンソール操作: CloudWatch → ログインサイト → ログループ /aws/cloudtrail/management を選択 → 以下のクエリを貼付 → 「クエリの実行」。

-- 全 SSM StartSession 一覧 (過去 7 日)fields @timestamp, eventName, userIdentity.arn, requestParameters.target, sourceIPAddress| filter eventName = "StartSession"| sort @timestamp desc| limit 100</code>
-- 特定 EC2 インスタンスへのアクセス履歴fields @timestamp, userIdentity.arn, sourceIPAddress| filter eventName = "StartSession"| filter requestParameters.target = "i-0123456789abcdef0"| sort @timestamp desc| limit 50</code>
-- Emergency Permission Set 使用履歴 (緊急調査用)fields @timestamp, userIdentity.arn, requestParameters.roleArn| filter eventName = "AssumeRole"| filter requestParameters.roleArn like /AWSReservedSSO_Emergency/| sort @timestamp desc| limit 20</code>

7-8. SIEM 連携 (Splunk / Datadog / Wazuh 等) 概要

本番環境では CloudWatch Logs と CloudTrail ログを SIEM に転送し、集中監視・相関分析・アラートを一元化する。

SIEM連携方式主な設定
SplunkSplunk Add-on for AWS (S3/CloudWatch)CloudTrail S3 バケット → Splunk HEC
DatadogDatadog AWS Integration + Lambda ForwarderCloudWatch Logs → Lambda → Datadog API
WazuhWazuh AWS ModuleCloudTrail S3 バケット ポーリング
Microsoft SentinelAWS S3 ConnectorCloudTrail → S3 → Sentinel
Elastic SIEMElastic AWS IntegrationCloudWatch Logs Subscription → Elastic
SIEM 連携の優先設計ポイント (2026-04 時点)

  • CloudTrail → S3 → SIEM が最も安定。CloudTrail S3 バケットに SIEM の読み取り IAM Role をアタッチし、S3 Event Notification → Lambda → SIEM の経路で転送する
  • Session Manager ログは CloudWatch Logs Subscription Filter を使い、Kinesis Data Firehose 経由で SIEM に転送するのが低レイテンシ
  • Emergency Role の使用は SIEM で独立アラートルール を定義し、通常の AssumeRole と区別して優先度 Critical で通知する
  • 各 SIEM の AWS Integration バージョンアップが頻繁。Splunk Add-on for AWS v7.x / Datadog Agent v7.x / Wazuh v4.x を想定 (利用時に公式 Changelog を確認)

8. まとめ + よくあるエラー + 次のステップ

8-1. 6 実務論点振り返りマトリクス

論点設計ポイント実装章主要コマンド / HCL
IAM Identity CenterOrganization 連携・外部 IdP SAML/SCIM・グループ設計§3aws sso login
Permission Set 6 パターン最小権限・Session Duration・MFA 強制§4aws_ssoadmin_permission_set
SSM Session Manager 4 接続EC2 / ECS / RDS Port FW / RDP — 踏み台廃止§5aws ssm start-session
Terraform 完全実装modules/sso + modules/ssm の分離構成§6terraform apply
監査 + 録画CloudTrail + SM Logs + S3 + CW Alarm の 4 レイヤ§7CW Logs Insights クエリ
エラー対処SSM Agent / IAM 不足 / Permission Set 伝搬待ち§8-3→ 下表参照

8-2. チートシート

IAM Identity Center

# IC インスタンス ARN 確認aws sso-admin list-instances \  --query 'Instances[0].[InstanceArn,IdentityStoreId]'# SSO プロファイル設定 (初回のみ)aws configure sso --profile prod-admin# SSO ログインaws sso login --profile prod-admin# 認証確認aws sts get-caller-identity --profile prod-admin</code>

Permission Set (Terraform 抜粋)

resource "aws_ssoadmin_permission_set" "operator" {  name = "OperatorAccess"  instance_arn  = tolist(data.aws_ssoadmin_instances.main.arns)[0]  session_duration = "PT8H"  tags = { Env = "prod" }}</code>

SSM Session Manager 4 接続

# A: EC2 直接 SSMaws ssm start-session --target i-0123456789abcdef0# B: ECS Exec (Fargate)aws ecs execute-command \  --cluster my-cluster --task <task-id> \  --container app --interactive --command "/bin/sh"# C: RDS Port Forwarding (PostgreSQL 5432)aws ssm start-session \  --target i-0123456789abcdef0 \  --document-name AWS-StartPortForwardingSessionToRemoteHost \  --parameters '{"host":["db.xxxx.rds.amazonaws.com"],"portNumber":["5432"],"localPortNumber":["15432"]}'# → psql -h 127.0.0.1 -p 15432 -U appuser -d mydb# D: RDP over Port FW (Windows Server)aws ssm start-session \  --target i-0123456789abcdef0 \  --document-name AWS-StartPortForwardingSession \  --parameters '{"portNumber":["3389"],"localPortNumber":["13389"]}'# → mstsc /v:localhost:13389</code>

監査クエリ (CW Logs Insights)

fields @timestamp, userIdentity.arn, requestParameters| filter eventName = "AssumeRole" and requestParameters.roleArn like /Emergency/| sort @timestamp desc| limit 50</code>

8-3. よくあるエラー 10 ケース集

よくあるエラー 10 ケース集 — SSM Session Manager × IAM Identity Center 即引きリファレンス

  • ケース1: TargetNotConnected — SSM Agent 未起動 / バージョン古い。aws ssm describe-instance-information --filters Key=InstanceIds,Values=i-xxx で確認 → systemctl restart amazon-ssm-agent で再起動
  • ケース2: AccessDeniedException: ssm:StartSession — EC2 Instance Profile の IAM Role 未アタッチ。AmazonSSMManagedInstanceCore policy が Role にアタッチされているか確認
  • ケース3: Permission Set 割当後すぐ使えない — 伝搬に 5〜30 分かかる仕様。aws sso-admin describe-account-assignment-creation-statusSUCCEEDED になるまで待機
  • ケース4: セッション途中で切断 (ThrottlingException) — Session Duration 不足 / STS トークン期限切れ。Permission Set の session_duration = "PT8H" に拡張 → aws sso login で再認証
  • ケース5: RDS Port FW 接続タイムアウト — VPC Endpoint (ssm / ssmmessages / ec2messages) 未作成。aws ec2 describe-vpc-endpoints で 3 エンドポイントの AVAILABLE 状態を確認
  • ケース6: InvalidEndpointState / Endpoint 障害 — ssm / ssmmessages / ec2messages の 3 点が未全 AVAILABLE。Terraform で aws_vpc_endpoint × 3 を再 apply して解消
  • ケース7: CW Logs にセッションログが届かない — Session Manager Preferences の cloudWatchLogGroupName 未設定。Preferences で /aws/ssm/sessions ロググループを設定 (Terraform: aws_ssm_document で管理)
  • ケース8: S3 録画バケット AccessDenied — SSM Service Principal の s3:PutObject 権限不足。S3 バケットポリシーに ssm.amazonaws.com からの PutObject を許可
  • ケース9: SAML AuthorizationError — ログイン不可 — IdP 側の属性マッピングミス (email / groups 未設定)。Azure AD / Okta コンソールで SAML 属性マッピングを再確認
  • ケース10: Break-glass 使用後 Slack 通知が来ない — CW Alarm → SNS → Lambda (Slack webhook) の連携漏れ。aws cloudwatch set-alarm-state --alarm-name EmergencyRoleUsed --state-value ALARM --state-reason test で動作確認

8-4. 関連記事表

記事役割
Aurora PostgreSQL IAM 認証本記事の起点 — DB 特化版 (ID:1196)
AWS 公式 IAM Identity Center User Guide外部 IdP 連携 / SCIM 同期の詳細
AWS 公式 Session Manager ユーザーガイドSSM Agent 設定 / IAM / ログ設定の詳細

8-5. 次のステップ

本記事の先へ — 3 つの発展テーマ

  • AWS Verified Access (ZTNA) — VPN 不要のゼロトラストネットワークアクセス。IAM Identity Center と連携してアプリケーション単位のアクセス制御を実現。SSH / RDP レス運用の最終形
  • IAM Roles Anywhere — オンプレミスサーバーや CI/CD パイプラインに IAM Role を付与。人手 IAM キー廃止をオンプレまで横展開できる
  • Just-In-Time (JIT) Access — EventBridge + Step Functions で「申請→承認→自動払出→自動回収」を自動化。Emergency Permission Set の運用をさらに強化する発展形

8-6. 次のアクション

→ Aurora PostgreSQL IAM 認証 (DB 特化版) を読む

→ AWS 公式 IAM Identity Center doc

→ AWS Verified Access (ZTNA) を読む