コンテンツにスキップ

RDS.1

検証日: 2026-05-24 / リージョン: ap-northeast-1

概要

RDS.1 は RDS DB インスタンススナップショットがパブリック化されている場合に FAILED となる Security Hub CSPM コントロール。本記事では、Security Hub finding を EventBridge でフィルタし、SSM Automation の AWSSupport-ModifyRDSSnapshotPermission を起動してスナップショットを自動的にプライベートに戻す構成を検証する。

自動修復の構成

RDS スナップショットがパブリック化(modify-db-snapshot-attribute --values-to-add all)
  → Config ルール securityhub-rds-snapshots-public-prohibited-<サフィックス> が NON_COMPLIANT
  → Security Hub finding RDS.1 が FAILED
  → EventBridge ルールが finding をフィルタ(Input Transformer でスナップショット ID 抽出)
  → SSM Automation AWSSupport-ModifyRDSSnapshotPermission を起動(Private=Yes)
  → modify-db-snapshot-attribute --values-to-remove all 実行
  → スナップショットがプライベートに戻る
  → Config 再評価 → COMPLIANT
  → Security Hub finding → PASSED
EventBridge 発火タイミングの注意: Security Hub は Config の評価結果が変化した時点で finding を発行・更新する。同じ状態(FAILED → FAILED)が続く場合、Security Hub Findings - Imported イベントは発行されないため、EventBridge の発火タイミングは「コンプライアンス状態の変化点」に限られる(実機検証で確認)。本番運用では新規パブリック化時の PASSED → FAILED 変化で発火するため問題にならないが、本記事の検証では FAILED finding の観測タイミングを確保するために EventBridge を一時的に DISABLED にしているため、後述のステップ 5.3〜5.6 で「PASSED → FAILED」の状態変化を意図的に起こしている。

使用するランブック

AWSSupport-ModifyRDSSnapshotPermission(AWS マネージド)を使用する。RDS DB インスタンススナップショット(AwsRdsDbSnapshot)のみ対応で、Aurora / DocumentDB / Neptune のクラスタースナップショット(AwsRdsDbClusterSnapshot)には別途カスタムランブックが必要(DocumentDB.3 / Neptune.3 で対応予定)。

パラメータ役割
SnapshotIdentifiersStringList修復対象スナップショット ID(finding から抽出して渡す)
PrivateStringYes 固定
AutomationAssumeRoleARNSSM Automation が rds:ModifyDBSnapshotAttribute を呼ぶための IAM ロール

Security Hub finding 構造

Security Hub finding の Resources[0].Details.AwsRdsDbSnapshot.DbSnapshotIdentifier にスナップショット ID が ID 形式(ARN ではない)で含まれる。EventBridge Input Transformer で直接抽出可能。

{
  "Resources": [{
    "Type": "AwsRdsDbSnapshot",
    "Id": "arn:aws:rds:<リージョン>:<アカウント ID>:snapshot:<スナップショット ID>",
    "Details": {
      "AwsRdsDbSnapshot": {
        "DbSnapshotIdentifier": "<スナップショット ID>",
        ...
      }
    }
  }]
}

検証環境

検証環境の構成図

本記事のコマンドは、--profile 指定がない場合は Workload アカウントで実行する。事前に export AWS_PROFILE=Workload でデフォルトを設定しておくと便利。

結果

検証項目結果
Security Hub finding(FAILED)から EventBridge へのトリガー✓ 状態変化(PASSED → FAILED)で発火確認
Input Transformer でスナップショット ID 抽出Resources[0].Details.AwsRdsDbSnapshot.DbSnapshotIdentifier から取得
SSM Automation 起動と修復実行✓ Status: Success
スナップショットのパブリック共有解除restore 属性が空
Config / Security Hub PASSED 復帰✓ Compliance: PASSED, Workflow: RESOLVED

