コンテンツにスキップ

CT.KMS.PV.7

検証日: 2026-03-23 / リージョン: ap-northeast-1

コントロールの説明

組織外の IAM プリンシパルによる KMS リソースへのアクセスを拒否する。

本コントロールは RCP(リソースコントロールポリシー)により、組織外の IAM プリンシパルからの KMS API 操作をブロックする。Control Tower で対象の OU を指定して有効化すると、その OU 配下の全アカウントの全 KMS リソースに適用される。

RCP テンプレートの Condition は以下の 2 つの条件を AND で評価する。

  • aws:PrincipalIsAWSServicefalse(AWS サービスプリンシパルでない)
  • aws:PrincipalOrgID が自組織の ID と一致しない(組織外のプリンシパルである)

パラメータは以下の 1 つ。

  • ExemptedPrincipalArns(任意): RCP の拒否対象外にする IAM プリンシパルの ARN。組織外のパートナーアカウントや外部サービスのロール等、特定のプリンシパルにアクセスを許可する場合に使用する

本コントロールはキーポリシーを変更するのではなく、独立したアクセス制御レイヤーとして機能する。キーポリシーで組織外アカウントにアクセスを許可していても、本コントロールが有効な場合は RCP により拒否される。

本コントロール(組織外アクセスの拒否)に直接対応する Security Hub CSPM コントロールは確認できませんでした。KMS.5 は「キーポリシーがパブリックアクセスを許可していないか」をチェックするものであり、組織外アクセスの拒否とは評価対象が異なります。

検証の流れ

    flowchart LR
    A[1. 事前準備] --> B[2. 組織内・組織外<br>両方成功]
    B --> C[3. CT.KMS.PV.7<br>有効化]
    C --> D[4. 既存設定<br>維持を確認]
    C --> E[5. 組織内アクセス<br>成功を確認]
    C --> F[6. 組織外アクセス<br>拒否を確認]
    D & E & F --> G[7. CloudTrail<br>で確認]
    G --> H[8. CT.KMS.PV.7<br>無効化]
    H --> I[9. 組織外アクセス<br>成功を確認]
  

結果

  • コントロールの有効化前、組織内・組織外の両方から KMS キーを使った暗号化・復号が成功することを確認できた。
  • コントロールの有効化後、既存のキーポリシー(組織外アカウントへの許可)は維持されることを確認できた。
  • 組織内プリンシパルからのアクセスは引き続き成功することを確認できた。
  • 組織外プリンシパルからのアクセス(Encrypt、Decrypt)が拒否されることを確認できた。
  • 拒否されたイベントは、呼び出し元である組織外アカウントの CloudTrail に管理イベントとして記録されることを確認できた。一方、リソース所有者である Workload アカウントの CloudTrail や、管理アカウントの Organization Trail(CloudWatch Logs)には記録されなかった。CT.SECRETSMANAGER.PV.1 では Workload アカウントの CloudTrail と Organization Trail の両方で確認できたのとは対照的である。
  • コントロールの無効化後、組織外プリンシパルからのアクセスが再び成功することを確認できた。

1. 事前準備

テスト用の KMS カスタマーマネージドキー(CMK)を作成する。

aws kms create-key \
  --description "ct-kms-pv7-test" \
  --query 'KeyMetadata.{KeyId:KeyId,Arn:Arn,KeyState:KeyState}'
{
    "KeyId": "<キー ID>",
    "Arn": "arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID>",
    "KeyState": "Enabled"
}

エイリアスを作成する。

aws kms create-alias \
  --alias-name alias/ct-kms-pv7-test \
  --target-key-id <キー ID>
(出力なし)

キーポリシーで組織外アカウントに Encrypt と Decrypt を許可する。

aws kms put-key-policy \
  --key-id <キー ID> \
  --policy-name default \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowRootAccount",
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<Workload のアカウント ID>:root"},
        "Action": "kms:*",
        "Resource": "*"
      },
      {
        "Sid": "AllowExternalEncryptDecrypt",
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>"},
        "Action": ["kms:Encrypt", "kms:Decrypt"],
        "Resource": "*"
      }
    ]
  }'
