はじめに
2026年5月、AWS Security Hub が IAM Access Analyzer と統合し、未使用の IAM 権限・ロール・認証情報を組織全体で自動検出できるようになりました。さらに、検出した未使用アクセスに基づいて最小権限ポリシーをオンデマンドで自動生成する機能も追加されています。
「IAM のクリーンアップは大事だとわかっているが、どこから手をつければいいかわからない」という状況を解消する機能です。本記事では仕組みから実践的な運用設計まで解説します。
1. 背景:なぜ未使用 IAM アクセスが問題なのか
IAM は「設定して終わり」になりがちです。結果として以下の問題が発生します:
ゾンビ権限の蓄積:退職したメンバーのアクセスキー、使われなくなったロール、過剰な権限が付与されたポリシーが長期間放置される。
攻撃対象領域の拡大:使われていない権限でも、それが存在する限り攻撃者に悪用されるリスクがある。s3:* のような過剰権限は典型例。
コンプライアンス上のリスク:PCI DSS・ISO27001 などでは最小権限の原則(Principle of Least Privilege)の遵守が求められる。定期的なアクセス棚卸しを手動で行うのは現実的ではない。
2. 統合の仕組み
2.1 コンポーネントの関係
AWS Organizations
│
▼
Security Hub(管理アカウント)
│
├── 自動作成: IAM Access Analyzer(サービスリンク)
│ 各メンバーアカウントに自動展開
│ ↓ 90日間のアクティビティを評価
│ ↓ 未使用アクセスの findings を生成
│
├── 統合コンソール(Identity Risk 専用ビュー)
│ 脅威 / 露出 / ポスチャの findings と同一画面で管理
│
└── 最小権限ポリシー生成
↓ 実際の使用パターンに基づいて自動生成
→ 管理者がレビュー → IAM ポリシーとして適用
2.2 サービスリンク IAM Access Analyzer の自動作成
Security Hub を AWS Organizations で有効化すると、各メンバーアカウントに サービスリンク IAM Access Analyzer が自動作成されます。追加設定は不要です。
このアナライザーが収集するのは以下です:
- IAM ロールの最終使用日時
- IAM ユーザーのアクセスキー・パスワードの最終使用日時
- 各ロールに付与された権限と実際に使用されたサービス・アクション
90日間のウィンドウ:CloudTrail の記録に基づき、直近90日間で一度も使用されていない権限・認証情報・ロールを「未使用」と判定します。
3. 検出される findings の種類
3.1 Finding の分類
| Finding タイプ | 説明 | 重要度 |
|---|---|---|
| UnusedIAMRole | 90日間未使用のロール | Medium |
| UnusedIAMUserAccessKey | 90日間未使用のアクセスキー | High |
| UnusedIAMUserPassword | 90日間未使用のコンソールパスワード | Medium |
| UnusedPermission | ロールに付与されているが使用されていない権限 | Low〜Medium |
3.2 Finding の例(JSON 形式)
{
"SchemaVersion": "2018-10-08",
"Id": "arn:aws:access-analyzer:ap-northeast-1:123456789012:analyzer/security-hub-analyzer/finding/EXAMPLE-FINDING-ID",
"ProductArn": "arn:aws:securityhub:ap-northeast-1::product/aws/access-analyzer",
"GeneratorId": "aws/access-analyzer",
"AwsAccountId": "123456789012",
"Types": ["Software and Configuration Checks/AWS Security Best Practices/Unused Access"],
"Severity": {"Label": "HIGH"},
"Title": "Unused IAM user access key",
"Description": "IAM user 'deploy-bot' has access key AKIAIOSFODNN7EXAMPLE that has not been used in 90 days.",
"Resources": [
{
"Type": "AwsIamAccessKey",
"Id": "arn:aws:iam::123456789012:user/deploy-bot",
"Details": {
"AwsIamUser": {
"UserName": "deploy-bot",
"CreateDate": "2023-01-15T00:00:00Z",
"UserPolicyList": []
}
}
}
]
}
4. 最小権限ポリシーの自動生成
4.1 仕組み
IAM Access Analyzer は、CloudTrail に記録された実際の API 呼び出し履歴を解析し、そのロールが実際に使用した権限だけを含む IAM ポリシーを生成します。
CloudTrail ログ(90日分)
│
▼
IAM Access Analyzer(使用パターン分析)
│
▼ 実際に呼ばれた API のみ抽出
├── ec2:DescribeInstances(使用あり)
├── s3:GetObject(バケット: my-app-bucket のみ)
├── s3:PutObject(バケット: my-app-bucket のみ)
└── ※ s3:DeleteObject(付与されているが未使用) → 除外
▼
最小権限ポリシー(JSON)
4.2 AWS CLI での生成手順
# 1. アナライザーの ARN を確認
aws accessanalyzer list-analyzers \
--query 'analyzers[?type==`ACCOUNT_UNUSED_ACCESS`].arn' \
--output text
# 2. 対象ロールの最小権限ポリシーを生成
aws accessanalyzer generate-access-preview \
--analyzer-arn "arn:aws:accessanalyzer:ap-northeast-1:123456789012:analyzer/security-hub-analyzer" \
--principal-arn "arn:aws:iam::123456789012:role/MyApplicationRole" \
--query 'id' \
--output text
# → access-preview-id が返る
# 3. 生成されたポリシーを取得
aws accessanalyzer get-generated-policy \
--job-id "<access-preview-id>" \
--include-service-level-template
4.3 生成されたポリシーの例
既存の過剰なポリシーと生成された最小権限ポリシーの比較:
既存のポリシー(過剰な権限):
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:*",
"Resource": "*"
},
{
"Effect": "Allow",
"Action": "ec2:*",
"Resource": "*"
}
]
}
自動生成された最小権限ポリシー:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:PutObject",
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::my-app-bucket",
"arn:aws:s3:::my-app-bucket/*"
]
},
{
"Effect": "Allow",
"Action": [
"ec2:DescribeInstances",
"ec2:DescribeSecurityGroups"
],
"Resource": "*"
}
]
}
s3:* が必要最低限のアクションに絞られ、リソースも特定バケットに限定されています。
5. 運用設計:Security Hub との統合を最大限活用する
5.1 EventBridge による自動アクション
Security Hub の findings を EventBridge でキャッチして、自動アクションを設定できます。
# 未使用アクセスキーを自動無効化する Lambda の例
import boto3
import json
iam = boto3.client('iam')
def lambda_handler(event, context):
detail = event['detail']
# Security Hub finding から情報を抽出
finding = detail['findings'][0]
finding_type = finding['Types'][0]
if 'UnusedIAMUserAccessKey' not in finding_type:
return
# 重要度が HIGH の場合のみ自動対処
if finding['Severity']['Label'] != 'HIGH':
return
# リソース情報を取得
resource = finding['Resources'][0]
user_name = resource['Details']['AwsIamUser']['UserName']
# アクセスキーの一覧を取得して無効化
keys = iam.list_access_keys(UserName=user_name)
for key in keys['AccessKeyMetadata']:
if key['Status'] == 'Active':
iam.update_access_key(
UserName=user_name,
AccessKeyId=key['AccessKeyId'],
Status='Inactive'
)
print(f"Disabled access key {key['AccessKeyId']} for user {user_name}")
# Security Hub の finding をレビュー済みに更新
sh_client = boto3.client('securityhub')
sh_client.batch_update_findings(
FindingIdentifiers=[{
'Id': finding['Id'],
'ProductArn': finding['ProductArn']
}],
Note={
'Text': f'Access key automatically disabled by Lambda.',
'UpdatedBy': 'auto-remediation-lambda'
},
Workflow={'Status': 'RESOLVED'}
)
5.2 EventBridge ルールの設定
{
"source": ["aws.securityhub"],
"detail-type": ["Security Hub Findings - Imported"],
"detail": {
"findings": {
"Types": [{"prefix": "Software and Configuration Checks/AWS Security Best Practices/Unused Access"}],
"Severity": {
"Label": ["HIGH", "CRITICAL"]
},
"WorkflowState": ["NEW"]
}
}
}
5.3 定期レビューワークフローの設計
全自動での修正は危険を伴う場合もあります(例:バッチジョブが月次実行のため90日未使用に見えるケース)。以下のような段階的なアプローチを推奨します。
Week 1: Findings の棚卸し
│
├── UnusedIAMUserAccessKey(HIGH)→ 即時対応(無効化)
├── UnusedIAMRole(MEDIUM)→ ロール所有者に確認メール送付
└── UnusedPermission(LOW)→ 月次レビューキューに追加
Week 2-4: ロール所有者の確認
│
├── 返答あり・不要→ 削除
├── 返答あり・必要→ Finding に注釈を付けてサプレス
└── 返答なし→ エスカレーション
Month 2以降: 最小権限ポリシーの段階的適用
│
└── 生成ポリシーをテスト環境で適用 → 問題なければ本番に適用
6. コストについて
本機能は Security Hub Essentials に追加コストなしで含まれます(2026年5月時点)。ただし Security Hub 自体の利用料金は発生します。
| コンポーネント | コスト |
|---|---|
| Security Hub Essentials | $0.001/finding/month(上限あり) |
| IAM Access Analyzer(サービスリンク) | 追加コストなし |
| 最小権限ポリシー生成 | 追加コストなし |
| EventBridge + Lambda(自動修復) | 通常の Lambda・EventBridge 料金 |
7. 注意点
90日ウィンドウの落とし穴:月次・四半期実行のバッチジョブや、障害時のみ使うbreak-glass用ロールは「未使用」と判定されます。必ず所有者への確認フローを設けてください。
CloudTrail が有効である必要がある:IAM Access Analyzer は CloudTrail のデータを元に分析します。CloudTrail が無効なアカウントやリージョンでは正確な分析ができません。必ずマルチリージョンの証跡(Trail)を有効にしてください。
既存の Access Analyzer との共存:外部アクセス検出用(ACCOUNT タイプ)の Access Analyzer と、今回の未使用アクセス検出用(ACCOUNT_UNUSED_ACCESS タイプ)は別のアナライザーです。Security Hub が自動作成するのは後者です。
8. まとめ
Security Hub と IAM Access Analyzer の統合により、これまで手動で行っていた IAM クリーンアップ作業を大幅に効率化できます。
| 作業 | 従来 | 今回の統合後 |
|---|---|---|
| 未使用権限の発見 | 手動棚卸し(スプレッドシート管理) | 自動検出・一元管理 |
| 最小権限ポリシーの作成 | 手動で権限調査・ポリシー記述 | CloudTrail 分析から自動生成 |
| 対応優先度の判断 | 担当者の経験に依存 | Severity ベースで自動分類 |
| 修復アクション | 手動実行 | EventBridge + Lambda で自動化可能 |
「最小権限の原則」を継続的に維持する仕組みを構築するための重要なピースが揃いました。AWS Organizations で Security Hub を使っている環境であれば、追加コストなしで使い始められるので、ぜひ有効化してみてください。