実測時間:

  • 設定変更 → Security Hub finding 反映: 約 3〜5 分(初回パブリック化時 5 分、再パブリック化時 3 分)
  • finding 発行 → EventBridge 発火 → SSM Automation 実行完了: 約 19 秒
  • 修復完了 → Security Hub PASSED 復帰: 約 2 分

検証の流れ

    flowchart LR
    A[1. 事前確認] --> B[2. 修復用 IAM ロール作成]
    B --> C[3. EventBridge ルール作成<br>DISABLED 状態]
    C --> D[4. RDS インスタンス・<br>スナップショット作成]
    D --> E[5.1 パブリック化<br>5.2 FAILED 観測]
    E --> F[5.3 プライベートに戻す<br>5.4 PASSED 観測]
    F --> G[5.5 EventBridge 有効化<br>5.6 再パブリック化]
    G --> H[6. 自動修復実行確認]
    H --> I[7. PASSED 復帰確認]
    I --> J[8. クリーンアップ]
  

1. 事前確認

Config ルールの存在確認

aws configservice describe-config-rules \
  --query "ConfigRules[?contains(ConfigRuleName, 'rds-snapshots-public-prohibited')].ConfigRuleName" \
  --output text \
  --region ap-northeast-1
securityhub-rds-snapshots-public-prohibited-<サフィックス>

既存の EventBridge ルール確認

aws events list-rules \
  --name-prefix "rds-1-auto-remediation" \
  --region ap-northeast-1 \
  --query 'Rules[].Name' \
  --output json
[]

既存の IAM ロール確認

aws iam list-roles \
  --query "Roles[?starts_with(RoleName, 'rds-1-')].RoleName" \
  --output json
[]

過去の検証で残っているロールがあれば事前に削除する。

2. 修復用 IAM ロール作成

SSM Automation が rds:ModifyDBSnapshotAttribute を呼ぶための IAM ロールと、EventBridge が SSM Automation を起動するための IAM ロールの 2 つを作成する。

2.1 SSM Automation 実行ロール

cat <<'EOF' > /tmp/ssm-automation-trust.json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "ssm.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}
EOF

aws iam create-role \
  --role-name rds-1-automation-role \
  --assume-role-policy-document file:///tmp/ssm-automation-trust.json \
  --query 'Role.Arn' \
  --output text
arn:aws:iam::<アカウント ID>:role/rds-1-automation-role
cat <<'EOF' > /tmp/rds-snapshot-policy.json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Action": [
      "ssm:StartAutomationExecution",
      "ssm:GetAutomationExecution",
      "rds:DescribeDBSnapshots",
      "rds:DescribeDBSnapshotAttributes",
      "rds:ModifyDBSnapshotAttribute"
    ],
    "Resource": "*"
  }]
}
EOF

aws iam put-role-policy \
  --role-name rds-1-automation-role \
  --policy-name rds-snapshot-permission \
  --policy-document file:///tmp/rds-snapshot-policy.json

(出力なし)

AWSSupport-ModifyRDSSnapshotPermission の AWS 公式ドキュメント に従い、AutomationAssumeRole には ssm:StartAutomationExecution / ssm:GetAutomationExecution も含めている。本検証ではこの構成で動作確認している。

なお、DocumentDB.3 / Neptune.3 で作成するカスタムランブック(aws:executeAwsApirds:ModifyDBClusterSnapshotAttribute を直接呼ぶ単純な構成)は rds:* のみで動作することを実機確認している。本ランブックは AWS マネージドで内部実装が不明のため、ssm:* を含めた構成で検証した結果をそのまま記載しているが、実際には rds:* のみで動作する可能性がある(未検証)。

2.2 EventBridge から SSM Automation 起動するロール

cat <<'EOF' > /tmp/eventbridge-trust.json
{
  "Version": "2012-10-17",
  "Statement": [{
    "Effect": "Allow",
    "Principal": {"Service": "events.amazonaws.com"},
    "Action": "sts:AssumeRole"
  }]
}
EOF