(出力なし)

テスト用の平文ファイルを作成する。

echo -n "test data" > /tmp/plaintext.txt

2. 有効化前の確認

組織内アクセス(成功)

aws kms encrypt \
  --key-id <キー ID> \
  --plaintext fileb:///tmp/plaintext.txt \
  --query '{KeyId:KeyId,EncryptionAlgorithm:EncryptionAlgorithm}'
{
    "KeyId": "arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID>",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

後続の Decrypt 検証で使用する暗号文をファイルに保存する。

aws kms encrypt \
  --key-id <キー ID> \
  --plaintext fileb:///tmp/plaintext.txt \
  --query 'CiphertextBlob' \
  --output text | base64 --decode > /tmp/ciphertext.bin
(出力なし)

組織外アクセス(成功)

組織外アカウントの認証情報で、キーポリシーにより許可された暗号化が成功することを確認する。

aws kms encrypt \
  --key-id arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID> \
  --plaintext fileb:///tmp/plaintext.txt \
  --query '{KeyId:KeyId,EncryptionAlgorithm:EncryptionAlgorithm}' \
  --profile <組織外プロファイル名>
{
    "KeyId": "arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID>",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

キーポリシーにより、組織外アカウントからも暗号化が成功した。

3. CT.KMS.PV.7 の有効化

Control Tower の管理アカウントで、対象の OU にコントロールが有効になっていないことを確認する。

aws controltower list-enabled-controls \
  --target-identifier <OU の ARN> \
  --profile Master
{
    "enabledControls": []
}

コントロールを有効化する。

aws controltower enable-control \
  --control-identifier arn:aws:controlcatalog:::control/eolw7feyvr8b4l2lfhp3bneou \
  --target-identifier <OU の ARN> \
  --profile Master
{
    "arn": "arn:aws:controltower:ap-northeast-1:<管理アカウント ID>:enabledcontrol/<enabledcontrol ID>",
    "operationIdentifier": "<オペレーション ID>"
}

有効化が完了するまで待機する。

aws controltower get-control-operation \
  --operation-identifier <オペレーション ID> \
  --query 'controlOperation.{operationType:operationType,status:status,statusMessage:statusMessage}' \
  --profile Master
{
    "operationType": "ENABLE_CONTROL",
    "status": "SUCCEEDED",
    "statusMessage": "Operation was successful."
}

4. 既存設定の維持確認

RCP はキーポリシーを変更するのではなく、アクセス制御のレイヤーとして機能する。キーポリシーが自動的に変更されていないことを確認する。

aws kms get-key-policy \
  --key-id <キー ID> \
  --policy-name default \
  --output json | jq -r '.Policy' | jq .
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "AllowRootAccount",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<Workload のアカウント ID>:root"
            },
            "Action": "kms:*",
            "Resource": "*"
        },
        {
            "Sid": "AllowExternalEncryptDecrypt",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>"
            },
            "Action": [
                "kms:Encrypt",
                "kms:Decrypt"
            ],
            "Resource": "*"
        }
    ]
}

キーポリシーは変更されていない。組織外アカウントへの許可が残っているが、RCP により実際のアクセスは拒否される。

5. 組織内アクセスの確認

組織内プリンシパルからのアクセスは引き続き成功する。

