Управление и учет

Виртуальные ключи

Виртуальные ключи (Virtual Keys) — основная сущность governance в Meridian. Они дают пользователям и приложениям ограниченный доступ к моделям и провайдерам, а также бюджеты и rate limits.

Обзор

Виртуальные ключи — это основная сущность governance в Meridian. Пользователи и приложения аутентифицируются через специальные заголовки и получают через виртуальный ключ конкретные права доступа, бюджеты и rate limits.

Поддерживаемые заголовки:

  • x-bf-vk — заголовок виртуального ключа, например sk-bf-*;
  • Authorization — заголовок авторизации, например Bearer sk-bf-* (стиль OpenAI);
  • x-api-key — заголовок API-ключа, например sk-bf-* (стиль Anthropic);
  • x-goog-api-key — заголовок API-ключа, например sk-bf-* (стиль Google Gemini).

Старые виртуальные ключи (без префикса sk-bf-*) поддерживаются только заголовком x-bf-vk.

Через Authorization, x-api-key и x-goog-api-key можно также передавать прямые ключи провайдера. Подробнее — на странице Управление ключами провайдеров, раздел Direct Key Bypass.

Ключевые возможности:

  • Контроль доступа — фильтрация по моделям и провайдерам;
  • Управление расходами — независимые бюджеты (учитываются вместе с бюджетами команды или клиента, если они привязаны);
  • Rate limits — ограничения по токенам и количеству запросов (только на уровне VK);
  • Ограничение по ключам — VK можно ограничить конкретными API-ключами провайдера (тогда VK сможет использовать только их);
  • Эксклюзивная привязка — VK принадлежит либо одной команде, либо одному клиенту, либо ничему (взаимоисключающе);
  • Активный/неактивный статус — мгновенное включение и отключение доступа.

Конфигурация

  1. Перейдите в раздел Virtual Keys.
  2. Нажмите кнопку Add Virtual Key.
Создание виртуального ключа

Настройки бюджета:

  • Max Limit — лимит в долларах (например, 10.50);
  • Reset Duration1m, 1h, 1d, 1w, 1M, 1Y;
  • Calendar aligned (опционально) — при включении бюджет сбрасывается по календарным границам в UTC (день/неделя/месяц/год), а не по скользящему окну. Применяется только к периодам день/неделя/месяц/год. См. Бюджеты и лимиты, раздел Calendar aligned budgets.

Rate limits:

  • Token Limit — максимум токенов за период;
  • Request Limit — максимум запросов за период;
  • Reset Duration — частота сброса для каждого лимита.

Привязки:

  • Team — привязать к существующей команде (взаимоисключающе с клиентом);
  • Customer — привязать к существующему клиенту (взаимоисключающе с командой).
  1. Нажмите Create Virtual Key.

Создание виртуального ключа (привязан к команде):

curl -X POST http://localhost:8080/api/governance/virtual-keys \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Engineering Team API",
    "description": "Main API key for engineering team",
    "provider_configs": [
      {
        "provider": "openai",
        "weight": 0.5,
        "allowed_models": ["gpt-4o-mini"]
      },
      {
        "provider": "anthropic",
        "weight": 0.5,
        "allowed_models": ["claude-3-sonnet-20240229"]
      }
    ],
    "team_id": "team-eng-001",
    "budget": {
      "max_limit": 100.00,
      "reset_duration": "1M"
    },
    "rate_limit": {
      "token_max_limit": 10000,
      "token_reset_duration": "1h",
      "request_max_limit": 100,
      "request_reset_duration": "1m"
    },
    "key_ids": ["8c52039e-38c6-48b2-8016-0bd884b7befb"],
    "is_active": true
  }'

Создание виртуального ключа (привязан напрямую к клиенту):

curl -X POST http://localhost:8080/api/governance/virtual-keys \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Executive API Key",
    "description": "Direct customer-level API access",
    "provider_configs": [
      {
        "provider": "openai",
        "weight": 0.5,
        "allowed_models": ["gpt-4o"]
      },
      {
        "provider": "anthropic",
        "weight": 0.5,
        "allowed_models": ["claude-3-opus-20240229"]
      }
    ],
    "customer_id": "customer-acme-corp",
    "budget": {
      "max_limit": 500.00,
      "reset_duration": "1M"
    },
    "is_active": true
  }'
  • team_id и customer_id взаимоисключающи — VK может принадлежать либо одной команде, либо одному клиенту, но не обоим одновременно.
  • key_ids ограничивает VK конкретными API-ключами провайдера. Передайте ["*"], чтобы разрешить доступ ко всем доступным ключам. Пустой массив [] или отсутствующее поле полностью запрещают доступ к ключам.

