Skip to main content
Glama
kbroughton
by kbroughton

downscoping-mcp

Понижение привилегий учетных данных пользователя до настраиваемого подмножества для использования инструментами ИИ. Пользователю уже должен быть предоставлен набор разрешений для повседневной работы, который соответствует службам в определенных проектах GCP или учетных записях AWS. Понижение привилегий (downscoping) относится к дальнейшему ограничению действий в соответствии с корпоративными стандартами.

Предоставление разрешений обычно выглядит как <Action allowed> on <Resource>. Понижение привилегий влияет на <Action allowed>, уменьшая возможности, например, с чтения/записи до «только чтение».

Примеры

  • Разрешить чтение, но не запись документов Google Drive

  • Разрешить чтение PR в GitHub, но не слияние или утверждение

  • Разрешить чтение логов, но не развертывание в проекте GCP


Проблема

Claude Code работает с любыми учетными данными, присутствующими в вашей среде. Модель, которая может читать файлы, также может вызвать gh repo delete, gcloud projects delete или aws iam delete-user — используя тот же токен. Одного джейлбрейка, промпт-инъекции или атаки типа «confused-deputy» достаточно, чтобы нанести ущерб. То же самое касается случайных ошибок — если Claude выполнит push напрямую в релизную ветку, это может запустить конвейер развертывания, если защита веток или GitHub Actions настроены неправильно.

Related MCP server: MCP Airlock

Почему такой подход?

Очевидная альтернатива — создание выделенных IAM-ролей или сервисных аккаунтов с низкими привилегиями для использования ИИ — по одному на команду, на среду. Это быстро упирается в жесткие лимиты.

Типичный ~/.aws/config уже содержит более 60 профилей, охватывающих разные учетные записи и роли. Удвоение этого количества за счет специфичных для ИИ аналогов с пониженными привилегиями означает 120+ профилей, постоянное обслуживание IaC и настройку для каждого инженера в .claude/settings.local.json для подключения нужного профиля. В AWS установлена квота по умолчанию в 1000 IAM-ролей на учетную запись (для более высоких лимитов требуется запрос на увеличение квоты), и каждая новая роль — это еще один объект для аудита, ротации и синхронизации с исходной.

Этот инструмент использует другой подход: динамическое понижение привилегий во время вызова, без затрагивания IAM. Это работает аналогично aws sts assume-role --policy-arns, что ограничивает эффективные разрешения принятой роли пересечением политик роли и предоставленных ARN политик. Здесь пересечение определяется в YAML-файле, зафиксированном в вашем проекте, а не в документе политики IAM, но семантика та же. Используются ваши существующие учетные данные; их эффективные возможности сужаются для каждой операции в соответствии с правилами, которые вы определяете.

Сохраняется одно важное свойство: этот инструмент может только уменьшать привилегии, но никогда не увеличивать их. Он устанавливает защитные барьеры, чтобы использование инструментов ИИ было безопасным и соответствовало корпоративной политике, без необходимости внесения каких-либо изменений в вашу настройку IAM.


Как это работает

Правила оцениваются сверху вниз для каждой команды. Первое совпадение побеждает. Возможны три исхода:

Действие

Поведение

allow

Внедрить токен с ограниченными правами для соответствующего слота; команда выполняется

review

Заблокировать команду; попросить Claude предложить пользователю выполнить ее вручную

deny

Заблокировать команду; сообщить Claude, что она не разрешена для использования ИИ

Сообщения о блокировке включают имя правила и совпавший шаблон, поэтому причина всегда ясна.

Уровень 1 — Динамическое понижение привилегий (предпочтительно)

Нативный облачный STS получает ограниченный токен из ваших текущих учетных данных во время вызова. Не требуются новые IAM-роли или предварительно подготовленные токены.

  • AWS: sts:GetFederationToken или sts:AssumeRole с встроенной политикой. Эффективные разрешения = пересечение ваших политик идентификации и встроенной политики. См. docs/AWS_DOWNSCOPING.md.

  • GCP: Credential Access Boundary через sts.googleapis.com. Ограничивает текущий токен конкретными ресурсами и ролями. Поддерживается только для Cloud Storage. Для других служб GCP используется откат к ограничению областей OAuth. См. docs/GCP_DOWNSCOPING.md.

Уровень 2 — Слоты токенов (откат)

Используется, когда динамический API отсутствует. Предварительно подготовленные токены с узкими правами выбираются для каждой операции на основе правил YAML.

  • GitHub: Детализированные PAT (динамический API понижения привилегий отсутствует). См. docs/GITHUB_DOWNSCOPING.md.

  • Службы GCP, отличные от GCS: Ограничение области OAuth через generateAccessToken. Только гранулярность на уровне API.

  • kubectl: Токены Kubernetes ServiceAccount, привязанные к минимальным ролям RBAC. Кластеры EKS и GKE могут использовать динамическое понижение привилегий облачного провайдера — см. docs/KUBECTL_DOWNSCOPING.md.

Два режима принудительного применения

Режим 1 — Bash-хук (инструменты CLI)

Хук PreToolUse перехватывает каждый вызов инструмента Bash. Если команда начинается с известного бинарного файла службы (gh, gcloud, aws, kubectl), хук сопоставляет аргументы с вашими правилами 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 динамический (будущее)

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