Перейти к содержанию

Permissions Overview

1. Обзор разрешений#

В системе управления идентификацией и доступом (IAM) Permission (разрешение) — это основная сущность, определяющая право на выполнение конкретного действия над конкретным ресурсом. IAM работает по модели "запрет по умолчанию": если у пользователя или сервиса нет явно предоставленного разрешения на действие, это действие блокируется.

1.1. Структура разрешения#

Каждое разрешение представляется строкой, состоящей из трёх частей, разделённых точками:

<service_name>.<resource_name>.<action>

  • <service_name>:

    • Уникальный идентификатор сервиса или модуля в вашей системе
    • Примеры: billing, compute, auth, storage
  • <resource_name>:

    • Определяет тип объекта, над которым может быть выполнено действие
    • Выражается в единственном числе
    • Примеры: account, vm, user, policy
  • <action>:

    • Определяет операцию, которая может быть выполнена над указанным ресурсом
    • Примеры: read, write, create, delete, activate

Примеры разрешений:

  • billing.account.read — просмотр информации об аккаунте в сервисе биллинга
  • compute.vm.create — создание новой виртуальной машины в сервисе вычислений
  • auth.user.deactivate — деактивация пользователя в сервисе аутентификации

Вы также можете использовать * (wildcard) в любой из трёх частей. Это означает, что разрешены все значения в этой части.

Как работает * по частям:

  • * в первой части (service_name) — доступ к всем сервисам
  • * во второй части (resource_name) — доступ ко всем ресурсам в выбранном сервисе
  • * в третьей части (action) — доступ ко всем действиям над выбранным ресурсом

Примеры wildcard-разрешений:

  • *.vm.read — позволяет читать vm во всех сервисах
  • compute.*.read — позволяет читать любой ресурс в сервисе compute
  • compute.vm.* — позволяет выполнять любые действия над vm в сервисе compute
  • *.*.* — полный доступ ко всем сервисам, ресурсам и действиям

1.2. Модель безопасности: "Запрет по умолчанию"#

Важная философия IAM — принцип явного разрешения:

  • Изначально любой пользователь или сервисный аккаунт не имеет прав доступа
  • Для выполнения любого действия субъекту должно быть предоставлено соответствующее разрешение
  • Сервисы, интегрированные с IAM, должны проверять наличие требуемого разрешения перед выполнением операции

1.3. Примеры API разрешений#

Создание разрешения#

POST /v1/iam/permissions/
Content-Type: application/json
Authorization: Bearer <token>

{
  "name": "compute.vm.create",
  "description": "Разрешение на создание виртуальной машины"
}

Ответ#

{
  "uuid": "5a1b2c3d-4e5f-6789-abcd-ef0123456789",
  "name": "compute.vm.create",
  "description": "Разрешение на создание виртуальной машины",
  "created_at": "2025-08-21T07:38:04.778680Z",
  "updated_at": "2025-08-21T07:38:04.778688Z",
  "status": "ACTIVE"
}

Получение разрешения#

GET /v1/iam/permissions/5a1b2c3d-4e5f-6789-abcd-ef0123456789
Authorization: Bearer <token>

Фильтрация разрешений#

GET /v1/iam/permissions/?name=compute.vm.create&status=ACTIVE
Authorization: Bearer <token>

2. Роли#

Role (роль) — это именованная коллекция разрешений. Если разрешение определяет право на одно конкретное действие, то роль группирует эти права в логические блоки, соответствующие должностным функциям, обязанностям или уровню доступа пользователя или сервиса.

2.1. Привязка разрешений: связь ролей и разрешений#

Для назначения разрешений роли используется сущность Permission Binding (привязка разрешения). Эта сущность устанавливает отношение многие-ко-многим между ролями и разрешениями.

  • Одно разрешение может быть привязано к нескольким разным ролям
  • Одна роль может содержать множество разных разрешений