Обновление виртуального ключа:

curl -X PUT http://localhost:8080/api/governance/virtual-keys/{vk_id} \
  -H "Content-Type: application/json" \
  -d '{
    "description": "Updated description",
    "budget": {
      "max_limit": 150.00,
      "reset_duration": "1M"
    }
  }'

Получение виртуальных ключей:

# Список всех виртуальных ключей
curl http://localhost:8080/api/governance/virtual-keys

# Получить конкретный виртуальный ключ
curl http://localhost:8080/api/governance/virtual-keys/{vk_id}

Удаление виртуального ключа:

curl -X DELETE http://localhost:8080/api/governance/virtual-keys/{vk_id}
{
  "client": {
    "enforce_auth_on_inference": true
  },
  "governance": {
    "virtual_keys": [
      {
        "id": "vk-001",
        "name": "Engineering Team API",
        "value": "vk-engineering-main",
        "description": "Main API key for engineering team",
        "is_active": true,
        "provider_configs": [
          {
            "provider": "openai",
            "weight": 0.5,
            "allowed_models": ["gpt-4o-mini"]
          },
          {
            "provider": "anthropic",
            "weight": 0.5,
            "allowed_models": ["claude-3-sonnet-20240229"]
          }
        ],
        "team_id": "team-eng-001",
        "budget_id": "budget-eng-vk",
        "rate_limit_id": "rate-limit-eng-vk",
        "keys": [
          {"key_id": "8c52039e-38c6-48b2-8016-0bd884b7befb"}
        ]
      },
      {
        "id": "vk-002",
        "name": "Executive API Key",
        "value": "vk-executive-direct",
        "description": "Direct customer-level API access",
        "is_active": true,
        "provider_configs": [
          {
            "provider": "openai",
            "weight": 0.5,
            "allowed_models": ["gpt-4o"]
          },
          {
            "provider": "anthropic",
            "weight": 0.5,
            "allowed_models": ["claude-3-opus-20240229"]
          }
        ],
        "customer_id": "customer-acme-corp",
        "budget_id": "budget-exec-vk",
        "keys": [
          {"key_id": "8c52039e-38c6-48b2-8016-0bd884b7befb"}
        ]
      }
    ],
    "budgets": [
      {
        "id": "budget-eng-vk",
        "max_limit": 100.00,
        "reset_duration": "1M",
        "current_usage": 0.0,
        "last_reset": "2025-01-01T00:00:00Z"
      },
      {
        "id": "budget-exec-vk",
        "max_limit": 500.00,
        "reset_duration": "1M",
        "current_usage": 0.0,
        "last_reset": "2025-01-01T00:00:00Z"
      }
    ],
    "rate_limits": [
      {
        "id": "rate-limit-eng-vk",
        "token_max_limit": 10000,
        "token_reset_duration": "1h",
        "token_current_usage": 0,
        "token_last_reset": "2025-01-01T00:00:00Z",
        "request_max_limit": 100,
        "request_reset_duration": "1m",
        "request_current_usage": 0,
        "request_last_reset": "2025-01-01T00:00:00Z"
      }
    ]
  }
}

Группы пользователей

Команды

Команды (Teams) дают организационную группировку для виртуальных ключей и управление бюджетом на уровне отдела. Команда может принадлежать одному клиенту и иметь собственный независимый бюджет.

Ключевые возможности:

  • Организационная структура — группировка нескольких виртуальных ключей;
  • Независимые бюджеты — управление расходами на уровне отдела (отдельно от бюджета клиента);
  • Привязка к клиенту — может принадлежать одному клиенту (опционально);
  • Без rate limits — у команды не может быть rate limits (только на уровне VK).

Конфигурация

  1. Перейдите в Users & Groups → Teams.

  2. Нажмите кнопку Add Team.

Создание команды

Заполните форму и нажмите Create Team.

  1. Привяжите виртуальные ключи к команде:
    • Откройте страницу Virtual Keys;
    • отредактируйте виртуальный ключ и привяжите его к команде;
    • нажмите Save.

Создание команды:

curl -X POST http://localhost:8080/api/governance/teams \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Engineering Team",
    "customer_id": "customer-acme-corp",
    "budget": {
      "max_limit": 500.00,
      "reset_duration": "1M"
    }
  }'