aws iam create-role \
  --role-name rds-1-eventbridge-role \
  --assume-role-policy-document file:///tmp/eventbridge-trust.json \
  --query 'Role.Arn' \
  --output text
arn:aws:iam::<アカウント ID>:role/rds-1-eventbridge-role
cat <<'EOF' > /tmp/eventbridge-policy.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ssm:StartAutomationExecution",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": "iam:PassRole",
      "Resource": "arn:aws:iam::<アカウント ID>:role/rds-1-automation-role",
      "Condition": {
        "StringEquals": {
          "iam:PassedToService": "ssm.amazonaws.com"
        }
      }
    }
  ]
}
EOF

aws iam put-role-policy \
  --role-name rds-1-eventbridge-role \
  --policy-name eventbridge-ssm-automation \
  --policy-document file:///tmp/eventbridge-policy.json

(出力なし)

3. EventBridge ルール作成

3.1 ルール本体作成(DISABLED 状態)

Security Hub finding のうち、RDS.1 で FAILED かつ Workflow.Status が NEW のものをフィルタする。検証手順では FAILED finding の観測タイミングを確保するため、最初は DISABLED 状態で作成し、ステップ 5 で FAILED を観測した後に有効化する。

cat <<'EOF' > /tmp/eventbridge-pattern.json
{
  "source": ["aws.securityhub"],
  "detail-type": ["Security Hub Findings - Imported"],
  "detail": {
    "findings": {
      "Compliance": {
        "SecurityControlId": ["RDS.1"],
        "Status": ["FAILED"]
      },
      "Workflow": {
        "Status": ["NEW"]
      },
      "Resources": {
        "Type": ["AwsRdsDbSnapshot"]
      }
    }
  }
}
EOF

aws events put-rule \
  --name rds-1-auto-remediation \
  --event-pattern file:///tmp/eventbridge-pattern.json \
  --state DISABLED \
  --region ap-northeast-1 \
  --query 'RuleArn' \
  --output text
arn:aws:events:ap-northeast-1:<アカウント ID>:rule/rds-1-auto-remediation

3.2 ターゲット設定(Input Transformer 付き)

EVENTBRIDGE_ROLE_ARN=$(aws iam get-role \
  --role-name rds-1-eventbridge-role \
  --query 'Role.Arn' \
  --output text)

AUTOMATION_ROLE_ARN=$(aws iam get-role \
  --role-name rds-1-automation-role \
  --query 'Role.Arn' \
  --output text)

cat <<EOF > /tmp/eventbridge-target.json
[
  {
    "Id": "ssm-automation-target",
    "Arn": "arn:aws:ssm:ap-northeast-1::automation-definition/AWSSupport-ModifyRDSSnapshotPermission:\$DEFAULT",
    "RoleArn": "$EVENTBRIDGE_ROLE_ARN",
    "InputTransformer": {
      "InputPathsMap": {
        "snapshotId": "\$.detail.findings[0].Resources[0].Details.AwsRdsDbSnapshot.DbSnapshotIdentifier"
      },
      "InputTemplate": "{\"SnapshotIdentifiers\": [\"<snapshotId>\"], \"Private\": [\"Yes\"], \"AutomationAssumeRole\": [\"$AUTOMATION_ROLE_ARN\"]}"
    }
  }
]
EOF

aws events put-targets \
  --rule rds-1-auto-remediation \
  --targets file:///tmp/eventbridge-target.json \
  --region ap-northeast-1
{
    "FailedEntryCount": 0,
    "FailedEntries": []
}
本検証では automation-definition/AWSSupport-ModifyRDSSnapshotPermission:$DEFAULT で最新バージョンを参照している。本番運用では AWS によるランブック更新で挙動が変わるリスクを避けるため、特定バージョン(例: :1)に pin する選択肢もある。

4. RDS インスタンス・スナップショット作成

4.1 RDS インスタンス作成

