Skip to main content
Glama
kbroughton
by kbroughton

downscoping-mcp

AIツールで使用するために、ユーザーの認証情報権限を設定可能なサブセットまでダウングレードします。ユーザーには、特定のGCPプロジェクトやAWSアカウントのサービスにマッピングされた、日常業務に必要な権限のサブセットが既に付与されているはずです。ダウンスコーピングとは、企業基準に準拠するためにアクションをさらに制限することを指します。

権限付与は通常「<Action allowed> on <Resource>」という形式です。ダウンスコーピングは、例えば読み取り/書き込みから読み取り専用にするなど、機能を削減することで「<Action allowed>」に影響を与えます。

  • Googleドライブドキュメントの読み取りは許可するが、書き込みは許可しない

  • GitHubのPR読み取りは許可するが、マージや承認は許可しない

  • GCPプロジェクトのログ読み取りは許可するが、デプロイは許可しない


問題点

Claude Codeは、環境内に存在する認証情報を使用して実行されます。ファイルを読み取れるモデルは、同じトークンを使用して gh repo deletegcloud projects delete、または aws iam delete-user を呼び出すこともできます。一度の脱獄(ジェイルブレイク)、プロンプトインジェクション、またはConfused Deputy攻撃で十分な被害が発生します。偶発的なエラーも同様です。Claudeがリリースブランチに直接プッシュすることで、ブランチ保護やGitHub Actionsが正しく設定されていない場合、デプロイパイプラインがトリガーされる可能性があります。

Related MCP server: MCP Airlock

なぜこのアプローチなのか?

明白な代替案は、AI用にチームごと、環境ごとに専用の低権限IAMロールやサービスアカウントを作成することです。これはすぐに厳しい制限に突き当たります。

一般的な ~/.aws/config には、すでに異なるアカウントやロールをカバーする60以上のプロファイルが存在します。これをAI専用のダウンスコープされたプロファイルで倍増させると、120以上のプロファイル、継続的なIaCメンテナンス、そして適切なプロファイルを接続するための .claude/settings.local.json 内のエンジニアごとの設定が必要になります。AWSにはアカウントあたり1,000というデフォルトのIAMロールクォータがあり(上限引き上げには申請が必要)、新しいロールが増えるたびに監査、ローテーション、元のロールとの同期が必要な対象が増えることになります。

このツールは異なるアプローチをとります。IAMに触れることなく、呼び出し時に動的にダウンスコープします。これは aws sts assume-role --policy-arns と同様に機能し、引き受けたロールの有効な権限を、そのロールのポリシーと提供されたポリシーARNの積集合に制限します。ここでは、積集合はIAMポリシー文書ではなく、プロジェクトにチェックインされたYAMLファイルで定義されますが、セマンティクスは同じです。既存の認証情報が使用されますが、定義したルールに従って操作ごとに有効な機能が絞り込まれます。

重要な特性が1つ維持されています。このツールは権限を削減することしかできず、決して増やすことはできません。 IAM設定を変更することなく、AIツールの使用を安全かつ企業ポリシーに準拠させるためのガードレールを設定します。


仕組み

ルールは各コマンドに対して上から順に評価されます。最初に一致したものが適用されます。3つの結果が考えられます。

アクション

動作

allow

一致したスロットにスコープされたトークンを注入し、コマンドを実行する

review

コマンドをブロックし、Claudeにユーザーへ手動実行を依頼するよう伝える

deny

コマンドをブロックし、ClaudeにAI使用は許可されていないと伝える

ブロックメッセージにはルール名と一致したパターンが含まれるため、理由は常に明確です。

Tier 1 — 動的ダウンスコーピング(推奨)

ネイティブのクラウドSTSは、呼び出し時に環境認証情報から制限されたトークンを導出します。新しいIAMロールや事前プロビジョニングされたトークンは不要です。

  • AWS: インラインポリシーを使用した sts:GetFederationToken または sts:AssumeRole。有効な権限 = IDポリシーとインラインポリシーの積集合。詳細は docs/AWS_DOWNSCOPING.md を参照してください。

  • GCP: sts.googleapis.com を介したCredential Access Boundary。環境トークンを特定のリソースとロールに制限します。Cloud Storageのみサポート。 その他のGCPサービスについては、OAuthスコープ制限にフォールバックします。詳細は docs/GCP_DOWNSCOPING.md を参照してください。

Tier 2 — トークンスロット(フォールバック)