Пример:

  • Роль BillingViewer получает следующие разрешения через Permission Binding:
    • billing.account.read
    • billing.invoice.read
  • Роль BillingOperator получает следующие разрешения через Permission Binding:
    • billing.account.read
    • billing.invoice.read
    • billing.invoice.pay

2.2. Привязка ролей: назначение ролей пользователям#

Для предоставления пользователю доступа роль должна быть назначена ему. Для этого используется сущность Role Binding (привязка роли). Эта сущность устанавливает отношение многие-ко-многим между пользователями и ролями.

  • Один пользователь может быть назначен на несколько ролей
  • Одна роль может быть назначена многим пользователям

2.3. Итоговая модель доступа#

Процесс проверки доступа:

  1. Пользователь вызывает сервис с токеном
  2. Сервис вызывает интроспекцию токена IAM
  3. Сервис получает список разрешений, доступных для этого токена, из ответа интроспекции
  4. Сервис проверяет, существует ли требуемое разрешение для запрошенного действия
  5. Если разрешение присутствует, доступ предоставляется

2.4. Примеры API ролей#

Создание роли#

POST /v1/iam/roles/
Content-Type: application/json
Authorization: Bearer <token>

{
  "name": "BillingOperator",
  "description": "Оператор биллинга с правами управления аккаунтами"
}

Ответ#

{
  "uuid": "6b2c3d4e-5f67-789a-bcde-f01234567890",
  "name": "BillingOperator",
  "description": "Оператор биллинга с правами управления аккаунтами",
  "created_at": "2025-08-21T07:38:04.779416Z",
  "updated_at": "2025-08-21T07:38:04.779424Z",
  "status": "ACTIVE",
  "project_id": null
}

Создание привязки разрешения#

POST /v1/iam/permission_bindings/
Content-Type: application/json
Authorization: Bearer <token>

{
  "role": "6b2c3d4e-5f67-789a-bcde-f01234567890",
  "permission": "5a1b2c3d-4e5f-6789-abcd-ef0123456789"
}

Создание привязки роли#

POST /v1/iam/role_bindings/
Content-Type: application/json
Authorization: Bearer <token>

{
  "user": "7c3d4e5f-6789-89ab-cdef-123456789012",
  "role": "6b2c3d4e-5f67-789a-bcde-f01234567890",
  "project": "8d4e5f67-789a-9abc-def1-234567890123"
}

Получение ролей пользователя#

GET /v1/iam/users/7c3d4e5f-6789-89ab-cdef-123456789012/actions/get_my_roles
Authorization: Bearer <token>

2.5. Проекты и область действия ролей/разрешений#

В IAM роли могут быть назначены:

  • Глобально (без проекта, project = null)
  • В рамках проекта (через поле project в Role Binding)

Это напрямую влияет на эффективный набор разрешений в токене.

При выдаче токена IAM определяет проект из scope:

  • project:<uuid> — токен привязан к указанному проекту
  • project:default — токен привязан к проекту по умолчанию пользователя
  • если нет сегмента project:... в scope, токен выдаётся без проекта (project = null)

При интроспекции IAM возвращает разрешения только в контексте проекта токена. Другими словами, эффективный набор разрешений зависит от того, для какого проекта выдан токен.

Важно: получение токена без проекта не даёт автоматического доступа ко всем проектам. Такой токен включает только разрешения, действительные в контексте project = null (глобальные назначения), и не включает назначения в рамках проекта из других проектов.

2.6. Как сервисы должны проверять разрешения (практический шаблон)#

Ниже приведена рекомендуемая модель интеграции бизнес-сервиса с IAM.

Базовый поток#

  1. Сервис получает токен пользователя (Authorization: Bearer ...)
  2. Сервис вызывает конечную точку интроспекции токена IAM
  3. Сервис получает список разрешений из интроспекции для текущего токена
  4. Перед каждым защищённым действием сервис проверяет наличие требуемого разрешения
  5. Если разрешение отсутствует, сервис возвращает 403 Forbidden