aws rds create-db-instance \
  --db-instance-identifier rds1-remediation-test \
  --db-instance-class db.t3.micro \
  --engine mysql \
  --master-username admin \
  --master-user-password '<パスワード>' \
  --allocated-storage 20 \
  --no-publicly-accessible \
  --db-subnet-group-name default \
  --no-multi-az \
  --backup-retention-period 0 \
  --region ap-northeast-1 \
  --query 'DBInstance.{DBInstanceIdentifier:DBInstanceIdentifier,Status:DBInstanceStatus}' \
  --output json
{
    "DBInstanceIdentifier": "rds1-remediation-test",
    "Status": "creating"
}

available 待ち(約 5〜7 分)。

while true; do
  STATUS=$(aws rds describe-db-instances \
    --db-instance-identifier rds1-remediation-test \
    --query 'DBInstances[0].DBInstanceStatus' \
    --output text \
    --region ap-northeast-1)
  echo "$(date '+%H:%M:%S') status: $STATUS"
  case "$STATUS" in
    available) break ;;
    failed) echo "失敗"; break ;;
    *) sleep 60 ;;
  esac
done
HH:MM:SS status: creating
(数分間 creating を繰り返す)
HH:MM:SS status: available

4.2 スナップショット作成

aws rds create-db-snapshot \
  --db-instance-identifier rds1-remediation-test \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --region ap-northeast-1 \
  --query 'DBSnapshot.{DBSnapshotIdentifier:DBSnapshotIdentifier,Status:Status}' \
  --output json
{
    "DBSnapshotIdentifier": "rds1-remediation-snapshot",
    "Status": "creating"
}

available 待ち(約 3 分)。

while true; do
  STATUS=$(aws rds describe-db-snapshots \
    --db-snapshot-identifier rds1-remediation-snapshot \
    --query 'DBSnapshots[0].Status' \
    --output text \
    --region ap-northeast-1)
  echo "$(date '+%H:%M:%S') snapshot: $STATUS"
  case "$STATUS" in
    available) break ;;
    failed) echo "失敗"; break ;;
    *) sleep 30 ;;
  esac
done
HH:MM:SS snapshot: creating
(数分間 creating を繰り返す)
HH:MM:SS snapshot: available

5. FAILED 観測と自動修復の起動準備

5.1 スナップショットをパブリック化

aws rds modify-db-snapshot-attribute \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --attribute-name restore \
  --values-to-add all \
  --region ap-northeast-1 \
  --query 'DBSnapshotAttributesResult.DBSnapshotAttributes' \
  --output json
[
    {
        "AttributeName": "restore",
        "AttributeValues": [
            "all"
        ]
    }
]

describe-db-snapshot-attributes でも restore 属性に all が含まれるパブリック状態であることを確認する。修復後(ステップ 7.1)と比較する基準値となる。

aws rds describe-db-snapshot-attributes \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --region ap-northeast-1 \
  --query 'DBSnapshotAttributesResult.DBSnapshotAttributes' \
  --output json
[
    {
        "AttributeName": "restore",
        "AttributeValues": [
            "all"
        ]
    }
]

5.2 Security Hub finding が FAILED になることを確認

Security Hub への反映には数分かかる。Compliance.StatusWorkflow.Status の両方を確認する(EventBridge フィルタは Workflow.Status: NEW を要求するため、NOTIFIED 等になっていると 5.3 でルールを有効化しても発火しない)。

sleep 300

aws securityhub get-findings \
  --filters '{"ComplianceSecurityControlId":[{"Comparison":"EQUALS","Value":"RDS.1"}],"ComplianceStatus":[{"Comparison":"EQUALS","Value":"FAILED"}],"ResourceId":[{"Comparison":"PREFIX","Value":"arn:aws:rds:ap-northeast-1:<アカウント ID>:snapshot:rds1-remediation-snapshot"}]}' \
  --region ap-northeast-1 \
  --query 'Findings[0].{Compliance:Compliance.Status,Workflow:Workflow.Status,SnapshotId:Resources[0].Details.AwsRdsDbSnapshot.DbSnapshotIdentifier}' \
  --output json
{
    "Compliance": "FAILED",
    "Workflow": "NEW",
    "SnapshotId": "rds1-remediation-snapshot"
}

