Документация Делегированные учётные данные для совместной работы

Делегированные учётные данные

Делегированные учётные данные (delegated credential) — это токен доступа,
который передаёт кому-то ограниченную часть ваших прав, и который этот
получатель не может расширить.

Используйте их, когда работа совместная: подрядчик прогоняет тесты в одном
проекте, CI-задача не должна иметь доступ к stage, MCP-клиент подключается от
имени ассистента, интеграция с партнёром, которой вы доверяете не полностью. Для
этого плохо подходит API-токен, потому что его владелец может изменить его права.
Делегированные учётные данные после выпуска изменить нельзя — ни их получателю,
ни вам. Вместо изменения выпустите новые.

Эндпоинты живут на admin-узле, под POST /api/v1/auth/delegated-credentials.
Токен несёт префикс mkd_ — именно по нему все части Mockarty отличают
делегированные учётные данные от API-токена (mk_) или токена интеграции
(mki_) ещё до обращения к базе.

Чем отличаются от API-токена

API-токен Делегированные учётные данные
Namespace значение по умолчанию, которое владелец может изменить набор, зафиксированный при выпуске; получатель не может его дополнить
Действия список, который владелец может править зафиксированы при выпуске
Срок действия необязателен обязателен и не более 365 дней вперёд
Кто может изменить область его владелец никто — эндпоинта, записывающего область, не существует
Чем управляет токенами своего владельца только теми делегированными учётными данными, которые выпустил сам
Префикс токена mk_ mkd_

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

Зафиксированная область

Три свойства фиксируются при выпуске:

Свойство Что означает Что может сделать получатель
Namespace namespace, в которых учётные данные могут работать ничего. Запрос с namespace вне набора отклоняется, а не перенаправляется молча
Действия read, write, delete ничего. Список действий подставляется из самих учётных данных при каждом запросе
Срок действия момент, когда они перестают работать ничего. Он обязателен и не более 365 дней вперёд

Namespace, названный в заголовке, в параметре запроса или в теле JSON, не может
сдвинуть границу. Namespace, в котором может работать запрос, берётся из самих
учётных данных; то, что вы отправили, может только выбрать один из
зафиксированных namespace, но не добавить новый.

Выпуск

Тот, кто выпускает, — это тот, кто прошёл аутентификацию: человек, вошедший в
кабинет, или сервис с API-токеном. Вы можете выпустить учётные данные только с
областью внутри собственного доступа, а если вызывающий — сам делегированные
учётные данные, то только внутри их зафиксированной области. Поэтому цепочка
делегирований может только сужаться.

CLI

mockarty-cli delegated-credential create \
  --name ci-reader \
  --description "nightly regression job" \
  --namespaces staging \
  --actions read \
  --expires 30d

--namespaces стоит во множественном числе, потому что это набор, к которому
привязаны учётные данные. Глобальный флаг --namespace — про другое: это
namespace, в котором работает ваша сессия CLI.

cURL

curl -X POST http://localhost:5770/api/v1/auth/delegated-credentials \
  -H "Authorization: Bearer mk_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ci-reader",
    "description": "nightly regression job",
    "namespaces": ["staging"],
    "allowed_actions": ["read"],
    "expires_at": "2026-12-31T00:00:00Z"
  }'

Go

expires := time.Now().UTC().Add(30 * 24 * time.Hour)
issued, err := client.DelegatedCredentials().Create(ctx, mockarty.DelegatedCredentialCreateRequest{
    Name:           "ci-reader",
    Description:    "nightly regression job",
    Namespaces:     []string{"staging"},
    AllowedActions: []string{"read"},
    ExpiresAt:      &expires,
})
fmt.Println(issued.Token) // выводится один раз

Python

from datetime import datetime, timedelta, timezone
from mockarty import DelegatedCredentialCreateRequest

issued = client.delegated_credentials.create(DelegatedCredentialCreateRequest(
    name="ci-reader",
    description="nightly regression job",
    namespaces=["staging"],
    allowed_actions=["read"],
    expires_at=datetime.now(timezone.utc) + timedelta(days=30),
))
print(issued.token)  # выводится один раз

