OGOwnGate

Бессмертные токены: почему смена пароля не спасёт от слива репозитория

Разработчик уволился, вы сменили ему пароль в AD, но его статический Personal Access Token продолжает пуллить код из GitLab. Разбираем анатомию скрытых бэкдоров.

«Мы сменили ему пароль, всё чисто»: величайшее заблуждение ИБ

Когда из компании с шумом или конфликтом уходит ведущий инженер, служба безопасности действует строго по инструкции: блокирует доменную учётку в Active Directory, меняет пароль на рабочей почте и сбрасывает сессии в корпоративном VPN.

На совещании отчитываются: *«Доступ закрыт, угроза нейтрализована»*.

Но через неделю исходный код закрытого микросервиса или свежий дамп клиентской базы всплывает на теневом форуме. Как?

Ответ прост: разработчики ненавидят вводить пароли. Для работы с Git по HTTPS, выкачивания артефактов и локального тестирования они генерируют Personal Access Tokens (PAT) и API-ключи. И эти токены живут совершенно отдельной жизнью.

Растворяющийся статический токен доступа

---

Почему токены переживают увольнение сотрудников

Давайте разберёмся, как устроена жизнь типичного PAT в GitLab, GitHub, Grafana или внутренней системе документации:

1. Генерация внутри приложения. Токен выпускается в личном кабинете сервиса. Он представляет собой случайную криптографическую строку (например, glpat-xxxxxxxxxxxxxxxxxxxx).

2. Автономное хранение. Хеш токена сохраняется в локальной таблице базы данных приложения (personal_access_tokens).

3. Полная изоляция от пароля. Когда разработчик делает git clone https://oauth2:token@gitlab.company.ru/project.git, сервис даже не пытается проверять пароль пользователя в Active Directory или LDAP. Он просто ищет токен в своей базе.

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

А какую дату истечения разработчики выбирают при создании токена, если политика безопасности не закручена гайками? Правильно: «No expiration date» или максимум на год вперёд.

---

Где прячутся неучтённые токены

Если вы проведёте аудит в компании на 100 человек, вы гарантированно найдёте десятки «спящих» ключей доступа:

  • Локальный файл ~/.gitconfig и ~/.netrc на личном домашнем ноутбуке разработчика;
  • CI/CD пайплайны сторонних проектов, куда инженер однажды вставил свой токен для быстрого деплоя;
  • Cron-скрипты на тестовых серверах, собирающие бэкапы или выгружающие логи;
  • Скрипты аналитиков, тянущие данные из Grafana или ClickHouse через статический API Key.

Каждый такой токен — это прямой бэкдор в обход любого Active Directory и любого второго фактора.

---

Как закрыть дыру: 4 уровня защиты

Чтобы ликвидировать риск утечек через персональные токены, нужен системный подход:

1. Запрет бессрочных токенов на уровне политик

В настройках GitLab (Admin Area → Settings → General → Account and limit) необходимо принудительно выставить максимальный срок жизни токенов:

  • Максимальный срок: не более 30 дней;
  • Автоматическое напоминание об истечении за 7 дней.

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

2. Привязка профиля к состоянию в шлюзе доступа

При интеграции GitLab через единый шлюз доступа (OIDC) профиль пользователя жёстко связан с его статусом в шлюзе.

При блокировке сотрудника в Active Directory шлюз передаёт статус блокировки в приложение, и GitLab переводит учётную запись в статус Blocked. В заблокированном состоянии GitLab автоматически аннулирует все Personal Access Tokens и SSH-ключи, привязанные к этому профилю.

3. Отказ от парольного Git через HTTPS в пользу SSH с сертификатами

Персональные токены стали популярны именно потому, что вводить пароль при каждом пуше неудобно. Альтернатива — использование SSH-ключей с подписью корпоративного центра сертификации или работа через короткоживущие сессионные токены, получаемые через SSO CLI.

4. Регулярная инвентаризация статических ключей

Раз в квартал запускайте простой аудит по API:


# Получить список активных токенов со сроком действия более 60 дней

curl --header "PRIVATE-TOKEN: <ADMIN_TOKEN>" \

  "https://gitlab.company.ru/api/v4/personal_access_tokens?revoked=false"

Все подозрительные или забытые токены должны безжалостно отзываться.

---

Вывод

Пароль — это лишь вершина айсберга корпоративного доступа. Если ваша процедура увольнения заканчивается галочкой в Active Directory, уволенный сотрудник остаётся с ключами от ваших репозиториев.

Безопасность достигается только тогда, когда блокировка пользователя в единой точке автоматически деактивирует не только веб-сессии, но и все порождённые им статические ключи доступа во всех сервисах компании.

← Все статьи