5.3 一度プライベートに戻して finding の状態を変化させる

Config 手動トリガーだけでは Security Hub finding の再 import が発火しない: 実機検証で確認した挙動。Config の start-config-rules-evaluation を実行しても、コンプライアンス状態が「FAILED → FAILED」で変わらない場合、Security Hub への新規 import イベントが発火しない。EventBridge は Security Hub Findings - Imported イベントを待つため、状態変化を起こす必要がある。

回避策として、一度プライベート化して PASSED に戻し、再度パブリック化することで「PASSED → FAILED」の状態変化を発生させ、新規 import イベントを起こす。

本番運用ではこの workaround は不要: EventBridge ルールが常時 ENABLED であれば、新規スナップショットがパブリック化された瞬間(初回の FAILED 検知時)に PASSED → FAILED 変化として発火する。本検証では FAILED finding を確実に観測するために EventBridge を DISABLED で作成して FAILED を発生させたため、後から ENABLED にしても既存 finding は再 import されず、状態変化を起こす必要が生じた。

スナップショットを一旦プライベートに戻す。

aws rds modify-db-snapshot-attribute \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --attribute-name restore \
  --values-to-remove all \
  --region ap-northeast-1 \
  --query 'DBSnapshotAttributesResult.DBSnapshotAttributes' \
  --output json
[
    {
        "AttributeName": "restore",
        "AttributeValues": []
    }
]

5.4 PASSED を観測

Security Hub finding が PASSED に戻ることを確認する(約 5 分)。

sleep 300

aws securityhub get-findings \
  --filters '{"ComplianceSecurityControlId":[{"Comparison":"EQUALS","Value":"RDS.1"}],"ResourceId":[{"Comparison":"PREFIX","Value":"arn:aws:rds:ap-northeast-1:<アカウント ID>:snapshot:rds1-remediation-snapshot"}]}' \
  --region ap-northeast-1 \
  --query 'Findings[0].{Compliance:Compliance.Status,Workflow:Workflow.Status}' \
  --output json
{
    "Compliance": "PASSED",
    "Workflow": "RESOLVED"
}

Compliance: FAILED → PASSED への変化が Security Hub に反映され、Workflow.Status も自動的に NEW → RESOLVED に遷移する。

5.5 EventBridge ルールを有効化

aws events enable-rule \
  --name rds-1-auto-remediation \
  --region ap-northeast-1

aws events describe-rule \
  --name rds-1-auto-remediation \
  --region ap-northeast-1 \
  --query 'State'
"ENABLED"

5.6 再度パブリック化(自動修復の起動)

aws rds modify-db-snapshot-attribute \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --attribute-name restore \
  --values-to-add all \
  --region ap-northeast-1 \
  --query 'DBSnapshotAttributesResult.DBSnapshotAttributes' \
  --output json
[
    {
        "AttributeName": "restore",
        "AttributeValues": [
            "all"
        ]
    }
]

Compliance: PASSED → FAILED の状態変化が発生し、Security Hub が新規 import イベントを発行する。EventBridge ルールが捕捉して SSM Automation を起動する。

6. 自動修復の実行確認

EventBridge が finding を捕捉して SSM Automation を起動するはず。SSM Automation の実行履歴を確認する。

sleep 60

aws ssm describe-automation-executions \
  --filters Key=DocumentNamePrefix,Values=AWSSupport-ModifyRDSSnapshotPermission \
  --max-results 5 \
  --region ap-northeast-1 \
  --query 'AutomationExecutionMetadataList[].{Status:AutomationExecutionStatus,ExecutionStartTime:ExecutionStartTime,ExecutionId:AutomationExecutionId}' \
  --output json
[
    {
        "Status": "Success",
        "ExecutionStartTime": "<開始時刻>",
        "ExecutionId": "<実行 ID>"
    }
]