動的APIが存在しない場合に使用されます。YAMLルールに基づいて、操作ごとに事前プロビジョニングされた狭い範囲のトークンが選択されます。

  • GitHub: 細粒度PAT(動的ダウンスコーピングAPIは利用不可)。詳細は docs/GITHUB_DOWNSCOPING.md を参照してください。

  • GCP非GCSサービス: generateAccessToken を介したOAuthスコープ制限。APIレベルの粒度のみ。

  • kubectl: 最小限のRBACロールにバインドされたKubernetes ServiceAccountトークン。EKSおよびGKEクラスターは、基盤となるクラウドプロバイダーの動的ダウンスコーピングを使用できます。詳細は docs/KUBECTL_DOWNSCOPING.md を参照してください。

2つの強制モード

モード1 — Bashフック(CLIツール)

PreToolUse フックがすべての Bash ツール呼び出しをインターセプトします。コマンドが既知のサービスバイナリ(ghgcloudawskubectl)で始まる場合、フックは引数をYAMLルールと照合し、アクションを評価し、スコープされたトークンでコマンドを書き換えるか、ブロックメッセージを出力します。Claudeが書き換えを見ることはありません。

モード2 — MCPプロキシ

MCPプロキシはアップストリームのMCPサーバーをラップします。各ツール呼び出しを転送する前に、同じYAMLルールを適用してその特定のツール用にスコープされたトークンを注入します。現在は github-pr-issue-analyser サーバーをサポートしており、他のサーバーは将来の拡張予定です。


クイックスタート

1. インストール

pip install -e .

2. 認証情報の設定

シェルプロファイルまたはCI環境でスコープされたトークンをエクスポートします:

# GitHub (token_slot mode — only option for GitHub)
export GITHUB_TOKEN_READONLY=ghp_...       # fine-grained: contents:read, issues:read
export GITHUB_TOKEN_ORG_WRITE=ghp_...      # fine-grained: issues:write, pull_requests:write

# GCP (token_slot fallback — preferred is CAB via google.auth.downscoped)
export GCLOUD_TOKEN_VIEWER=ya29....
export GCLOUD_TOKEN_EDITOR=ya29....

# AWS (token_slot fallback — preferred is sts:GetFederationToken)
export AWS_ACCESS_KEY_ID_READONLY=AKIA...

3. ポリシーファイルの作成

cp config.example.yaml .claude/downscoping.yaml

組織のアクセスモデルに合わせて編集してください。downscope_mode フィールドでサービスごとのメカニズムを選択します:

version: 1

services:
  aws:
    downscope_mode: sts_policy      # Tier 1: derive restricted token from ambient creds
    inline_policy:
      Version: "2012-10-17"
      Statement:
        - Effect: Allow
          Action: ["s3:GetObject", "s3:ListBucket", "ec2:Describe*"]
          Resource: "*"
    rules:
      - name: "S3 writes require review"
        match:
          args_pattern: "s3 (cp|mv|rm|sync) .* s3://"
        action: review
      - name: "IAM mutations denied"
        match:
          args_pattern: "iam (create|delete|put|attach|detach)"
        action: deny

  gh:
    downscope_mode: token_slot      # Tier 2: GitHub has no dynamic API
    token_slots:
      readonly:
        env_var: GITHUB_TOKEN_READONLY
        inject_as: GITHUB_TOKEN
      org-write:
        env_var: GITHUB_TOKEN_ORG_WRITE
        inject_as: GITHUB_TOKEN
    default_slot: readonly
    rules:
      - name: "repo deletion denied"
        match:
          args_pattern: "repo delete|repo rename"
        action: deny
      - name: "pr merge requires human review"
        match:
          args_pattern: "pr merge"
        action: review
      - name: "permitted writes use org-write token"
        match:
          args_pattern: "pr (create|edit)|issue (create|edit)|push"
        action: allow
        slot: org-write

4. フックの登録

プロジェクトの .claude/settings.json に追加します:

{
  "env": {
    "CLAUDE_PLUGIN_ROOT": "/path/to/downscoping-mcp"
  },
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/pre_tool_use.py",
            "timeout": 5
          }
        ]
      }
    ]
  }
}

5. (オプション) MCPプロキシの有効化

プロジェクトルートの .mcp.json に追加します:

{
  "mcpServers": {
    "credential-downscope-proxy": {
      "command": "python3",
      "args": ["-m", "credential_downscope.mcp_proxy"],
      "env": {
        "PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/src",
        "GITHUB_INTEGRATION_SRC": "/path/to/upstream-mcp-server/src"
      }
    }
  }
}

ポリシーファイルリファレンス

ルールアクション

