CT.SECRETSMANAGER.PV.1
コントロールの説明
組織内の Secrets Manager リソースに対し、組織外の IAM プリンシパルからのアクセスを禁止する。
本コントロールは RCP(リソースコントロールポリシー)により、組織外の IAM プリンシパル(別の AWS アカウントなど)から Secrets Manager リソースへのアクセスをブロックする。リソースポリシーで外部アカウントにアクセスを許可していても、RCP が優先されアクセスが拒否される。Control Tower で対象の OU を指定して有効化すると、その OU 配下の全アカウントの全 Secrets Manager リソースに適用される。
Security Hub CSPM には Secrets Manager の外部アクセスを検出するコントロールがない。そのため、外部アクセスの制限には本コントロールのような予防的な仕組みが重要になる。
| 方法 | 内容 | スコープ |
|---|---|---|
| IAM Access Analyzer | 外部アクセスアナライザーで Secrets Manager の外部共有を検出 | 検出のみ(ブロックしない) |
| リソースポリシー(手動) | シークレットごとにアクセス許可を管理 | シークレット単位 |
| CT.SECRETSMANAGER.PV.1(本コントロール) | OU 配下の全シークレットで組織外アクセスを自動的に拒否 | OU 単位 |
検証の流れ
flowchart LR
A[1. 事前準備] --> B[2. 組織外から<br>シークレット取得成功]
B --> C[3. CT.SECRETSMANAGER.PV.1<br>有効化]
C --> D[4. 既存設定<br>維持を確認]
C --> E[5. 組織外からの<br>アクセス拒否を確認]
D & E --> F[6. CloudTrail<br>で確認]
F --> G[7. CT.SECRETSMANAGER.PV.1<br>無効化]
G --> H[8. 組織外から<br>シークレット取得成功]
結果
- コントロールの有効化前、組織外アカウントから Secrets Manager のシークレットを取得できることを確認できた。
- コントロールの有効化後、既存のリソースポリシー(組織外アカウントへの許可)は維持されることを確認できた。
- 組織外アカウントからのアクセスが
explicit deny in a resource control policyで拒否されることを確認できた。 - 拒否されたイベントが CloudTrail の管理イベントとして記録されること、および管理アカウントの Organization Trail(CloudWatch Logs)からも確認できることを確認できた。
- コントロールの無効化後、再び組織外アカウントからシークレットを取得できることを確認できた。
1. 事前準備
Secrets Manager はシークレットの暗号化に KMS キーを使用する。デフォルトの AWS マネージドキー(aws/secretsmanager)はキーポリシーを編集できないため、組織外アカウントに復号を許可できない。そのため、カスタマーマネージドキー(CMK)を作成し、キーポリシーで組織外アカウントに kms:Decrypt を許可する。なお、CT.SECRETSMANAGER.PV.1 は Secrets Manager の API を対象とする RCP であり、KMS キーへのアクセスは制御しない。
KMS CMK の作成
aws kms create-key \
--description "ct-secretsmanager-pv1-test"{
"KeyMetadata": {
"AWSAccountId": "<Workload のアカウント ID>",
"KeyId": "<キー ID>",
"Arn": "arn:aws:kms:ap-northeast-1:<Workload のアカウント ID>:key/<キー ID>",
"CreationDate": "2026-03-15T23:17:00.000000+09:00",
"Enabled": true,
"Description": "ct-secretsmanager-pv1-test",
"KeyUsage": "ENCRYPT_DECRYPT",
"KeyState": "Enabled",
"Origin": "AWS_KMS",
"KeyManager": "CUSTOMER",
"CustomerMasterKeySpec": "SYMMETRIC_DEFAULT",
"KeySpec": "SYMMETRIC_DEFAULT",
"EncryptionAlgorithms": [
"SYMMETRIC_DEFAULT"
],
"MultiRegion": false
}
}aws kms create-alias \
--alias-name alias/ct-secretsmanager-pv1-test \
--target-key-id <キー ID>キーポリシーで組織外アカウントに kms: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": "AllowExternalDecrypt",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>"},
"Action": "kms:Decrypt",
"Resource": "*"
}
]
}'シークレットの作成
CMK で暗号化したシークレットを作成する。
aws secretsmanager create-secret \
--name ct-secretsmanager-pv1-test \
--secret-string '{"username":"testuser","password":"testpass"}' \
--kms-key-id <キー ID>{
"ARN": "arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス>",
"Name": "ct-secretsmanager-pv1-test",
"VersionId": "<バージョン ID>"
}リソースポリシーの設定
シークレットのリソースポリシーで組織外アカウントに GetSecretValue を許可する。
aws secretsmanager put-resource-policy \
--secret-id ct-secretsmanager-pv1-test \
--resource-policy '{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowExternalAccess",
"Effect": "Allow",
"Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>"},
"Action": "secretsmanager:GetSecretValue",
"Resource": "*"
}
]
}'{
"ARN": "arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス>",
"Name": "ct-secretsmanager-pv1-test"
}2. 有効化前の確認
組織外アカウントからシークレットを取得できることを確認する。以降、組織外アカウントで実行するコマンドには --profile <組織外アカウント> を付与する。
aws secretsmanager get-secret-value \
--secret-id arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス> \
--profile <組織外アカウント>{
"ARN": "arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス>",
"Name": "ct-secretsmanager-pv1-test",
"VersionId": "<バージョン ID>",
"SecretString": "{\"username\":\"testuser\",\"password\":\"testpass\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2026-03-15T23:17:44.548000+09:00"
}リソースポリシーと KMS キーポリシーの両方で許可されているため、組織外アカウントからシークレットを取得できた。
3. CT.SECRETSMANAGER.PV.1 の有効化
aws controltower enable-control \
--control-identifier arn:aws:controlcatalog:::control/dvhe47fxg5o6lryqrq9g6sxg4 \
--target-identifier <OU の ARN>{
"arn": "arn:aws:controltower:ap-northeast-1:<管理アカウント ID>:enabledcontrol/<enabledcontrol ID>",
"operationIdentifier": "<オペレーション ID>"
}有効化が完了するまで待機する。
aws controltower get-control-operation \
--operation-identifier <オペレーション ID>{
"controlOperation": {
"operationType": "ENABLE_CONTROL",
"status": "SUCCEEDED",
"statusMessage": "Operation was successful."
}
}4. 既存設定の維持確認
RCP はリソースポリシーを変更するのではなく、アクセス制御のレイヤーとして機能する。リソースポリシーが自動的に変更されていないことを確認する。
aws secretsmanager get-resource-policy \
--secret-id ct-secretsmanager-pv1-test{
"ARN": "arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス>",
"Name": "ct-secretsmanager-pv1-test",
"ResourcePolicy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"AllowExternalAccess\",\"Effect\":\"Allow\",\"Principal\":{\"AWS\":\"arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>\"},\"Action\":\"secretsmanager:GetSecretValue\",\"Resource\":\"*\"}]}"
}リソースポリシーは変更されていない。RCP はリソースの設定を変更せず、独立したアクセス制御レイヤーとして組織外アクセスをブロックする。
5. 拒否の確認
組織外アカウントからシークレットを取得する。
aws secretsmanager get-secret-value \
--secret-id arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス> \
--profile <組織外アカウント>An error occurred (AccessDeniedException) when calling the GetSecretValue operation:
User: arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名>
is not authorized to perform: secretsmanager:GetSecretValue on resource:
arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス>
with an explicit deny in a resource control policyリソースポリシーで許可されているにもかかわらず、RCP により拒否された。エラーメッセージに explicit deny in a resource control policy と記載されており、RCP による拒否であることがわかる。
6. CloudTrail での確認
拒否されたイベントが CloudTrail に記録されていることを確認する。Secrets Manager の GetSecretValue は CloudTrail の管理イベントとして記録されるため、CloudTrail のイベント履歴から確認できる。
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=GetSecretValue \
--start-time 2026-03-15T23:19:00+09:00 \
--end-time 2026-03-15T23:22:00+09:00 \
--query 'Events[].CloudTrailEvent' \
--output text | jq 'select(.errorCode != null) | {eventName, errorCode, errorMessage}'{
"eventName": "GetSecretValue",
"errorCode": "AccessDenied",
"errorMessage": "User: arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名> is not authorized to perform: secretsmanager:GetSecretValue on resource: arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス> with an explicit deny in a resource control policy: arn:aws:organizations::<管理アカウント ID>:policy/<組織 ID>/resource_control_policy/<ポリシー ID>"
}errorMessage に explicit deny in a resource control policy と記録されており、RCP による拒否であることがわかる。S3 の GetObject 等はデータイベントに分類されるため別途設定が必要だが、Secrets Manager の GetSecretValue は管理イベントのため、追加設定なしで CloudTrail に記録される。
管理アカウントの Organization Trail(CloudWatch Logs)からも同じイベントを確認できる。
aws logs start-query \
--log-group-name "aws-controltower/CloudTrailLogs" \
--start-time $(date -d '2026-03-15T23:19:00+09:00' +%s) \
--end-time $(date -d '2026-03-15T23:22:00+09:00' +%s) \
--query-string 'fields @timestamp, eventName, errorCode, errorMessage
| filter eventName = "GetSecretValue" and errorCode = "AccessDenied"
| sort @timestamp asc'aws logs get-query-results --query-id <クエリ ID>{
"results": [
[
{"field": "@timestamp", "value": "2026-03-15 14:21:45.033"},
{"field": "eventName", "value": "GetSecretValue"},
{"field": "errorCode", "value": "AccessDenied"},
{"field": "errorMessage", "value": "User: arn:aws:iam::<組織外アカウント ID>:user/<IAM ユーザー名> is not authorized to perform: secretsmanager:GetSecretValue on resource: arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス> with an explicit deny in a resource control policy"}
]
],
"status": "Complete"
}管理アカウントの CloudWatch Logs にも同じ拒否イベントが記録されていることを確認できた。
7. CT.SECRETSMANAGER.PV.1 の無効化
aws controltower disable-control \
--control-identifier arn:aws:controlcatalog:::control/dvhe47fxg5o6lryqrq9g6sxg4 \
--target-identifier <OU の ARN>{
"operationIdentifier": "<オペレーション ID>"
}aws controltower get-control-operation \
--operation-identifier <オペレーション ID>{
"controlOperation": {
"operationType": "DISABLE_CONTROL",
"status": "SUCCEEDED",
"statusMessage": "Operation was successful."
}
}8. 制限解除の確認
コントロール無効化後、組織外アカウントから再びシークレットを取得できることを確認する。
aws secretsmanager get-secret-value \
--secret-id arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス> \
--profile <組織外アカウント>{
"ARN": "arn:aws:secretsmanager:ap-northeast-1:<Workload のアカウント ID>:secret:ct-secretsmanager-pv1-test-<サフィックス>",
"Name": "ct-secretsmanager-pv1-test",
"VersionId": "<バージョン ID>",
"SecretString": "{\"username\":\"testuser\",\"password\":\"testpass\"}",
"VersionStages": [
"AWSCURRENT"
],
"CreatedDate": "2026-03-15T23:17:44.548000+09:00"
}組織外アカウントからのアクセスが再び成功した。コントロールを無効化すると即座に制限が解除される。
9. クリーンアップ
# シークレットを即時削除
aws secretsmanager delete-secret \
--secret-id ct-secretsmanager-pv1-test \
--force-delete-without-recovery
# KMS キーの削除スケジュール(最短 7 日)
aws kms schedule-key-deletion \
--key-id <キー ID> \
--pending-window-in-days 7
# KMS エイリアスの削除
aws kms delete-alias \
--alias-name alias/ct-secretsmanager-pv1-test補足1: IAM Access Analyzer での検出について
Security Hub CSPM には Secrets Manager の外部アクセスを検出するコントロールがない。検出手段としては IAM Access Analyzer の外部アクセスアナライザーがあり、Secrets Manager や KMS の外部共有を検出できる。また、RCP が有効な場合は「RCP restriction: Applicable」と表示され、RCP により実質的にアクセスがブロックされていることがわかる。詳細については別記事で取り上げる予定。
補足2: 除外プリンシパル
CT.SECRETSMANAGER.PV.1 の有効化時にパラメータ ExemptedPrincipalArns で特定の IAM ロールの ARN を指定すると、そのロールのみ RCP の制限を回避(組織外からのアクセスを許可)できる。例えば、組織外のパートナー企業のアカウントが一時的にシークレットを参照する必要がある場合に使用する。
設定方法は Configure controls with parameters を参照。