Java

DelegatedCredentialWithToken issued = client.delegatedCredentials().create(
    DelegatedCredentialCreateRequest.builder()
        .name("ci-reader")
        .description("nightly regression job")
        .namespaces(List.of("staging"))
        .allowedActions(List.of("read"))
        .expiresAt(Instant.now().plus(Duration.ofDays(30)))
        .build());
System.out.println(issued.getToken()); // выводится один раз

В ответе токен приходит один раз. Он не хранится и не может быть прочитан
повторно — сохраняется только его верификатор. Поэтому сохраните его там, откуда
интеграция сможет его взять. Если потеряли — смените токен (rotate), а не
выпускайте новые учётные данные: так история аудита останется на одной сущности.

Не указывайте allowed_actions — тогда будут разрешены все действия (read,
write, delete). Набор namespace и срок действия всё равно обязательны: без них
это был бы API-токен, то есть ровно то, что эти учётные данные заменяют.

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

Получатель предъявляет их так же, как предъявлял бы API-токен:

MOCKARTY_API_KEY=mkd_... mockarty-cli mock list
client := mockarty.NewClient("http://localhost:5770",
    mockarty.WithAPIKey("mkd_..."))

Для интеграции с проектом положите токен в секреты этого проекта и читайте его в
ту же переменную, в которую попал бы API-токен: изменений на стороне клиента не
нужно, область применения применяет сервер.

Попытка выйти за пределы зафиксированной области отклоняется с 403, причём в
ответе называется учётная запись, а не вызывающий, чтобы оператор мог отличить
отказ по области от отказа по правам.

Смена токена (rotate)

Смена выпускает новый токен и оставляет область ровно такой, какой она была.
Прежний токен перестаёт работать сразу. Это нужно, когда токен утёк, а работа
должна продолжаться:

CLI

mockarty-cli delegated-credential rotate 5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51

cURL

curl -X POST http://localhost:5770/api/v1/auth/delegated-credentials/5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51/rotate \
  -H "Authorization: Bearer mk_YOUR_TOKEN"

Go

rotated, err := client.DelegatedCredentials().Rotate(ctx, "5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51")
fmt.Println(rotated.Token)

Python

rotated = client.delegated_credentials.rotate("5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51")
print(rotated.token)

Java

DelegatedCredentialWithToken rotated =
    client.delegatedCredentials().rotate("5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51");
System.out.println(rotated.getToken());

Смена токена — это не изменение области. Если работе теперь нужен другой
namespace, другое действие или более поздний срок, выпустите новые учётные
данные: тогда изменение получит собственную сущность в истории аудита, а не
окажется незаметной правкой тех учётных данных, которые уже у кого-то на руках.

Отзыв

Отзыв необратим и действует на всех узлах кластера, а не только на том, который
ответил на запрос. Отмены отзыва намеренно нет — «временно отозванные» это ровно
то окно, которого у общих учётных данных быть не должно. Повторный отзыв — не
ошибка, а отсутствие изменений.

CLI

mockarty-cli delegated-credential revoke 5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51

cURL

curl -X DELETE http://localhost:5770/api/v1/auth/delegated-credentials/5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51 \
  -H "Authorization: Bearer mk_YOUR_TOKEN"

Go

err := client.DelegatedCredentials().Revoke(ctx, "5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51")

Python

client.delegated_credentials.revoke("5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51")

Java

client.delegatedCredentials().revoke("5f3c9d10-2b7a-4c8e-9d1f-8a6b0c2e4d51");

Список

Тот, кто выпустил, видит все выпущенные им учётные данные, новые сверху. Сами
делегированные учётные данные видят только то, что выпустили сами — не
учётные данные своего издателя и не соседние.

CLI

mockarty-cli delegated-credential list

cURL

curl http://localhost:5770/api/v1/auth/delegated-credentials \
  -H "Authorization: Bearer mk_YOUR_TOKEN"

Go