rules:
  - name: "human-readable name — appears in block messages"
    match:
      args_pattern: "<regex matched against CLI args after the binary>"
      # OR for MCP tools:
      tools: [tool_name_1, tool_name_2]
    action: allow    # inject scoped token (default if action omitted)
    slot: readonly   # which token slot to use (action: allow only)

  - name: "example deny"
    match:
      args_pattern: "iam delete"
    action: deny     # blocked; Claude told it is not permitted for AI use

  - name: "example review"
    match:
      args_pattern: "s3 cp .* s3://"
    action: review   # blocked; Claude told to ask user to run manually

ルールの順序は重要です — ルールは上から順に評価され、最初に一致したものが適用されます。特定の deny/review ルールは、広範な allow ルールの前に配置してください。

トークン解決順序 (token_slotモード)

  1. 現在のプロセス環境から env_var を読み取る

  2. 設定されていない場合は、inject_as 変数にフォールバックする(環境認証情報を使用)

  3. どちらも設定されていない場合は、コマンドをそのまま通過させる


アーキテクチャ

Claude Code
    │
    ├─ Bash tool call ──► PreToolUse hook (hooks/pre_tool_use.py)
    │                          │
    │                          ├─ load .claude/downscoping.yaml
    │                          ├─ detect service binary
    │                          ├─ match args against rules → RuleDecision
    │                          │
    │                          ├─ action=deny   → {"continue": false, "stopReason": "...denied..."}
    │                          ├─ action=review → {"continue": false, "stopReason": "...run manually..."}
    │                          └─ action=allow  → {"updatedInput": {"command": "TOKEN=value <cmd>"}}
    │
    └─ MCP tool call ──► credential-downscope-proxy (mcp_proxy.py)
                              │
                              ├─ match tool name against MCP rules → RuleDecision
                              ├─ inject scoped token into env
                              └─ forward to upstream MCP server

サポートされているサービス

サービス

バイナリ / インターフェース

ダウンスコープモード

ドキュメント

GitHub CLI

gh

token_slot

GITHUB_DOWNSCOPING.md

AWS CLI

aws

sts_policy (推奨), token_slot

AWS_DOWNSCOPING.md

Google Cloud

gcloud

credential_access_boundary (GCS), oauth_scope, token_slot

GCP_DOWNSCOPING.md

Kubernetes

kubectl

token_slot; EKS/GKE dynamic (将来)

KUBECTL_DOWNSCOPING.md

MCPサーバー

プロキシ

token_slot

GITHUB_DOWNSCOPING.md

追加のサービスは config.yaml を拡張することで追加可能です。コードの変更は不要です。


セキュリティ上の注意

  • トークン値は、細工されたトークン値によるコマンドインジェクションを防ぐため、シェル注入前に shlex.quote でエスケープされます。

  • コマンドの前に TOKEN=value を付加すると、プロセスリスト (ps aux) でトークンが可視化されます。より高いセキュリティ環境では、ファイル記述子やシークレットマネージャーを介してトークンを注入する認証情報ヘルパーを使用してください。

  • ブロックメッセージには一致したルール名とパターンが含まれるため、理由は常に監査可能です。

  • 環境の inject_as トークンへのフォールバックは、スコープされたトークンをまだプロビジョニングしていない場合、コマンドが環境認証情報を使用して通過することを意味します。これを強化するには DOWNSCOPE_REQUIRE_SCOPED=1 (将来実装) を設定してください。

  • ローカルパスを含む .claude/settings.json は gitignore に含めるべきです。このリポジトリの .gitignore を参照してください。


開発

pip install -e .
pytest tests/

ライセンス

MIT

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Policy-enforcing MCP proxy that blocks dangerous tool calls before they execute. Protects credentials, filesystem, shell, and databases across Claude Desktop, Cursor, Windsurf, and OpenClaw.
    6 npm
    39
    Apache 2.0
  • A
    license
    C
    quality
    D
    maintenance
    Enables secure, zero-trust access to MCP tools through short-lived, signed capability leases that bind tool execution to specific sessions, intents, and constraints. Prevents prompt injection attacks and privilege escalation with dynamic risk scoring, policy enforcement, and tamper-evident audit logging.
    4
    1
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Security gateway for MCP tool calls. Sits between your LLM client and MCP servers, enforcing per-tool policies (allow/block/approve/read-only), logging every call, and pausing dangerous operations for human approval in terminal or Slack.
    0
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Runtime proxy that intercepts and blocks MCP tool calls based on YAML-defined policies, enforcing security rules for AI agents like Claude Code or Cursor.
    44 npm
    1
    Apache 2.0