Skip to main content
Glama
kbroughton
by kbroughton

downscoping-mcp

将用户凭证权限降级为可配置的子集,供 AI 工具使用。用户在日常工作中通常已经拥有了一组映射到特定 GCP 项目或 AWS 账户服务的权限。降级(Downscoping)是指进一步限制操作以符合公司标准。

权限授予通常是 <Action allowed> on <Resource>。降级通过减少能力来影响 <Action allowed>,例如从读/写变为只读。

示例

  • 允许读取但禁止写入 Google Drive 文档

  • 允许读取 GitHub PR 但禁止合并或批准

  • 允许读取日志但禁止部署到 GCP 项目


问题

Claude Code 使用环境中存在的任何凭证运行。一个可以读取文件的模型也可以使用相同的令牌调用 gh repo deletegcloud projects deleteaws iam delete-user。一次越狱、提示词注入或混淆代理攻击就足以造成损害。意外错误也是如此——如果分支保护或 GitHub Actions 配置不当,Claude 直接推送到发布分支可能会触发部署流水线。

Related MCP server: MCP Airlock

为什么选择这种方法?

显而易见的替代方案是为 AI 使用创建专用的低权限 IAM 角色或服务账户——每个团队、每个环境一个。这很快就会遇到硬性限制。

典型的 ~/.aws/config 已经有 60 多个配置文件,涵盖了不同的账户和角色。如果为 AI 专门创建降级副本,意味着会有 120 多个配置文件、持续的 IaC 维护工作,并且需要在 .claude/settings.local.json 中为每个工程师进行配置以连接正确的配置文件。AWS 每个账户的默认 IAM 角色配额为 1,000 个(更高的限制需要申请增加配额),并且每个新角色都需要审计、轮换并与原始角色保持同步。

该工具采用了不同的方法:在调用时动态降级,无需触及 IAM。它的工作原理类似于 aws sts assume-role --policy-arns,后者将所承担角色的有效权限限制为角色策略与所提供策略 ARN 的交集。在这里,交集是在签入项目的 YAML 文件中定义的,而不是在 IAM 策略文档中——但语义是相同的。使用您现有的凭证;它们的有效能力会根据您定义的规则按操作进行缩减。

保留了一个重要属性:此工具只能降低权限,绝不能增加权限。 它设置了护栏,以确保 AI 工具的使用安全并符合公司政策,而无需更改您的 IAM 设置。


工作原理

规则会针对每个命令从上到下进行评估。第一个匹配项生效。有三种可能的结果:

操作

行为

allow

为匹配的槽位注入降级令牌;命令继续执行

review

阻止命令;告知 Claude 要求用户手动运行

deny

阻止命令;告知 Claude 该操作不允许 AI 使用

阻止消息包含规则名称和匹配的模式,因此原因始终是明确的。

第一层 — 动态降级(首选)

原生云 STS 在调用时从您的环境凭证中派生受限令牌。无需新的 IAM 角色或预配置令牌。

  • AWS: sts:GetFederationToken 或带有内联策略的 sts:AssumeRole。有效权限 = 您的身份策略与内联策略的交集。请参阅 docs/AWS_DOWNSCOPING.md

  • GCP: 通过 sts.googleapis.com 的凭证访问边界(Credential Access Boundary)。将环境令牌限制为特定资源和角色。仅支持 Cloud Storage。 对于其他 GCP 服务,回退到 OAuth 范围限制。请参阅 docs/GCP_DOWNSCOPING.md

第二层 — 令牌槽(回退)

在没有动态 API 时使用。根据 YAML 规则为每个操作选择预配置的窄范围令牌。

  • GitHub: 细粒度 PAT(没有可用的动态降级 API)。请参阅 docs/GITHUB_DOWNSCOPING.md

  • GCP 非 GCS 服务: 通过 generateAccessToken 进行 OAuth 范围限制。仅限 API 级别粒度。

  • kubectl: 绑定到最小 RBAC 角色的 Kubernetes ServiceAccount 令牌。EKS 和 GKE 集群可以使用底层云提供商的动态降级——请参阅 docs/KUBECTL_DOWNSCOPING.md

两种执行模式

模式 1 — Bash 钩子(CLI 工具)

PreToolUse 钩子会拦截每个 Bash 工具调用。如果命令以已知的服务二进制文件(ghgcloudawskubectl)开头,钩子会将参数与您的 YAML 规则进行匹配,评估操作,并使用降级令牌重写命令或发出阻止消息。Claude 永远看不到重写过程。

模式 2 — MCP 代理

MCP 代理包装上游 MCP 服务器。在转发每个工具调用之前,它会应用相同的 YAML 规则,为该特定工具注入降级令牌。目前支持 github-pr-issue-analyser 服务器;其他服务器是未来的扩展。


快速入门

1. 安装

pip install -e .

2. 配置凭证

在您的 shell 配置文件或 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 动态 (未来)

KUBECTL_DOWNSCOPING.md

MCP 服务器

代理

token_slot

GITHUB_DOWNSCOPING.md

可以通过扩展 config.yaml 添加其他服务——无需更改代码。


安全说明

  • 令牌值在 shell 注入前会经过 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