page, err := client.DelegatedCredentials().List(ctx)
for _, cred := range page.Credentials {
    fmt.Println(cred.ID, cred.Name, cred.Namespaces, cred.ExpiresAt)
}

Python

for cred in client.delegated_credentials.list().credentials:
    print(cred.id, cred.name, cred.namespaces, cred.expires_at)

Java

for (DelegatedCredential cred : client.delegatedCredentials().list().getCredentials()) {
    System.out.println(cred.getId() + " " + cred.getNamespaces());
}

Чего делегированные учётные данные намеренно не могут

  • Их нельзя расширить. Ни один эндпоинт не записывает namespace, действия или
    срок действия. Смена токена заменяет только токен.
  • Они не могут управлять API-токенами владельца. Создание, чтение,
    редактирование и отзыв API-токенов отклоняются: там они действуют как свой
    издатель и иначе могли бы выпустить себе токен без ограничений.
  • Они не могут отозвать или сменить своего издателя. Они управляют только
    теми учётными данными, которые выпустили сами, поэтому не могут уничтожить или
    заменить те, от которых зависят.
  • Они не могут отозвать или сменить соседние учётные данные, выпущенные рядом.
  • Они не могут жить дольше года. Срок действия более чем на 365 дней вперёд
    отклоняется.
  • Отзыв нельзя отменить.
  • Их нельзя выбрать заголовком. Namespace в заголовке, параметре запроса или
    теле может только выбрать один из зафиксированных namespace.
  • Они не работают по gRPC. Поверхность gRPC аутентифицирует только
    API-токены, поэтому делегированный токен там отклоняется — это граница, на
    которую эти учётные данные не распространяются.
  • Их нельзя выпустить из сессии MCP. Выпуск учётных данных — действие
    оператора, за которым стоит человек, поэтому эти пять эндпоинтов не входят в
    каталог инструментов, который просматривает ассистент: инструмент, выпускающий
    учётные данные, передаёт вызывающему выбор области. Используйте кабинет, CLI или
    SDK.
  • У них нет собственного ограничения частоты запросов. Делегированные учётные
    данные не считаются по отдельному бюджету запросов на токен; действуют
    ограничения аккаунта издателя. Если интеграции нужен лимит, поставьте его на
    входе.

Полезно знать ещё вот что:

  • Учётные данные, издатель которых отключён, перестают работать раньше срока.
    Издатель должен оставаться активным пользователем, иначе учётные данные не
    принимаются.
  • Отзыв рассылается на все узлы кластера. Узел, не получивший рассылку, перестаёт
    принимать учётные данные примерно в течение минуты: сначала отзывайте, а
    кратковременное пересечение считайте ожидаемым, а не неудачей отзыва.
  • Сам токен никогда не попадает в аудит или журнал. В записи аудита есть только
    отображаемая метка — первые символы токена, которых достаточно, чтобы сопоставить
    строку в списке с сообщением об утечке.

Эндпоинты

Метод Путь Описание
POST /api/v1/auth/delegated-credentials Выпустить учётные данные; токен возвращается один раз
GET /api/v1/auth/delegated-credentials Список учётных данных, доступных вызывающему
GET /api/v1/auth/delegated-credentials/:id Прочитать одни учётные данные
POST /api/v1/auth/delegated-credentials/:id/rotate Заменить токен, сохранив область
DELETE /api/v1/auth/delegated-credentials/:id Отозвать навсегда

Учётные данные вне полномочий вызывающего отвечают 404, а не 403 — иначе
делегированные учётные данные могли бы перебирать учётные данные своего издателя
по одному идентификатору.

Выпуск, смена токена и отзыв записываются в аудит с идентификатором самих учётных
данных, поэтому разбор инцидента может вытащить всю историю одних учётных данных
одним фильтром.

Где ими управлять в кабинете

Откройте API-токены в кабинете. Владелец namespace увидит там панель
Делегированные учётные данные со списком выпущенного, с зафиксированной
областью, состоянием и последним использованием, а также действия выпуска, смены
токена и отзыва.

См. также