Руководство по настройке для команд ИТ и информационной безопасности
Содержание¶
- Обзор
- Ключевые возможности
- Архитектура
- Поток аутентификации
- Регистрация провайдеров
- OAuth2/OIDC
- Поддерживаемые провайдеры
- Настройка
- Поток авторизации
- Автоматическое создание пользователей
- LDAP/Active Directory
- Настройка LDAP
- Сопоставление групп и ролей
- Создание пользователей из LDAP
- Интеграция с SIEM
- События аутентификации
- Примеры событий
- Справочник API
- Конечные точки OAuth
- Конечные точки LDAP
- Запуск и остановка
- Устранение неполадок
- Связанные документы
Обзор¶
CodeGraph поддерживает корпоративную единую аутентификацию (SSO) через OAuth2/OIDC и интеграцию с LDAP/Active Directory. Оба метода инициализируются при запуске приложения и генерируют события безопасности для SIEM при каждой попытке аутентификации.
Ключевые возможности¶
| Возможность | Описание |
|---|---|
| 6 провайдеров OAuth2 | GitHub, Google, Keycloak (OIDC), GitLab, SourceCraft (Yandex ID), GitVerse (Sber ID) |
| Поддержка LDAP/AD | Active Directory, OpenLDAP с синхронизацией групп |
| Автоматическое создание | Пользователи создаются при первом входе через SSO/LDAP |
| Сопоставление RBAC | Группы LDAP сопоставляются с ролями CodeGraph (ADMIN, REVIEWER, ANALYST, VIEWER) |
| Защита от CSRF | Параметр state с серверной валидацией |
| Аудит в SIEM | События AUTH_SUCCESS / AUTH_FAILURE при каждом входе |
| Устойчивость к сбоям | Приложение запускается даже без OAuth/LDAP |
Архитектура¶
Поток аутентификации¶
┌──────────────┐
│ Браузер / │
│ API-клиент │
└──────┬───────┘
│
┌─────────────┼─────────────┐
│ │ │
┌──────▼──────┐ ┌───▼────┐ ┌──────▼──────┐
│ OAuth2 │ │ LDAP │ │ Локальный │
│ /OIDC │ │ /AD │ │ JWT + API │
└──────┬──────┘ └───┬────┘ └──────┬──────┘
│ │ │
└─────────────┼─────────────┘
│
┌───────▼───────┐
│ User Repo │
│ (найти или │
│ создать) │
└───────┬───────┘
│
┌───────▼───────┐ ┌──────────────┐
│ JWT-токены │ │ SIEM-событие│
│ (access + │──────►│ Диспетчер │
│ refresh) │ │ (auth.*) │
└───────────────┘ └──────────────┘
Регистрация провайдеров¶
При запуске функция lifespan() инициализирует подсистемы аутентификации:
- OAuth —
setup_oauth_providers()читает переменные окруженияOAUTH_*, регистрирует включённые провайдеры вOAuthManager - IAM —
setup_iam_validator()инициализирует валидацию токенов Yandex Cloud IAM (еслиIAM_ENABLED=true) - LDAP —
setup_ldap_authenticator()читает переменные окруженияLDAP_*, создаёт синглтонLDAPAuthenticator
Все блоки обёрнуты в try/except — приложение нормально запускается, даже если SSO не сконфигурирован.
OAuth2/OIDC¶
Поддерживаемые провайдеры¶
CodeGraph поддерживает 6 провайдеров OAuth2/OIDC. 4 базовых провайдера перечислены в эндпоинте /oauth/providers; SourceCraft и GitVerse — платформенные интеграции с отдельной документацией.
| Провайдер | URL авторизации | URL токена | Области доступа |
|---|---|---|---|
| GitHub | github.com/login/oauth/authorize |
github.com/login/oauth/access_token |
user:email |
accounts.google.com/o/oauth2/v2/auth |
oauth2.googleapis.com/token |
openid, email, profile |
|
| Keycloak | {server}/realms/{realm}/protocol/openid-connect/auth |
.../token |
openid, email, profile |
| GitLab | gitlab.com/oauth/authorize (или локальный) |
gitlab.com/oauth/token |
read_user, openid |
| SourceCraft | {server}/authorize (Yandex ID) |
{server}/token |
login:email, login:info |
| GitVerse | {server}/oauth/authorize (Sber ID) |
{server}/oauth/token |
read:user, user:email |
Примечание: SourceCraft и GitVerse подробно описаны в Интеграция с SourceCraft и Интеграция с GitVerse.
Настройка¶
Установите переменные окружения для каждого провайдера, который необходимо включить:
# GitHub
export OAUTH_GITHUB_CLIENT_ID="ваш_github_client_id"
export OAUTH_GITHUB_CLIENT_SECRET="ваш_github_client_secret"
# Google
export OAUTH_GOOGLE_CLIENT_ID="ваш_google_client_id"
export OAUTH_GOOGLE_CLIENT_SECRET="ваш_google_client_secret"
# Keycloak (OIDC)
export OAUTH_KEYCLOAK_SERVER_URL="https://keycloak.corp.example.com"
export OAUTH_KEYCLOAK_REALM="codegraph"
export OAUTH_KEYCLOAK_CLIENT_ID="codegraph-app"
export OAUTH_KEYCLOAK_CLIENT_SECRET="ваш_keycloak_client_secret"
# SourceCraft (Yandex ID)
export OAUTH_SOURCECRAFT_CLIENT_ID="ваш_sourcecraft_client_id"
export OAUTH_SOURCECRAFT_CLIENT_SECRET="ваш_sourcecraft_client_secret"
export OAUTH_SOURCECRAFT_SERVER_URL="https://oauth.yandex.ru" # по умолчанию
# GitVerse (Sber ID)
export OAUTH_GITVERSE_CLIENT_ID="ваш_gitverse_client_id"
export OAUTH_GITVERSE_CLIENT_SECRET="ваш_gitverse_client_secret"
export OAUTH_GITVERSE_SERVER_URL="https://gitverse.ru" # по умолчанию
Провайдеры без CLIENT_ID и CLIENT_SECRET автоматически пропускаются.
Примечание: OAuth для GitLab поддерживается в коде, но не имеет выделенных переменных окружения
OAUTH_GITLAB_*. Для включения GitLab настройте его напрямую вconfig.yamlв секцииauth.oauth.gitlabс полямиclient_id,client_secretи опциональноauthorize_url/token_urlдля локальных инстансов.
Поток авторизации¶
1. Пользователь → GET /api/v1/auth/oauth/{provider}
2. Сервер генерирует CSRF state, сохраняет в памяти
3. Редирект 302 на URL авторизации провайдера
4. Пользователь аутентифицируется на стороне провайдера
5. Провайдер перенаправляет на GET /api/v1/auth/oauth/{provider}/callback?code=...&state=...
6. Сервер проверяет state (CSRF), обменивает code на access token
7. Сервер запрашивает информацию о пользователе через API провайдера
8. Сервер находит или создаёт пользователя в базе данных
9. Сервер возвращает JWT-токены (access + refresh)
Автоматическое создание пользователей¶
При первом входе через OAuth автоматически создаётся пользователь:
| Поле | Источник |
|---|---|
username |
Зависит от провайдера (GitHub: login, Google: префикс email, Keycloak: preferred_username) |
email |
Информация от провайдера |
auth_provider |
Per-provider: oauth_github, oauth_google, oauth_gitlab, oauth_keycloak |
role |
По умолчанию: ANALYST |
external_id |
Уникальный ID пользователя у провайдера |
Примечание: Поле
display_nameиз информации провайдера передаётся в метод создания пользователя, но в настоящее время не сохраняется в базе данных. Полеusernameслужит основным отображаемым идентификатором.
Последующие входы находят пользователя по паре (auth_provider, external_id) и используют существующий аккаунт.
LDAP/Active Directory¶
Настройка LDAP¶
# Обязательные
export LDAP_SERVER="ldaps://ldap.corp.example.com"
export LDAP_BASE_DN="dc=corp,dc=example,dc=com"
# Сервисный аккаунт для поиска
export LDAP_BIND_USER="cn=codegraph-svc,ou=service-accounts,dc=corp,dc=example,dc=com"
export LDAP_BIND_PASSWORD="пароль_сервисного_аккаунта"
# Базы поиска
export LDAP_USER_SEARCH_BASE="ou=users,dc=corp,dc=example,dc=com"
export LDAP_GROUP_SEARCH_BASE="ou=groups,dc=corp,dc=example,dc=com"
Полная конфигурация LDAPConfig в config.yaml:
auth:
ldap:
enabled: true
server: "ldaps://ldap.corp.example.com"
port: 636
use_ssl: true
base_dn: "dc=corp,dc=example,dc=com"
user_search_base: "ou=users,dc=corp,dc=example,dc=com"
group_search_base: "ou=groups,dc=corp,dc=example,dc=com"
bind_user: "cn=codegraph-svc,ou=service-accounts,dc=corp,dc=example,dc=com"
bind_password: "${LDAP_BIND_PASSWORD}"
user_object_class: "person"
group_object_class: "group"
username_attribute: "sAMAccountName"
email_attribute: "mail"
group_membership_attribute: "memberOf"
role_mapping:
"cn=codegraph-admins,ou=groups,dc=corp,dc=example,dc=com": "admin"
"cn=codegraph-reviewers,ou=groups,dc=corp,dc=example,dc=com": "reviewer"
"cn=codegraph-analysts,ou=groups,dc=corp,dc=example,dc=com": "analyst"
Сопоставление групп и ролей¶
Группы LDAP сопоставляются с ролями RBAC CodeGraph через role_mapping в LDAPConfig. LDAPAuthenticator проверяет группы пользователя в порядке приоритета (admin > reviewer > analyst > viewer). Побеждает первое совпадение.
| Группа LDAP | Роль CodeGraph | Разрешения |
|---|---|---|
codegraph-admins |
ADMIN | Полный доступ (admin:all) |
codegraph-reviewers |
REVIEWER | Проверка кода + разрешения аналитика |
codegraph-analysts |
ANALYST | Выполнение запросов + API-ключи |
| (нет совпадения) | ANALYST | Роль по умолчанию |
Известная проблема: Метод
LDAPAuthenticator.map_groups_to_role()обращается кconfig.group_role_mappingвместо поляrole_mapping, определённого вLDAPConfig. Из-за этого сопоставление молча возвращает рольanalystпо умолчанию. Исправление требует выравнивания имени атрибута вldap_auth.pyс именем поляLDAPConfig.
Создание пользователей из LDAP¶
При первом входе через LDAP создаётся пользователь через LDAPAuthenticator:
| Поле | Источник |
|---|---|
username |
LDAP-атрибут sAMAccountName (или настроенный атрибут) |
email |
LDAP-атрибут mail |
ldap_dn |
Полное различающееся имя (DN), сохраняется как external_id |
auth_provider |
ldap |
role |
Из сопоставления групп и ролей |
Примечание:
display_nameиз LDAP-атрибутаdisplayNameпередаётся вcreate_ldap_user(), но в настоящее время не сохраняется в базе данных.
Последующие входы находят пользователя по ldap_dn (хранится как external_id с auth_provider=ldap).
Интеграция с SIEM¶
Все попытки аутентификации (успешные и неуспешные) генерируют SIEM-события, отправляемые в настроенные обработчики (Syslog, CEF, LEEF).
События аутентификации¶
| Тип события | Серьёзность | Триггер |
|---|---|---|
AUTH_SUCCESS |
6 (Информационное) | Успешный вход любым методом |
AUTH_FAILURE |
4 (Предупреждение) | Неуспешный вход — неверные учётные данные, неизвестный пользователь, ошибка провайдера |
Примеры событий¶
Успешный вход через OAuth:
{
"event_type": "auth.success",
"timestamp": "2026-02-26T10:30:00.000Z",
"severity": 6,
"message": "OAuth login: ghuser via github",
"user_id": "550e8400-e29b-41d4-a716-446655440000",
"ip_address": "10.0.0.50",
"provider": "github",
"request_id": "req-abc123"
}
Неуспешный вход через LDAP:
{
"event_type": "auth.failure",
"timestamp": "2026-02-26T10:31:00.000Z",
"severity": 4,
"message": "LDAP auth failed: unknown_user",
"ip_address": "10.0.0.51",
"request_id": "req-def456"
}
Неуспешный локальный вход (неверный пароль):
{
"event_type": "auth.failure",
"timestamp": "2026-02-26T10:32:00.000Z",
"severity": 4,
"message": "Login failed: invalid password for analyst01",
"user_id": "550e8400-e29b-41d4-a716-446655440001",
"ip_address": "10.0.0.52",
"request_id": "req-ghi789"
}
Справочник API¶
Конечные точки OAuth¶
| Метод | Путь | Описание |
|---|---|---|
GET |
/api/v1/auth/oauth/providers |
Список 4 базовых провайдеров OAuth и их статус |
GET |
/api/v1/auth/oauth/{provider} |
Начать OAuth-поток (перенаправление к провайдеру) |
GET |
/api/v1/auth/oauth/{provider}/callback |
Обработка OAuth-колбэка, возврат JWT-токенов |
Ответ списка провайдеров:
Примечание: Эндпоинт
/oauth/providersперечисляет 4 базовых провайдера (github, google, gitlab, keycloak) по захардкоженному списку. SourceCraft и GitVerse зарегистрированы вOAuthManagerи принимают OAuth-потоки через/oauth/{provider}, но не включены в листинг провайдеров.
[
{"name": "github", "enabled": true, "authorize_url": "https://github.com/login/oauth/authorize?..."},
{"name": "google", "enabled": false, "authorize_url": null},
{"name": "gitlab", "enabled": false, "authorize_url": null},
{"name": "keycloak", "enabled": false, "authorize_url": null}
]
Успешный ответ колбэка:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
"token_type": "bearer",
"expires_in": 1800
}
Конечные точки LDAP¶
| Метод | Путь | Описание |
|---|---|---|
POST |
/api/v1/auth/ldap |
Аутентификация через LDAP |
GET |
/api/v1/auth/ldap/status |
Проверка статуса подключения к LDAP |
Запрос аутентификации LDAP:
{
"username": "jdoe",
"password": "corporate_password"
}
Ответ статуса LDAP (подключён):
{
"enabled": true,
"available": true,
"connected": true,
"server": "ldaps://ldap.corp.example.com"
}
Ответ статуса LDAP (не настроен):
{
"enabled": false,
"available": false,
"message": "LDAP not configured"
}
Ответ статуса LDAP (библиотека ldap3 не установлена):
{
"enabled": true,
"available": false,
"message": "LDAP configured but ldap3 library not installed"
}
Ответ статуса LDAP (ошибка подключения):
{
"enabled": true,
"available": true,
"connected": false,
"error": "Connection refused"
}
Запуск и остановка¶
Последовательность запуска¶
При запуске приложения (lifespan()) подсистемы аутентификации инициализируются последовательно:
# 1. Провайдеры OAuth (6 провайдеров)
auth_config = get_auth_config()
oauth_providers = setup_oauth_providers({
"github": auth_config.oauth.github,
"google": auth_config.oauth.google,
"gitlab": auth_config.oauth.gitlab,
"keycloak": auth_config.oauth.keycloak,
"sourcecraft": auth_config.oauth.sourcecraft,
"gitverse": auth_config.oauth.gitverse,
})
# Лог: "OAuth providers initialized: 2" или "No OAuth providers configured"
# 2. Yandex Cloud IAM (опционально)
if settings.iam_enabled:
setup_iam_validator(enabled=True, validation_url=settings.iam_validation_url)
# Лог: "Yandex Cloud IAM validator initialized" или "IAM auth disabled"
# 3. LDAP-аутентификатор
ldap = setup_ldap_authenticator(auth_config.ldap)
# Лог: "LDAP authenticator initialized: ldaps://..." или "LDAP not configured"
Очистка при остановке¶
При остановке HTTP-клиенты OAuth закрываются корректно:
await get_oauth_manager().close_all()
Устойчивость к сбоям¶
Все подсистемы необязательны. Если инициализация не удалась (отсутствует библиотека, неверная конфигурация), приложение логирует предупреждение и продолжает работу:
WARNING OAuth initialization skipped: <ошибка>
WARNING IAM initialization skipped: <ошибка>
WARNING LDAP initialization skipped: <ошибка>
Все остальные конечные точки (локальный JWT-логин, API-ключи, запросы, сценарии) остаются полностью функциональными.
Устранение неполадок¶
Провайдеры OAuth показывают enabled: false¶
Проверьте установку переменных окружения:
echo $OAUTH_GITHUB_CLIENT_ID
echo $OAUTH_GITHUB_CLIENT_SECRET
Оба значения CLIENT_ID и CLIENT_SECRET должны быть непустыми для регистрации провайдера.
OAuth-колбэк возвращает invalid_state_parameter¶
CSRF-токен state хранится в памяти сервера. Эта ошибка возникает если: - Токен state устарел (сервер перезапущен между редиректом и колбэком) - Токен state уже использован (обновление страницы в браузере) - Многоинстансное развёртывание без общего хранилища state (используйте Redis в рабочей среде)
LDAP возвращает 503 ldap_not_configured¶
Переменная окружения LDAP_SERVER не установлена или библиотека ldap3 не установлена:
pip install ldap3>=2.9.1
Тест подключения к LDAP не проходит¶
Проверьте сетевую доступность и учётные данные:
# Тест подключения к LDAP
ldapsearch -H ldaps://ldap.corp.example.com -x -D "cn=codegraph-svc,..." -w ПАРОЛЬ -b "dc=corp,dc=example,dc=com" "(sAMAccountName=testuser)"
Сопоставление ролей LDAP всегда возвращает analyst¶
Метод LDAPAuthenticator.map_groups_to_role() имеет известное несоответствие имён атрибутов: обращается к config.group_role_mapping вместо config.role_mapping. До исправления в ldap_auth.py все LDAP-пользователи получают роль analyst по умолчанию вне зависимости от конфигурации role_mapping.
SIEM-события не появляются¶
Проверьте, что диспетчер SIEM включён в config.yaml:
siem:
enabled: true
handlers:
- type: syslog
host: "siem.corp.example.com"
port: 514
Подробная настройка — см. Интеграция с SIEM.
В логах запуска предупреждения об инициализации¶
Проверьте логи приложения на конкретные ошибки:
uvicorn src.api.main:app --log-level debug 2>&1 | grep -i "oauth\|ldap\|iam"
Связанные документы¶
- RBAC и авторизация — Иерархия ролей и каталог разрешений
- Интеграция с SIEM — Форматы событий безопасности и настройка диспетчера
- Обзор безопасности — Корпоративная безопасность
- Защита от утечек данных — Предотвращение утечки данных
- Руководство по развёртыванию — Развёртывание высокой доступности
- Интеграция с SourceCraft — SourceCraft (Yandex ID) OAuth
- Интеграция с GitVerse — GitVerse (Sber ID) OAuth