Обновление команды:

curl -X PUT http://localhost:8080/api/governance/teams/{team_id} \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Updated Engineering Team",
    "budget": {
      "max_limit": 750.00,
      "reset_duration": "1M"
    }
  }'

Получение команд:

# Список всех команд
curl http://localhost:8080/api/governance/teams

# Получить конкретную команду
curl http://localhost:8080/api/governance/teams/{team_id}

Удаление команды:

curl -X DELETE http://localhost:8080/api/governance/teams/{team_id}
{
  "governance": {
    "teams": [
      {
        "id": "team-eng-001",
        "name": "Engineering Team",
        "customer_id": "customer-acme-corp",
        "budget_id": "budget-team-eng"
      },
      {
        "id": "team-sales-001",
        "name": "Sales Team",
        "customer_id": "customer-acme-corp",
        "budget_id": "budget-team-sales"
      }
    ],
    "budgets": [
      {
        "id": "budget-team-eng",
        "max_limit": 500.00,
        "reset_duration": "1M",
        "current_usage": 0.0,
        "last_reset": "2025-01-01T00:00:00Z"
      },
      {
        "id": "budget-team-sales",
        "max_limit": 250.00,
        "reset_duration": "1M",
        "current_usage": 0.0,
        "last_reset": "2025-01-01T00:00:00Z"
      }
    ]
  }
}

Клиенты

Клиенты (Customers) — это верхний уровень иерархии governance, обычно соответствующий организации или крупному бизнес-подразделению. Они дают контроль бюджета верхнего уровня и общую организационную структуру.

Ключевые возможности:

  • Верхний уровень иерархии — самый высокий уровень группировки;
  • Независимые бюджеты — управление расходами на уровне организации (отдельно от бюджетов команды и VK);
  • Управление командами — содержит несколько команд и прямые VK;
  • Без rate limits — у клиента не может быть rate limits (только на уровне VK).

Конфигурация

  1. Перейдите в Users & Groups → Customers.

  2. Нажмите кнопку Add Customer.

Создание клиента

Заполните форму и нажмите Create Customer.

  1. Привяжите команды к клиенту:

    • Откройте страницу Teams;
    • отредактируйте команду и привяжите её к клиенту;
    • нажмите Save.
  2. Привяжите виртуальные ключи к клиенту:

    • Откройте страницу Virtual Keys;
    • отредактируйте виртуальный ключ и привяжите его к клиенту;
    • нажмите Save.

Создание клиента:

curl -X POST http://localhost:8080/api/governance/customers \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corporation",
    "budget": {
      "max_limit": 2000.00,
      "reset_duration": "1M"
    }
  }'

Обновление клиента:

curl -X PUT http://localhost:8080/api/governance/customers/{customer_id} \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Acme Corp (Updated)",
    "budget": {
      "max_limit": 2500.00,
      "reset_duration": "1M"
    }
  }'

Получение клиентов:

# Список всех клиентов
curl http://localhost:8080/api/governance/customers

# Получить конкретного клиента
curl http://localhost:8080/api/governance/customers/{customer_id}

Удаление клиента:

curl -X DELETE http://localhost:8080/api/governance/customers/{customer_id}
{
  "governance": {
    "customers": [
      {
        "id": "customer-acme-corp",
        "name": "Acme Corporation",
        "budget_id": "budget-customer-acme"
      },
      {
        "id": "customer-beta-inc",
        "name": "Beta Inc",
        "budget_id": "budget-customer-beta"
      }
    ],
    "budgets": [
      {
        "id": "budget-customer-acme",
        "max_limit": 2000.00,
        "reset_duration": "1M",
        "current_usage": 0.0,
        "last_reset": "2025-01-01T00:00:00Z"
      },
      {
        "id": "budget-customer-beta",
        "max_limit": 1500.00,
        "reset_duration": "1M",
        "current_usage": 0.0,
        "last_reset": "2025-01-01T00:00:00Z"
      }
    ]
  }
}

Связанные возможности

  • Бюджеты и лимиты — enterprise-уровень управления бюджетами, контроля расходов и rate limits через виртуальные ключи.
  • Маршрутизация — направление запросов к нужным провайдерам/моделям и ограничение API-ключей через виртуальные ключи.
  • Фильтрация MCP-инструментов — управление MCP-клиентами и инструментами для виртуальных ключей.

