記事公開日
Claude Code の AWS 操作を SCP でリードオンリーにする|AWS MCP Server 検証

この記事のポイント
Claude Code 経由の AWS 操作を、SCP でリードオンリーに制限できるかを検証しました。AWS MCP Server 経由のリクエストにだけ付く条件キー aws:ViaAWSMCPService を使います。
- MCP 経由の書き込みだけを拒否:
同じロール(mcp-test-writer)が、SCP の適用前は書き込めて、適用後は MCP 経由の書き込みだけが拒否されました。 - 許可リスト外のロールは読み取りも拒否:
SCP の許可リストにないロールは、IAM で読み取りができても、MCP 経由では読み取りも拒否されました。 - CLI の直接実行は SCP では止まらない:
CLI の直接実行には条件キーが付かないため、Claude Code から CLI を使う経路は、Claude Code 側のdenyと運用ルールで塞ぎます。
▼ 無料ダウンロード資料
Claude 導入チェックリスト(情報システム・セキュリティ部門向け)
プラン選定・監査ログ・SSO・テナント制限・コスト管理・運用ポリシーまで、Claude / Claude Code を組織へ安全に導入するための確認項目を6カテゴリで整理。導入プロジェクトの進捗管理・監査証跡としてそのままご活用いただけます。
はじめに
DXソリューション営業本部の三浦です。
Claude Code に AWS を操作させるときに、誤ったリソースの削除や作成といった、意図しない操作は避けたいものです。
そこで、Claude Code 経由の AWS 操作を、リードオンリーに制限できないかを検証しました。
結論は次のとおりです。
- AWS MCP Server 経由のリクエストにだけ付く条件キー
aws:ViaAWSMCPServiceを SCP の条件に使うと、同じロールでも、MCP 経由の書き込みだけを拒否できました(条件キーの定義、ポリシー例)。 - 一方で、CLI で直接実行したリクエストには、この条件キーが付かないため、SCP では止まりません(IAM のグローバル条件キー)。人間が手元で CLI を直接実行する操作は止めたくないため、この仕様は都合が良いものです。Claude Code から CLI を使う経路だけは、Claude Code 側の
denyと運用ルールで塞ぎます。
構成説明
方針
| 目的 | 手段 | 止めるもの |
|---|---|---|
| Claude Code からの AWS 操作を MCP 経由に限定する | settings.json で aws* を deny。CLAUDE.md で、boto3 などでの迂回を禁止する |
CLI からの直接実行 |
| MCP 経由では、リードオンリーにする | SCP で、aws:ViaAWSMCPService が true のとき、読み取り以外と、許可リスト外のロールを拒否する |
MCP 経由の書き込み、許可リスト外のロールの全操作 |
なお、MCP 専用の IAM アクション(aws-mcp:InvokeMcp など)は廃止されており、制御には条件キーを使います(公式ドキュメント)。
Claude Code が MCP 経由で使うロールには、hub プロファイルの認証情報から AssumeRole して入ります。
環境
| 項目 | 内容 |
|---|---|
| クライアント | Claude Code(Windows 11、ネイティブ) |
| MCP | AWS MCP Server(https://aws-mcp.ap-northeast-1.api.aws/mcp)、プロキシは mcp-proxy-for-aws-cli(SigV4) |
| 認証 | IAM Identity Center(SSO)。hub プロファイルから、各ロールに AssumeRole |
| リージョン | ap-northeast-1(東京) |
アカウント
| 記号 | 役割 |
|---|---|
| 管理アカウント(hub) | IdC と Organizations があるアカウント。SCP の作成と、hub プロファイルの認証に使う。SCP は管理アカウントには効かないため、MCP の操作対象にはしない |
アカウント A(111111111111) |
メンバーアカウント。検証の主な対象。SCP を直接アタッチ |
アカウント B(222222222222) |
メンバーアカウント。アカウントの切り替えの検証用。SCP を直接アタッチ |
作成したロール
A と B の両方に、同じ CloudFormation テンプレートで 3 つのロールを作成しました。信頼先は、管理アカウント(hub)です。
| ロール | 権限 | SCP の許可リスト | 狙い |
|---|---|---|---|
mcp-test-readonly |
ReadOnlyAccess |
○ | 許可ロールの読み取り |
mcp-test-writer |
ReadOnlyAccess + mcp-test-* バケットへの S3 書き込み(作成、削除、PutObject、DeleteObject) |
○ | 「IAM では書けるロール」が、SCP で止まるかの確認 |
mcp-test-unapproved |
ReadOnlyAccess |
×(許可リスト外) | 許可リスト外のロールが、読み取りも含めて止まるかの確認 |
検証で使ったのは、A の 3 ロールと、B の mcp-test-readonly です。
プロファイルの切り替え
AWS MCP Server のプロキシに、複数のプロファイルを登録しています(AWS_MCP_PROXY_PROFILES)。Claude Code は、呼び出しごとに aws_profile を指定して、アカウントとロールを切り替えます。指定しない場合は、先頭のプロファイルが使われます(Multi-profile support)。
.mcp.json の設定です(抜粋)。
{
"mcpServers": {
"aws-mcp": {
"type": "stdio",
"command": "uvx",
"args": [
"mcp-proxy-for-aws-cli@latest",
"https://aws-mcp.ap-northeast-1.api.aws/mcp",
"--metadata",
"AWS_REGION=ap-northeast-1"
],
"env": {
"AWS_MCP_PROXY_PROFILES": "mcp-a-ro mcp-a-rw mcp-a-un mcp-b-ro"
}
}
}
}
aws_profile |
アカウント | ロール |
|---|---|---|
mcp-a-ro(既定) |
A | mcp-test-readonly |
mcp-a-rw |
A | mcp-test-writer |
mcp-a-un |
A | mcp-test-unapproved |
mcp-b-ro |
B | mcp-test-readonly |
事前準備
1. CLI からの接続が遮断されていることを確認する
settings.json で、aws CLI のコマンドを deny します。CLAUDE.md では、この制約を迂回すること(boto3 などの使用)を禁止します。
CLAUDE.md の該当部分です(抜粋)。
| 層 | 内容 | 役割 | |---|---|---| | 運用ルール | AWSへのアクセスは MCP 経由に限定(組織のガイドラインで明記) | 前提 | ## 注意 - AWS コマンド(`aws ...`)は、**このディレクトリの Claude セッションの外**(別のターミナル)で人間が実行する。
"permissions": {
"deny": [
"Bash(aws*)",
"PowerShell(aws*)",
"Read(~/.aws/**)"
]
}
deny ルールは、Claude が普段書く形のコマンドを止めるもので、別の形(フルパス、bash -c、boto3 など)まで止めるものではありません(公式ドキュメント)。そのため、CLAUDE.md で迂回も禁止し、「AWS は MCP 経由に限定する」という運用ルールを前提にしています。
Claude Code に、aws CLI の実行を依頼します。
aws sts get-caller-identity を Bash で実行して
Claude Code の応答です。
aws sts get-caller-identity を Bash で1回だけ実行します。 ● Bash(aws sts get-caller-identity) ⎿ Error: Permission to use Bash with command aws sts get-caller-identity has been denied. ● aws sts get-caller-identity は実行できませんでした。Bash での実行が権限設定(.claude/settings.json の aws* deny)で拒否されました。 - 操作: aws sts get-caller-identity(Bash) - 結果: 拒否 - エラーメッセージ(原文): Permission to use Bash with command aws sts get-caller-identity has been denied. - aws_profile / アカウントID: MCP を経由していないため該当なし 組織ポリシーと CLAUDE.md のルールに従い、python や PowerShell など別の手段での代替実行はしません。ここで止めます。
設定が効いていることが確認できました。
2. SCP の適用前に、MCP 経由で書き込めることを確認する
SCP がない状態では、MCP 経由でも書き込めることを、先に確認しておきます。あとの拒否が、SCP によるものだと示すためです。
mcp-test-writer(mcp-a-rw)で、S3 バケットを作成します。
aws_profile=mcp-a-rw で、東京リージョンに mcp-test-111111111111-baseline という S3 バケットを作って
応答です。
バケットを作成できました。
- 指定した aws_profile: mcp-a-rw(アカウントID: 111111111111)
- 呼び出し元は arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: aws-mcp の run_script 経由で、s3:CreateBucket を ap-northeast-1(東京)に対して実行しました。バケット名は mcp-test-111111111111-baseline で、LocationConstraint は ap-northeast-1 です。確認用に sts:GetCallerIdentity も1回呼んでいます。
- 結果: 成功。api_calls でも、GetCallerIdentity と CreateBucket の両方が success でした。
- BucketArn: arn:aws:s3:::mcp-test-111111111111-baseline
- エラーメッセージ: なし
マネジメントコンソール上でも、バケットが作成されていることを確認しました。
CloudTrail でも、このリクエストが MCP 経由であることを確認しました。userIdentity.invokedBy と userAgent に、aws-mcp.amazonaws.com が入っています。
eventTime : 2026-10-23T04:45:50Z eventName : CreateBucket errorCode : (なし) role : arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 invokedBy : aws-mcp.amazonaws.com userAgent : aws-mcp.amazonaws.com
3. SCP を設定する
次の SCP を作成し、アカウント A と B に直接アタッチしました。AWS のドキュメントにある「MCP 経由の削除を拒否する」例(ポリシー例)を、「読み取り以外をすべて拒否する」形に広げています。
2 つの Deny は、どちらも aws:ViaAWSMCPService が true(MCP 経由)のときだけ効きます。
DenyMcpFromNonApprovedRoles: 許可リスト(mcp-test-readonly、mcp-test-writer)にないロールの、すべての操作を拒否します。DenyNonReadActionsViaMcp:NotActionで列挙した読み取り操作以外を、すべて拒否します。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyMcpFromNonApprovedRoles",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"Bool": {
"aws:ViaAWSMCPService": "true"
},
"ArnNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::*:role/mcp-test-readonly",
"arn:aws:iam::*:role/mcp-test-writer"
]
}
}
},
{
"Sid": "DenyNonReadActionsViaMcp",
"Effect": "Deny",
"NotAction": [
"sts:GetCallerIdentity",
"s3:Get*",
"s3:List*",
"ec2:Describe*",
"iam:Get*",
"iam:List*",
"cloudformation:Describe*",
"cloudformation:Get*",
"cloudformation:List*",
"cloudwatch:Describe*",
"cloudwatch:Get*",
"cloudwatch:List*",
"logs:Describe*",
"logs:Get*",
"logs:List*",
"tag:Get*",
"organizations:Describe*",
"organizations:List*"
],
"Resource": "*",
"Condition": {
"Bool": {
"aws:ViaAWSMCPService": "true"
}
}
}
]
}
検証
※ Claude Code の応答は、長い部分を省略しています。
結果サマリー
| # | 検証 | aws_profile |
期待 | 結果 | 拒否した層 |
|---|---|---|---|---|---|
| 事前 2 | SCP 適用前の書き込み | mcp-a-rw |
成功 | 成功 | - |
| 1 | 許可ロールの読み取り | mcp-a-ro |
成功 | 成功 | - |
| 2 | 許可ロール(読み取り権限のみ)の書き込み | mcp-a-ro |
拒否 | 拒否 | IAM(メッセージ上) |
| 3 | 許可ロール+書き込み権限ありの書き込み | mcp-a-rw |
拒否 | 拒否 | SCP |
| 4 | 同じロールの読み取り | mcp-a-rw |
成功 | 成功 | - |
| 5 | 非許可ロールの読み取り | mcp-a-un |
拒否 | 拒否 | SCP |
| 6 | 別アカウントへの切り替え | mcp-b-ro |
成功(B) | 成功(B) | - |
| 7 | プロファイル未指定 | なし | 既定(mcp-a-ro、A) |
一致 | - |
| 8 | CLI での直接実行(対照) | mcp-a-rw |
成功 | 成功 | - |
mcp-a-rw(同じロール、同じ CreateBucket)の結果が、SCP の適用前後と、MCP 経由か CLI 直接かで変わりました。
| 条件 | 結果 |
|---|---|
| SCP 適用前、MCP 経由(事前 2) | 成功 |
| SCP 適用後、MCP 経由(検証 3) | SCP で拒否 |
| SCP 適用後、CLI で直接実行(検証 8) | 成功 |
1. 許可ロールの読み取り
SCP の許可リストにあるロール(mcp-test-readonly)で、読み取りができるかを確認します。
mcp-a-ro で、呼び出し元のアカウント ID と S3 バケット一覧を出して
mcp-a-ro で、アカウントIDの取得とバケット一覧の取得はどちらも成功しました。
- 指定した aws_profile: mcp-a-ro(アカウントID: 111111111111)
- 呼び出し元は
arn:aws:sts::111111111111:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: aws-mcp の run_script 経由で sts:GetCallerIdentity と s3:ListBuckets を実行しました。
- 結果: 成功。api_calls は両方とも success で、バケットは127個でした。
- エラーメッセージ: なし
先ほど mcp-a-rw で作成した mcp-test-111111111111-baseline は、一覧に含まれていました(作成日時: 2026-10-23T04:45:51Z)。
mcp-a-ro から読み取りで確認できたことになります。
(以下、既存バケットの説明は省略)
2. 許可ロール(読み取り権限のみ)の書き込み
同じロールで、書き込みを試します。
mcp-a-ro で mcp-test-111111111111-ro-write という S3 バケットを作って
mcp-a-ro でのバケット作成は拒否されました。想定どおりの結果です。
- 指定した aws_profile: mcp-a-ro(アカウントID: 111111111111)
- 呼び出し元は
arn:aws:sts::111111111111:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: s3:CreateBucket(バケット名 mcp-test-111111111111-ro-write、ap-northeast-1)
- 結果: 拒否(AccessDenied)。バケットは作成されていません。
- エラーメッセージ(原文):
An error occurred (AccessDenied) when calling the CreateBucket operation: User:
arn:aws:sts::111111111111:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 is not
authorized to perform: s3:CreateBucket on resource: "arn:aws:s3:::mcp-test-111111111111-ro-write"
with an explicit deny in an identity-based policy
拒否メッセージは explicit deny in an identity-based policy で、メッセージ上は、IAM(アイデンティティベースのポリシー)側の明示的な拒否です。
この時点では SCP もアタッチ済みで、2 つ目の Deny(DenyNonReadActionsViaMcp)も、この CreateBucket に該当します。SCP の効果は、IAM では書き込みが許可されているロールで確認する、次の検証 3 で見ます。
CloudTrail にも、同じ内容が記録されています。
eventTime : 2026-10-23T05:19:17Z eventName : CreateBucket errorCode : AccessDenied errorMessage : User: arn:aws:sts::111111111111:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 is not authorized to perform: s3:CreateBucket on resource: "arn:aws:s3:::mcp-test-111111111111-ro-write" with an explicit deny in an identity-based policy role : arn:aws:sts::111111111111:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 invokedBy : aws-mcp.amazonaws.com userAgent : aws-mcp.amazonaws.com
3. 許可ロール+書き込み権限ありの書き込み
mcp-test-writer は、SCP の許可リストにあるロールで、IAM でも S3 の書き込みが許可されています。事前準備の 2 では、このロールでバケットを作成できました。同じ操作を、SCP の適用後にもう一度実行します。
mcp-a-rw で mcp-test-111111111111-rw-write という S3 バケットを作って
mcp-a-rw でのバケット作成は拒否されました。今回の拒否は SCP によるものです。
- 指定した aws_profile: mcp-a-rw(アカウントID: 111111111111)
- 呼び出し元は arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: s3:CreateBucket(バケット名 mcp-test-111111111111-rw-write、ap-northeast-1)
- 結果: 拒否(AccessDenied)。バケットは作成されていません。
- エラーメッセージ(原文):
An error occurred (AccessDenied) when calling the CreateBucket operation: User:
arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 is not
authorized to perform: s3:CreateBucket on resource: "arn:aws:s3:::mcp-test-111111111111-rw-write"
with an explicit deny in a service control policy:
arn:aws:organizations::999999999999:policy/o-xxxxxxxxxx/service_control_policy/p-xxxxxxxx
事前準備の 2 と、同じロール、同じ操作で、結果が変わりました。拒否メッセージには、SCP の ARN が含まれています。
mcp-test-writer は許可リストのロールなので、1 つ目の Deny(DenyMcpFromNonApprovedRoles)の対象ではありません。このため、2 つ目の DenyNonReadActionsViaMcp による拒否です。拒否メッセージには Statement の Sid は表示されないので、消去法で判断しています。
CloudTrail のイベントです。invokedBy と userAgent が aws-mcp.amazonaws.com で、MCP 経由のリクエストが拒否されています。
eventTime : 2026-10-23T05:32:04Z eventName : CreateBucket errorCode : AccessDenied errorMessage : User: arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 is not authorized to perform: s3:CreateBucket on resource: "arn:aws:s3:::mcp-test-111111111111-rw-write" with an explicit deny in a service control policy: arn:aws:organizations::999999999999:policy/o-xxxxxxxxxx/service_control_policy/p-xxxxxxxx role : arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 invokedBy : aws-mcp.amazonaws.com userAgent : aws-mcp.amazonaws.com
4. 同じロールの読み取り
SCP が適用されている状態で、検証 3 と同じロール(mcp-a-rw)の読み取りが通るかを確認します。
mcp-a-rw で S3 バケット一覧を出して
mcp-a-rw でのバケット一覧の取得は成功しました。
- 指定した aws_profile: mcp-a-rw(アカウントID: 111111111111)
- 呼び出し元は arn:aws:sts::111111111111:assumed-role/mcp-test-writer/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: aws-mcp の run_script 経由で sts:GetCallerIdentity と s3:ListBuckets を実行しました。
- 結果: 成功。バケットは127個で、api_calls も両方 success でした。
- エラーメッセージ: なし
mcp-test- で始まるバケットは、mcp-test-111111111111-baseline の1つだけです。
拒否された mcp-test-111111111111-ro-write と mcp-test-111111111111-rw-write は存在しません。
書き込みは拒否され、読み取りは通っています。
5. 非許可ロールの読み取り
mcp-test-unapproved は、IAM では ReadOnlyAccess で読み取りができるロールですが、SCP の許可リストにはありません。同じ読み取りが、通るかを確認します。
mcp-a-un で S3 バケット一覧を出して
mcp-a-un でのバケット一覧の取得は拒否されました。想定どおりの結果です。
- 指定した aws_profile: mcp-a-un(アカウントID: 111111111111)
- 呼び出し元は
arn:aws:sts::111111111111:assumed-role/mcp-test-unapproved/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: sts:GetCallerIdentity(成功)と s3:ListBuckets(API 上の許可名は s3:ListAllMyBuckets)。
- 結果: GetCallerIdentity は成功し、ListBuckets は拒否(AccessDenied)されました。バケット一覧は取得できていません。
- エラーメッセージ(原文):
An error occurred (AccessDenied) when calling the ListBuckets operation: User:
arn:aws:sts::111111111111:assumed-role/mcp-test-unapproved/mcp-proxy-for-aws-1792730708 is not
authorized to perform: s3:ListAllMyBuckets with an explicit deny in a service control policy:
arn:aws:organizations::999999999999:policy/o-xxxxxxxxxx/service_control_policy/p-xxxxxxxx
検証 1 と 4 で、許可ロールの同じ操作(s3:ListAllMyBuckets)は通っています。この操作は、2 つ目の Deny の許可リスト(s3:List*)に含まれるので、2 つ目では拒否されません。したがって、この拒否は、1 つ目の DenyMcpFromNonApprovedRoles(許可リスト外のロールを拒否する Deny)によるものです。
sts:GetCallerIdentity は、非許可ロールでも成功しています。この操作は、明示的な Deny があっても実行できる仕様のためです(GetCallerIdentity)。
CloudTrail のイベントです。
eventTime : 2026-10-23T05:37:20Z eventName : ListBuckets errorCode : AccessDenied errorMessage : User: arn:aws:sts::111111111111:assumed-role/mcp-test-unapproved/mcp-proxy-for-aws-1792730708 is not authorized to perform: s3:ListAllMyBuckets with an explicit deny in a service control policy: arn:aws:organizations::999999999999:policy/o-xxxxxxxxxx/service_control_policy/p-xxxxxxxx role : arn:aws:sts::111111111111:assumed-role/mcp-test-unapproved/mcp-proxy-for-aws-1792730708 invokedBy : aws-mcp.amazonaws.com userAgent : aws-mcp.amazonaws.com
6. 別アカウントへの切り替え
aws_profile を mcp-b-ro に変えて、アカウント B に切り替えられるかを確認します。
mcp-b-ro で、呼び出し元のアカウント ID と S3 バケット一覧を出して
mcp-b-ro で、アカウントIDの取得とバケット一覧の取得はどちらも成功しました。
- 指定した aws_profile: mcp-b-ro(アカウントID: 222222222222)
- 呼び出し元は arn:aws:sts::222222222222:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 でした。
- 実行した操作: aws-mcp の run_script 経由で sts:GetCallerIdentity と s3:ListBuckets を実行しました。
- 結果: 成功。api_calls は両方とも success で、バケットは6個でした。
- エラーメッセージ: なし
(バケット一覧は省略)
アカウントは、アカウントA(111111111111)とは別のアカウントです。
呼び出し元のロールが、アカウント B の mcp-test-readonly に切り替わっています。
7. プロファイル未指定
aws_profile を指定しないと、どのロールが使われるかを確認します。
aws_profile を指定せずに、呼び出し元のアカウント ID を出して
aws_profile を指定しない呼び出しは、成功しました。
- 指定した aws_profile: なし(省略)。
- 実際の呼び出し元は arn:aws:sts::111111111111:assumed-role/mcp-test-readonly/mcp-proxy-for-aws-1792730708 で、アカウントIDは 111111111111(アカウントA)です。
- 実行した操作: aws-mcp の run_script 経由で sts:GetCallerIdentity を実行しました。
- 結果: 成功
- エラーメッセージ: なし
プロファイルを省略すると、先頭の mcp-a-ro(アカウントAの mcp-test-readonly)が使われます。CLAUDE.md の記載どおりです。
プロファイルを指定しないと、登録した先頭のプロファイル(mcp-a-ro)が使われます。先頭に、書き込み権限のないロールを置いておくと、指定漏れのときに安全側に倒れます。
8. CLI での直接実行(対照)
SCP は、MCP 経由のリクエストにだけ効くはずです。確認のために、SCP の適用後に、検証 3 と同じロール(mcp-a-rw)で、同じ操作(CreateBucket)を、CLI で直接実行します。Claude セッションの外(別のターミナル)で、人間が実行しています。
aws s3api create-bucket --bucket mcp-test-111111111111-cli-direct --region ap-northeast-1 --create-bucket-configuration LocationConstraint=ap-northeast-1 --profile mcp-a-rw
{
"Location": "http://mcp-test-111111111111-cli-direct.s3.amazonaws.com/",
"BucketArn": "arn:aws:s3:::mcp-test-111111111111-cli-direct"
}
同じロール、同じ操作でも、MCP 経由では SCP に拒否され(検証 3)、CLI の直接実行では成功しました。CLI の直接実行には aws:ViaAWSMCPService が付かないため、SCP の Deny の条件に一致しません。
CloudTrail のイベントです。MCP 経由のイベントとは、invokedBy と userAgent が違います。
eventTime : 2026-10-25T07:38:27Z eventName : CreateBucket errorCode : (なし) role : arn:aws:sts::111111111111:assumed-role/mcp-test-writer/botocore-session-1792913890 invokedBy : (なし) userAgent : [aws-cli/2.33.6 ... md/command#s3api.create-bucket]
| 項目 | MCP 経由(検証 3) | CLI の直接実行(検証 8) |
|---|---|---|
| ロール | mcp-test-writer |
mcp-test-writer(同じ) |
userIdentity.invokedBy |
aws-mcp.amazonaws.com |
なし |
userAgent |
aws-mcp.amazonaws.com |
aws-cli/2.33.6 ... |
| 結果 | SCP で拒否 | 成功 |
MCP 経由のリクエストにだけ、MCP サーバーを呼び出し元とする記録(invokedBy)が付いています。SCP の条件キー aws:ViaAWSMCPService も、このリクエストにだけ付くという、ドキュメントの記述と一致します。人間が手元で CLI を使う操作は止めたくないので、この動作は期待どおりです。
まとめ
わかったこと
aws:ViaAWSMCPServiceを条件にした SCP で、MCP 経由のリクエストだけを、リードオンリーにできました。同じロール(mcp-test-writer)が、SCP の前は書き込めて、SCP の後は MCP 経由の書き込みだけが拒否されました。- SCP の許可リストにないロールは、IAM で読み取りができても、MCP 経由では読み取りも拒否されました。
- 複数アカウントは、
AWS_MCP_PROXY_PROFILESに登録したプロファイルを、呼び出しごとにaws_profileで切り替えられました。 - CLI の直接実行には、SCP は効きません。
限界と注意点
- Claude Code が CLI を直接実行する経路は、SCP では止まりません。人間が手元で CLI を使う操作は止めたくないので、SCP の対象外であること自体は問題ありません。一方で、Claude Code の
denyは、セキュリティの境界ではありません(公式ドキュメント)。今回は、組織のガイドライン(MCP 経由に限定)と、CLAUDE.mdによる迂回の禁止で補っています。 - SCP は、管理アカウントには効きません。管理アカウントは、MCP の操作対象にしないようにしてください。
- 読み取りの許可リスト(
NotAction)は、自分で管理する必要があります。SCP は、1 つあたり 10,240 文字、1 つの対象に付けられるのは 10 個までです(クォータ)。今回の許可リストは、検証用の最小限です。
QESでは、ガバナンス整備・セキュアな利用環境構築・利活用コンサルティング・セキュリティレビューまで、Claude / Claude Code の組織導入を一貫して支援しています。AWS(Amazon Bedrock)経由での提供にも対応しています。支援内容は下記のサービスページ、および無料の「Claude 導入チェックリスト」をご覧いただくか、お問い合わせフォームよりお気軽にご相談ください。
▼ 無料ダウンロード資料
Claude 導入チェックリスト(情報システム・セキュリティ部門向け)
プラン選定・監査ログ・SSO・テナント制限・コスト管理・運用ポリシーまで、Claude / Claude Code を安全に導入するための確認項目を6カテゴリで整理。導入プロジェクトの進捗管理・監査証跡としてそのままご活用いただけます。
※Amazon Web Services、"Powered by Amazon Web Services"ロゴ、およびブログで使用されるその他のAWS商標は、米国その他の諸国における、Amazon.com, Inc.またはその関連会社の商標です。
※このブログで参照されている、Anthropic、Claude、Claude Code は、Anthropic, PBCの米国およびその他の国における商標または登録商標です。
※このブログで参照されている、Windows は、米国 Microsoft Corporation の米国およびその他の国における登録商標または商標です。