aws kms encrypt \
  --key-id <キー ID> \
  --plaintext fileb:///tmp/plaintext.txt \
  --query '{KeyId:KeyId,EncryptionAlgorithm:EncryptionAlgorithm}'
{
    "KeyId": "arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID>",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

6. 拒否の確認

組織外 Encrypt(拒否)

aws kms encrypt \
  --key-id arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID> \
  --plaintext fileb:///tmp/plaintext.txt \
  --profile <組織外プロファイル名>
An error occurred (AccessDeniedException) when calling the Encrypt operation:
User: arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>
is not authorized to perform: kms:Encrypt on this resource
with an explicit deny in a resource control policy

組織外 Decrypt(拒否)

ステップ 2 で保存した暗号文を組織外プリンシパルで復号する。

aws kms decrypt \
  --ciphertext-blob fileb:///tmp/ciphertext.bin \
  --profile <組織外プロファイル名>
An error occurred (AccessDeniedException) when calling the Decrypt operation:
User: arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>
is not authorized to perform: kms:Decrypt on the resource associated with this ciphertext
with an explicit deny in a resource control policy

キーポリシーで許可されているにもかかわらず、組織外プリンシパルからのアクセスが拒否された。エラーメッセージに explicit deny in a resource control policy と記載されており、RCP による拒否であることがわかる。CT.S3.PV.4 では組織外プリンシパルへの拒否時に Access Denied のみが返されたが、KMS では詳細なエラーメッセージが返された。なお、Encrypt では on this resource、Decrypt では on the resource associated with this ciphertext と、操作によってリソースの表現が異なる。

7. CloudTrail での確認

拒否されたイベントが CloudTrail に記録されていることを確認する。KMS の Encrypt / Decrypt は CloudTrail の管理イベントに分類されるため、デフォルトの CloudTrail 設定で記録される。

RCP による拒否イベントは、リソース所有者(Workload アカウント)ではなく、呼び出し元(組織外アカウント)の CloudTrail に記録される。CT.SECRETSMANAGER.PV.1 では Workload アカウントの CloudTrail で確認できたのとは対照的である。

aws cloudtrail lookup-events \
  --lookup-attributes AttributeKey=EventName,AttributeValue=Encrypt \
  --start-time <検索開始時刻> \
  --end-time <検索終了時刻> \
  --query 'Events[].CloudTrailEvent' \
  --output text \
  --profile <組織外プロファイル名> | jq 'select(.errorCode != null) | {eventName, errorCode, errorMessage}'
{
  "eventName": "Encrypt",
  "errorCode": "AccessDenied",
  "errorMessage": "User: arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名> is not authorized to perform: kms:Encrypt on this resource with an explicit deny in a resource control policy: arn:aws:organizations::<管理アカウント ID>:policy/<組織 ID>/resource_control_policy/<ポリシー ID>"
}

errorMessageexplicit deny in a resource control policy と記録されており、RCP による拒否であることがわかる。

なお、管理アカウントの Organization Trail(CloudWatch Logs)には、組織外アカウントの拒否イベントは記録されない。Organization Trail は組織内アカウントのイベントのみを集約するためである。

8. CT.KMS.PV.7 の無効化

aws controltower disable-control \
  --control-identifier arn:aws:controlcatalog:::control/eolw7feyvr8b4l2lfhp3bneou \
  --target-identifier <OU の ARN> \
  --profile Master
{
    "operationIdentifier": "<オペレーション ID>"
}
aws controltower get-control-operation \
  --operation-identifier <オペレーション ID> \
  --query 'controlOperation.{operationType:operationType,status:status,statusMessage:statusMessage}' \
  --profile Master
{
    "operationType": "DISABLE_CONTROL",
    "status": "SUCCEEDED",
    "statusMessage": "Operation was successful."
}

9. 制限解除の確認

コントロール無効化後、組織外プリンシパルからのアクセスが再び成功することを確認する。

aws kms encrypt \
  --key-id arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID> \
  --plaintext fileb:///tmp/plaintext.txt \
  --query '{KeyId:KeyId,EncryptionAlgorithm:EncryptionAlgorithm}' \
  --profile <組織外プロファイル名>
{
    "KeyId": "arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID>",
    "EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}

組織外プリンシパルからのアクセスが再び成功した。

10. クリーンアップ

# KMS エイリアスの削除
aws kms delete-alias \
  --alias-name alias/ct-kms-pv7-test

# KMS キーの削除スケジュール(最短 7 日)
aws kms schedule-key-deletion \
  --key-id <キー ID> \
  --pending-window-in-days 7

Amazonアソシエイトリンク