Использование

Сделать виртуальные ключи обязательными

Все запросы с включённым governance должны передавать заголовок виртуального ключа:

curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Content-Type: application/json" \
  -H "x-bf-vk: vk-engineering-main" \
  -d '{
    "model": "gpt-4o-mini",
    "messages": [{"role": "user", "content": "Hello!"}]
  }'

По умолчанию governance необязателен: если заголовок виртуального ключа отсутствует, запрос всё равно проходит — но без проверок и маршрутизации governance. Это поведение можно сделать строгим, потребовав обязательного заголовка виртуального ключа.

  1. Перейдите в Config → Security.

  2. Включите чекбокс Enforce Virtual Keys.

Принудительное использование виртуальных ключей
curl -X PUT http://localhost:8080/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "client_config": {
      "enforce_auth_on_inference": true
    }
  }'
{
  "client": {
    "enforce_auth_on_inference": true
  }
}

При включённом обязательном использовании заголовка governance запрос отклоняется, если x-bf-vk не передан.

Аутентификация и виртуальные ключи

Виртуальные ключи и HTTP-аутентификация — это независимые слои, которые могут работать совместно:

СлойНазначениеЗаголовки
АутентификацияПроверка личности пользователяAuthorization: Basic/Bearer <credentials>
Виртуальные ключиМаршрутизация и governance запросаx-bf-vk, Authorization1, x-api-key, x-goog-api-key

Когда disable_auth_on_inference: true (аутентификация отключена):

Виртуальные ключи можно передавать через любой поддерживаемый заголовок без дополнительной аутентификации:

# Через заголовок x-bf-vk
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "x-bf-vk: <VIRTUAL_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4o-mini", "messages": [...]}'

# Через заголовок Authorization (стиль OpenAI)
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer <VIRTUAL_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4o-mini", "messages": [...]}'

Когда disable_auth_on_inference: false (аутентификация включена):

Нужно передать и учётные данные аутентификации, и виртуальный ключ. Виртуальный ключ — в x-bf-vk, потому что Authorization уже занят аутентификацией:

curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Authorization: Basic <base64-credentials>" \
  -H "x-bf-vk: <VIRTUAL_KEY>" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4o-mini", "messages": [...]}'

Настройка disable_auth_on_inference:

  1. Перейдите в Config → Security.
  2. Переключите Disable Auth on Inference, чтобы включить или отключить.
Disable Auth on Inference
curl -X PUT http://localhost:8080/api/config \
  -H "Content-Type: application/json" \
  -d '{
    "auth_config": {
      "disable_auth_on_inference": true
    }
  }'
{
  "auth_config": {
    "is_enabled": true,
    "disable_auth_on_inference": true
  }
}

Ошибки

  • Виртуальный ключ не найден (400):
{
  "error": {
    "type": "virtual_key_required",
    "message": "virtual key is missing in headers"
  }
}
  • Виртуальный ключ заблокирован (403):
{
  "error": {
    "type": "virtual_key_blocked",
    "message": "Virtual key is inactive"
  }
}
  • Превышен rate limit (429):
{
  "error": {
    "type": "rate_limited",
    "message": "Rate limits exceeded: [token limit exceeded (1500/1000, resets every 1h)]"
  }
}
  • Превышен лимит токенов (429):
{
  "error": {
    "type": "token_limited",
    "message": "Rate limits exceeded: [token limit exceeded (1500/1000, resets every 1h)]"
  }
}
  • Превышен лимит запросов (429):
{
  "error": {
    "type": "request_limited",
    "message": "Rate limits exceeded: [request limit exceeded (101/100, resets every 1m)]"
  }
}
  • Превышен бюджет (402):
{
  "error": {
    "type": "budget_exceeded",
    "message": "Budget exceeded: VK budget exceeded: 105.50 > 100.00 dollars"
  }
}
  • Модель не разрешена (403):
{
  "error": {
    "type": "model_blocked",
    "message": "Model 'gpt-4o' is not allowed for this virtual key"
  }
}
  • Провайдер не разрешён (403):
{
  "error": {
    "type": "provider_blocked",
    "message": "Provider 'anthropic' is not allowed for this virtual key"
  }
}

Footnotes

  1. Authorization может нести виртуальный ключ только при отключённой аутентификации (disable_auth_on_inference: true). Когда аутентификация включена, заголовок Authorization потребляется ею и не может использоваться для виртуальных ключей.

Содержание