Минимальная структура кода сервиса#

class IamClient:
    def introspect(self, token: str) -> dict:
        # HTTP GET /v1/iam/clients/<client_uuid>/actions/introspect/invoke
        # с Authorization: Bearer <token>
        ...


class AuthContext:
    def __init__(self, token: str, introspection: dict):
        self.token = token
        self.introspection = introspection
        self.permissions = {
            p["name"] if isinstance(p, dict) else str(p)
            for p in introspection.get("permissions", [])
        }

    def has_permission(self, permission_name: str) -> bool:
        return permission_name in self.permissions


class PermissionDenied(Exception):
    pass

Guard/декоратор для проверки разрешений#

def require_permission(permission_name: str):
    def wrapper(handler):
        def inner(request, *args, **kwargs):
            ctx: AuthContext = request.auth_context
            if not ctx.has_permission(permission_name):
                raise PermissionDenied(
                    f"Missing required permission: {permission_name}"
                )
            return handler(request, *args, **kwargs)
        return inner
    return wrapper

Пример конечной точки#

@require_permission("compute.vm.create")
def create_vm(request):
    payload = request.json
    # Бизнес-логика создания VM
    return {"status": "ok"}, 201

Инициализация контекста в middleware#

def auth_middleware(request, iam_client: IamClient):
    token = extract_bearer_token(request.headers)
    if not token:
        return {"error": "Unauthorized"}, 401

    introspection = iam_client.introspect(token)
    request.auth_context = AuthContext(token=token, introspection=introspection)
    return None  # продолжить

Практические рекомендации#

  • Проверяйте разрешения как можно ближе к точке выполнения действия (конечная точка/use-case)
  • Не выводите права в сервисе — IAM должен оставаться единственным источником правды
  • Приемлем только кратковременный кэш интроспекции на стороне сервера; не кэшируйте разрешения на клиентской стороне
  • Логируйте отказы в доступе с указанием требуемого разрешения и контекста пользователя/токена

3. Лучшие практики#

3.1. Принцип минимальных привилегий#

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

3.2. Семантическое именование#

Давайте ролям и разрешениям понятные имена, отражающие их назначение:

  • Роли: NetworkReadOnly, DatabaseSuperUser
  • Разрешения: compute.vm.read, storage.bucket.delete

3.3. Регулярные аудиты#

Периодически проверяйте:

  • Какие роли назначены кому
  • Какие разрешения включены в роли
  • Удаляйте ненужный доступ незамедлительно

3.4. Использование проектов для изоляции#

Используйте привязку ролей в рамках проекта для изоляции доступа между окружениями. Подробное описание поведения в контексте проекта дано в разделе 2.5.

4. Обработка ошибок#

Следующие ошибки могут возникнуть при работе с IAM API:

4.1. Ошибка доступа (403 Forbidden)#

{
  "status": 403,
  "json": {
    "code": 403,
    "type": "PermissionDeniedException",
    "message": "User does not have required permission: compute.vm.create"
  }
}

4.2. Не найдено (404 Not Found)#

{
  "status": 404,
  "json": {
    "code": 404,
    "type": "NotFoundException",
    "message": "Role with uuid 6b2c3d4e-5f67-789a-bcde-f01234567890 not found"
  }
}

4.3. Некорректный запрос (400 Bad Request)#

{
  "status": 400,
  "json": {
    "code": 400,
    "type": "ValidationErrorException",
    "message": "Field 'name' must be between 0 and 255 characters"
  }
}

5. Важные замечания#

  1. Все изменения разрешений и привязок ролей вступают в силу немедленно
  2. Не кэшируйте разрешения на клиентской стороне; если кэширование необходимо, используйте только кратковременный серверный кэш интроспекции
  3. Для сервисных аккаунтов используйте отдельные роли с минимально необходимыми разрешениями
  4. Регулярно обновляйте и проверяйте назначения ролей в системе