7. PASSED 復帰確認

7.1 スナップショットがプライベートに戻ったことを確認

aws rds describe-db-snapshot-attributes \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --region ap-northeast-1 \
  --query 'DBSnapshotAttributesResult.DBSnapshotAttributes' \
  --output json
[
    {
        "AttributeName": "restore",
        "AttributeValues": []
    }
]

restore 属性が空になっていれば、自動修復によりプライベートに戻った状態。

7.2 Config / Security Hub finding 確認

修復後、Security Hub finding が PASSED に戻ることを確認する。

sleep 120

aws securityhub get-findings \
  --filters '{"ComplianceSecurityControlId":[{"Comparison":"EQUALS","Value":"RDS.1"}],"ResourceId":[{"Comparison":"PREFIX","Value":"arn:aws:rds:ap-northeast-1:<アカウント ID>:snapshot:rds1-remediation-snapshot"}]}' \
  --region ap-northeast-1 \
  --query 'Findings[0].{Compliance:Compliance.Status,Workflow:Workflow.Status,UpdatedAt:UpdatedAt}' \
  --output json
{
    "Compliance": "PASSED",
    "Workflow": "RESOLVED",
    "UpdatedAt": "<更新時刻>"
}

修復から約 2 分で Security Hub finding が PASSED に反映される。Workflow.Status も自動的に RESOLVED に遷移する。

8. クリーンアップ

RDS スナップショット削除

aws rds delete-db-snapshot \
  --db-snapshot-identifier rds1-remediation-snapshot \
  --region ap-northeast-1 \
  --query 'DBSnapshot.{DBSnapshotIdentifier:DBSnapshotIdentifier,Status:Status}' \
  --output json
{
    "DBSnapshotIdentifier": "rds1-remediation-snapshot",
    "Status": "deleted"
}

RDS インスタンス削除

aws rds delete-db-instance \
  --db-instance-identifier rds1-remediation-test \
  --skip-final-snapshot \
  --delete-automated-backups \
  --region ap-northeast-1 \
  --query 'DBInstance.{DBInstanceIdentifier:DBInstanceIdentifier,Status:DBInstanceStatus}' \
  --output json
{
    "DBInstanceIdentifier": "rds1-remediation-test",
    "Status": "deleting"
}

削除完了を確認する。

while true; do
  COUNT=$(aws rds describe-db-instances \
    --query "length(DBInstances[?DBInstanceIdentifier=='rds1-remediation-test'])" \
    --output text \
    --region ap-northeast-1 2>/dev/null || echo 0)
  echo "$(date '+%H:%M:%S') 残存インスタンス数: $COUNT"
  [ "$COUNT" = "0" ] && echo "削除完了" && break
  sleep 60
done
HH:MM:SS 残存インスタンス数: 1
HH:MM:SS 残存インスタンス数: 0
削除完了

EventBridge ルール削除

aws events remove-targets \
  --rule rds-1-auto-remediation \
  --ids ssm-automation-target \
  --region ap-northeast-1 \
  --query '{FailedEntryCount:FailedEntryCount,FailedEntries:FailedEntries}' \
  --output json
{
    "FailedEntryCount": 0,
    "FailedEntries": []
}
aws events delete-rule \
  --name rds-1-auto-remediation \
  --region ap-northeast-1

(出力なし)

IAM ロール削除

aws iam delete-role-policy \
  --role-name rds-1-automation-role \
  --policy-name rds-snapshot-permission

aws iam delete-role \
  --role-name rds-1-automation-role

aws iam delete-role-policy \
  --role-name rds-1-eventbridge-role \
  --policy-name eventbridge-ssm-automation

aws iam delete-role \
  --role-name rds-1-eventbridge-role

(4 つとも出力なし)

aws iam list-roles \
  --query "Roles[?starts_with(RoleName, 'rds-1-')].RoleName" \
  --output json
[]

参考

Amazonアソシエイトリンク