Перейти до вмісту

Ідентичність і доступ

Розробник додає у репозиторій файл .env із ключем доступу до AWS і робить git push. Репозиторій публічний. За кілька хвилин в акаунті зʼявляються десятки великих інстансів у різних регіонах, а наприкінці місяця приходить рахунок на пʼять цифр. Зламувати нічого не довелося: ключ був дійсним, а хмара не відрізняє власника від того, хто його знайшов.

У хмарі кожна дія над ресурсом є викликом API, підписаним чиєюсь ідентичністю. API доступне з будь-якого місця, тому мережевий периметр вирішує небагато, і головною межею безпеки стають ідентичність та політики доступу. Більшість хмарних інцидентів починається з неправильно виданого або витеклого доступу.

У модулі розібрано, як влаштовано ідентичності й політики у трьох хмарах, як видати рівно ті права, що потрібні, як обійтися без довгоживучих ключів там, де їх найчастіше залишають (у CI), і чому знайдений ключ експлуатують швидше, ніж встигає надійти сповіщення.

Передумови. Ієрархія акаунтів, підписок і проєктів (модуль 2), модель спільної відповідальності (модуль 1). Секрети, шифрування й аудит розібрано в модулі 12, доставку через CI — у модулі 10. Права доступу й ізоляцію процесів розібрано в курсі ОС: захист і безпека.

Ідентичність, автентифікація, авторизація

Section titled “Ідентичність, автентифікація, авторизація”

Кожен запит до хмарного API проходить два окремі питання. Автентифікація (authentication) відповідає, хто це, а авторизація (authorization) відповідає, чи може він робити те, про що просить. Перше вирішується обліковими даними: паролем із MFA, токеном, підписаним запитом. Друге вирішується політиками.

Суб’єкта, який робить запит, називають принципалом (principal). Принципали бувають двох видів, і відмінність між ними визначає весь подальший дизайн доступу:

Вид Приклад Як автентифікується Типова небезпека
Людина інженер, адміністратор пароль + MFA, SSO через корпоративний провайдер фішинг, викрадена сесія
Робоче навантаження (workload) застосунок на інстансі, функція, CI-завдання тимчасові облікові дані від платформи ключ у коді, у репозиторії, у логах

Людям видають доступ через єдиний вхід (SSO). Навантаженням найкраще не видавати нічого довгоживучого: платформа сама підставляє їм короткі облікові дані, а їхнє походження можна перевірити. Решта модуля — про те, як це зробити.

Три моделі ідентичності

Section titled “Три моделі ідентичності”

AWS. Акаунт має власну підсистему IAM. Користувач IAM (user) є довгоживучою ідентичністю з паролем і/або ключами доступу. Роль (role) не має власних облікових даних: її «надягають» (assume) на певний час, отримуючи тимчасові ключі від STS. Кореневий користувач (root user) може все, тому ним користуються лише для кількох рідкісних операцій. Людям рекомендують IAM Identity Center із SSO замість користувачів IAM.

Azure. Ідентичності живуть у тенанті Microsoft Entra ID, а не в підписці: користувачі, групи, сервісні принципали (service principals). Для навантажень є керована ідентичність (managed identity): Azure сам створює й ротує її облікові дані. Права видає окремий шар, Azure RBAC, привʼязуючи принципала до ролі на певному рівні ієрархії з модуля 2. Ролі Entra ID (наприклад, Global Administrator) керують самим тенантом, ролі Azure RBAC керують ресурсами, і ці системи легко сплутати.

Google Cloud. Люди мають акаунти Google або Cloud Identity у вашому домені. Навантаження працюють від сервісного акаунта (service account), який одночасно є ідентичністю й ресурсом: іншим можна дозволити діяти від його імені. Права записують як привʼязки «роль + учасники» на рівні організації, папки, проєкту або ресурсу, і вони успадковуються вниз.

Як хмара ухвалює рішення

Section titled “Як хмара ухвалює рішення”

Усі три провайдери починають із заборони: доступу немає, доки якась політика його не дала. Якщо хоча б одна застосовна політика явно забороняє дію, вона забороняється, скільки б дозволів не було в інших (explicit deny). Дозволи додаються, тож надлишкові права накопичуються тихо, а забрати їх складніше, ніж видати.

Політика на боці принципала відповідає на питання «що йому можна», політика на боці ресурсу (бакет, ключ, секрет) на питання «кому з ним можна», і саме вона дозволяє доступ між акаунтами. В AWS обидва види є JSON-документами, в Azure права переважно задають призначеннями ролей на рівні ресурсу, а в GCP привʼязки прикріплюють до самого ресурсу. Мінімальна політика AWS, що дозволяє читати обʼєкти з одного префікса бакета й лише по TLS:

{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::reports-prod/2026/*",
"Condition": { "Bool": { "aws:SecureTransport": "true" } }
}
]
}

У політиках усіх провайдерів є ті самі частини: хто, що робить, над чим і за яких умов.

Окрім «що дозволено», є механізми «що не можна дозволити взагалі». Вони працюють як стеля, яку політики окремих ідентичностей не пробивають.

  • AWS. Політики керування сервісами (SCP) обмежують ідентичності акаунтів організації, політики керування ресурсами (RCP) обмежують доступ до ресурсів, межа дозволів (permissions boundary) задає максимум для окремої ролі. Ефективні права дорівнюють перетину дозволів і стель.
  • Azure. Для конфігурації використовують Azure Policy. Призначення заборони (deny assignments) переважно створює сама платформа.
  • GCP. Політики заборони (deny policies) мають пріоритет над дозволами, а Organization Policy обмежує конфігурацію (наприклад, забороняє створювати ключі сервісних акаунтів).

Принцип найменших привілеїв на практиці

Section titled “Принцип найменших привілеїв на практиці”

Принцип найменших привілеїв (least privilege) вимагає давати ідентичності рівно ті дії, що потрібні, на рівно тих ресурсах і не довше, ніж потрібно. Широкі права видають, бо вузькі писати довго, а помилка в них зупиняє роботу негайно, тоді як помилка в широких проявляється роками пізніше.

  1. Уникайте готових широких ролей. AdministratorAccess в AWS, Owner і Contributor в Azure, roles/owner та roles/editor в GCP існують для швидкого старту, а не для виробничого середовища.
  2. Звужуйте область дії. Роль на групі ресурсів безпечніша за роль на підписці, привʼязка на бакеті безпечніша за привʼязку на проєкті.
  3. Розділяйте ідентичності. Кожному навантаженню окрема роль чи сервісний акаунт: зламаний найслабший застосунок не отримає прав найсильнішого.
  4. Розширюйте за помилками, а не наперед. Реально використані права показують IAM Access Analyzer (AWS), IAM Recommender (GCP) та огляди доступу в Entra ID.
  5. Видавайте підвищені права на час. Privileged Identity Management в Entra ID дає адміністративну роль на годину після підтвердження.

Чому ключі в GitHub знаходять за хвилини

Section titled “Чому ключі в GitHub знаходять за хвилини”

Довгоживучий ключ доступу (в AWS це пара з ідентифікатором AKIA… і секретом, в GCP JSON-файл ключа сервісного акаунта) працює з будь-якого місця й не закінчується сам. Кожна копія в репозиторії, у логах збірки чи в чаті лишається робочим доступом, доки хтось його не відкличе.

Швидкість виявлення вимірювали кілька груп дослідників. Метод схожий: публікують приманку (honeypot), тобто справжній, але обмежений ключ, і дивляться в журнали.

Дослідження Що зробили Результат
Comparitech ключі AWS у публічних репозиторіях GitHub перше зловживання за одну хвилину; понад тисячу спроб створити інстанси в першу хвилину; 547 різних IP-адрес
Unit 42, 2023 випадкові репозиторії з ключами IAM, спостереження з 30 серпня по 6 жовтня ключі виявляли й починали використовувати за 4–5 хвилин
Clutch Security, 2024 ключі на різних платформах GitHub і Docker Hub за кілька хвилин; PyPI, Pastebin, Postman за кілька годин; GitLab, Stack Overflow, Reddit за 1–5 днів; npm не використано

Це порядок величини, а не закон: приманки розміщували свідомо, а видимість справжніх витоків різна. Практичний висновок в іншому: між публікацією ключа і першим використанням проходять хвилини, тож процес «помітимо й відкличемо» нічого не гарантує.

Причина швидкості проста. Потік публічних подій GitHub доступний усім, регулярний вираз на кшталт AKIA[0-9A-Z]{16} знаходить ключ у новому коміті за секунди, а перевірка ключа коштує один виклик sts get-caller-identity. Масштаб видно з даних GitHub: у 2024 році він виявив понад 39 мільйонів витеклих секретів.

Провайдери теж сканують публічні репозиторії. AWS прикріплює до користувача з виявленим ключем політику AWSCompromisedKeyQuarantineV3, яка блокує частину дорогих дій, і надсилає сповіщення; у повторному тесті Unit 42 у грудні 2025 року це сталося через 10 секунд. Проте політика не відкликає ключ, не зачіпає вже створені ресурси і блокує не все. Clutch Security зафіксувала, що автоматичні сповіщення й карантин часто не встигають за атакувальником.

Федерація (federation) означає, що хмара довіряє чужому провайдеру ідентичності й приймає його підтвердження замість власних облікових даних. Інженер входить у корпоративний Entra ID або Okta, хмара отримує підписане твердження (SAML чи токен OIDC) і видає сесію з обмеженим терміном. Пароля в хмарі немає, нема чого красти чи ротувати; звільнення вимикає доступ в одному місці; групи каталогу зіставляються з ролями; викрадена сесія живе години, а не роки.

В AWS цю схему втілює IAM Identity Center. В Azure роль провайдера ідентичності виконує сам Entra ID. Google Cloud підключає Cloud Identity або зовнішнього провайдера через workforce identity federation.

Федерація: робочі навантаження і OIDC

Section titled “Федерація: робочі навантаження і OIDC”

Для програм є той самий механізм, і саме він вирішує проблему з початку модуля. Замість ключа програма пред’являє токен, який їй видав довірений емітент. Найчастіший випадок — CI: GitHub Actions, GitLab CI та інші вміють видавати завданню підписаний токен OpenID Connect (OIDC) із твердженнями (claims) про те, хто його запустив.

Схема OIDC-федерації: завдання CI отримує підписаний токен від GitHub, передає його хмарі, хмара перевіряє підпис та умови довіри й повертає тимчасові облікові данізавдання CIGitHub Actionsемітент токенів GitHubtoken.actions.githubusercontent.comфедерація хмариперевірка підпису й умовресурси хмари123451завдання просить у GitHub короткоживучий JWT: у ньому repo, ref, sub2завдання передає токен хмарі й називає роль, яку хоче отримати3хмара перевіряє підпис відкритими ключами GitHub і умови довіри4хмара повертає тимчасові облікові дані, зазвичай на годину5завдання викликає API з цими даними; жодного збереженого ключа
Хмара перевіряє токен у момент запиту. Заздалегідь у CI не зберігається нічого, що можна було б вкрасти й використати потім.

Три твердження в токені мають значення для довіри:

  • iss (issuer) — хто видав токен. Для GitHub це https://token.actions.githubusercontent.com.
  • aud (audience) — кому токен призначений. Для AWS це sts.amazonaws.com, для Azure api://AzureADTokenExchange.
  • sub (subject) — про кого йдеться. У GitHub він складається з репозиторію і контексту запуску, наприклад repo:my-org/my-repo:ref:refs/heads/main або repo:my-org/my-repo:environment:production.

Довіру налаштовують правилами на боці хмари: «приймати токени цього емітента, лише якщо sub відповідає такому шаблону». Ця умова і є головним засобом захисту. Без умови на sub роль довірятиме будь-якому репозиторію GitHub, включно з чужими. Помилку в цьому описала команда Wiz, і AWS у 2025 році додала перевірку: створити роль, що довіряє провайдеру GitHub без умови на sub, уже не вдається.

Обмеження токена шаблоном sub працює настільки, наскільки точний шаблон. repo:my-org/* дозволяє кожному репозиторію організації, і якщо там є репозиторій із слабким контролем гілок, він може отримати права виробничої ролі. Для середовищ, які треба ізолювати (виробниче, наприклад), використовуйте environment: і захист середовища в самому GitHub.

Спершу — сам робочий процес. Дозвіл id-token: write потрібен, щоб завдання могло попросити токен, а ключів у файлі немає.

permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v6
with:
role-to-assume: arn:aws:iam::123456789012:role/github-deploy
aws-region: us-east-1
- run: aws sts get-caller-identity

Значення в secrets.AZURE_* не є секретами в звичному сенсі: це ідентифікатори. Їх зберігають у секретах лише тому, що документація дії радить не підставляти туди значення з непевних джерел.

Що налаштовується в хмарі

Section titled “Що налаштовується в хмарі”

Тепер сторона довіри. У всіх трьох випадках вона вимагає трьох речей: зареєструвати емітента, описати умову для sub і прив’язати до ролі мінімальні права.

variable "github_repo" {
type = string
default = "my-org/my-repo"
}
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = ["sts.amazonaws.com"]
}
data "aws_iam_policy_document" "trust" {
statement {
actions = ["sts:AssumeRoleWithWebIdentity"]
principals {
type = "Federated"
identifiers = [aws_iam_openid_connect_provider.github.arn]
}
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:aud"
values = ["sts.amazonaws.com"]
}
condition {
test = "StringEquals"
variable = "token.actions.githubusercontent.com:sub"
values = ["repo:${var.github_repo}:ref:refs/heads/main"]
}
}
}
resource "aws_iam_role" "deploy" {
name = "github-deploy"
assume_role_policy = data.aws_iam_policy_document.trust.json
max_session_duration = 3600
}

У прикладі AWS немає списку відбитків сертифіката (thumbprint_list): для GitHub AWS користується власною бібліотекою довірених центрів сертифікації, тож поле необов’язкове. Роль deploy у прикладі має лише довіру, без прав на ресурси, і їх додають окремо за принципом найменших привілеїв.

Однакова задача, різна кількість сутностей. AWS потребує провайдера й ролі, Azure керованої ідентичності, федеративних облікових даних і призначення ролі, GCP пулу, провайдера, сервісного акаунта й дозволу на його імперсонацію. У GCP умову довіри записано двічі: attribute_condition відсікає чужі токени ще до обміну, а principalSet обмежує, хто може діяти від імені саме цього сервісного акаунта.

Ідентичність навантажень усередині хмари

Section titled “Ідентичність навантажень усередині хмари”

Для коду, що вже працює в хмарі, ключі теж не потрібні. Платформа вбудовує ідентичність у середовище виконання.

Де працює код AWS Azure GCP
Віртуальна машина роль інстанса (instance profile) керована ідентичність сервісний акаунт, прикріплений до ВМ
Функція, контейнерна платформа роль виконання керована ідентичність сервісний акаунт сервісу
Kubernetes IRSA або EKS Pod Identity Microsoft Entra Workload ID Workload Identity Federation for GKE
Зовнішнє середовище (CI, інша хмара) OIDC-провайдер + роль федеративні облікові дані Workload Identity Federation

Отримані облікові дані короткоживучі й доступні через ендпоінт метаданих або токен, змонтований у під. Ендпоінт метаданих і його захист розібрано в модулі 4, а роботу ідентичностей у Kubernetes — в модулі 8.

Багатофакторна автентифікація (MFA) додає до пароля другий фактор. Найстійкіші до фішингу варіанти спираються на FIDO2 і passkeys: відповідь привʼязано до справжньої адреси сайту, тож підроблена сторінка нічого не перехопить. У 2024–2025 роках всі три провайдери перейшли від «рекомендуємо» до «вимагаємо»:

  • AWS вимагає MFA для кореневого користувача: спершу для керівних акаунтів організацій (травень 2024), потім для окремих акаунтів (червень 2024), а з червня 2025 року для всіх типів акаунтів, включно з членськими.
  • Azure вводить обовʼязковий MFA у два етапи. Другий, з 1 жовтня 2025, охоплює Azure CLI, PowerShell, мобільний застосунок, IaC-інструменти й REST API для операцій створення, оновлення та видалення. Керовані ідентичності й сервісні принципали не зачіпаються.
  • Google Cloud запровадила обовʼязковий MFA в три етапи від листопада 2024: підготовка адміністраторів, вимога для користувачів із паролем, наприкінці 2025 року для федеративних користувачів.

Практичні правила однакові. Кореневого користувача (AWS), глобальних адміністраторів (Azure) і власників організації (GCP) захищають апаратним ключем. Для аварійного доступу тримають два облікові записи «на розбитому склі» (break glass), незалежні від звичайного провайдера ідентичності. Ключів доступу для кореневого користувача не створюють.

AWS Azure GCP
Де живуть ідентичності акаунт (IAM) або IAM Identity Center тенант Entra ID Cloud Identity / Google Workspace, сервісні акаунти в проєкті
Ідентичність застосунку роль IAM керована ідентичність, сервісний принципал сервісний акаунт
Формат прав JSON-політика дозволів роль (набір дій) + область + принципал роль (набір дозволів) + учасник на ресурсі
Права, прикріплені до ресурсу політики ресурсів (бакет, ключ) призначення ролей на рівні ресурсу привʼязки на самому ресурсі
Стеля SCP, RCP, межа дозволів Azure Policy (для конфігурації) політики заборони, Organization Policy
Явна заборона Deny у будь-якій політиці deny assignments (переважно від платформи) deny policies
Обмін токена CI на доступ OIDC-провайдер + AssumeRoleWithWebIdentity федеративні облікові дані на керованій ідентичності Workload Identity Federation
Довгоживучі ключі ключі користувача IAM секрет застосунку, сертифікат JSON-ключ сервісного акаунта

Чим це відрізняється і що з цього випливає. У AWS права прив’язано до ідентичності й описано в політиках, тому питання «що може ця роль?» має відповідь в одному місці, а питання «хто може дістатися цього бакета?» потребує перегляду ще й політик ресурсів. В Azure та GCP права стають частиною ієрархії: призначення роль на підписці автоматично охоплює всі групи ресурсів під нею, і тому найчастіша помилка — надто високий рівень призначення. У GCP один сервісний акаунт водночас є ідентичністю й ресурсом, тож право «діяти від імені» (iam.serviceAccountUser, iam.serviceAccountTokenCreator) само стає способом підвищення привілеїв, яке легко пропустити під час перегляду доступу.

Перша діагностична дія в будь-якому середовищі: подивитися, від чиєї ідентичності виконуються команди, і які довгоживучі ключі існують.

Terminal window
aws sts get-caller-identity
aws iam list-access-keys --user-name deploy-bot
aws iam get-access-key-last-used --access-key-id AKIAEXAMPLE1234567890

Ключ, який місяцями не використовували, слід вимкнути.

Розбір: ключ у публічному репозиторії

Section titled “Розбір: ключ у публічному репозиторії”

Експеримент Unit 42 (Palo Alto Networks) дозволяє пройти шлях витоку крок за кроком. З 30 серпня по 6 жовтня 2023 року дослідники створювали випадкові репозиторії на GitHub і залишали в минулих комітах ключі IAM у відкритому вигляді. Ключі були приманками, але журнали фіксували все, що з ними робили.

Час. Ключі знайшли й почали використовувати через 4–5 хвилин після публікації.

Дії. Автоматика діяла за сценарієм, який дослідники повʼязали з відомою кампанією EleKtra-Leak (активною щонайменше з грудня 2020 року). Спершу DescribeRegions, тобто розвідка доступних регіонів. Потім групи безпеки в кожному регіоні. Потім інстанси c5a.24xlarge зі скриптами cloud-init, що завантажували майнер Monero зі сховища на Google Drive. За весь період дослідники зафіксували 474 унікальні інстанси, які, ймовірно, керував зловмисник. Понад 400 викликів API відбулося приблизно за 7 хвилин.

Що обмежило шкоду. Політика приманки, а також карантин AWS, який спрацював приблизно за 2 хвилини після виявлення ключа на GitHub. У справжньому інциденті політика ключа, найімовірніше, була б ширшою.

Свіжіший приклад описала сама AWS у грудні 2025 року. Кампанія стартувала 2 листопада 2025: зловмисник із дійсними обліковими даними IAM за перші десять хвилин перевірив квоти й права викликами з прапором DryRun, а потім розгорнув майнери в ECS та EC2 (понад 50 кластерів ECS, 14 груп автомасштабування). Він також вимкнув захист від видалення інстансів (disableApiTermination), щоб ускладнити реагування. Як отримано облікові дані, AWS не вказала; вона лише зазначила, що використано дійсні дані, а не вразливість сервісу. Рекомендації: тимчасові облікові дані замість довгоживучих ключів, MFA, найменші привілеї, GuardDuty.

Якби в репозиторії лежала OIDC-конфігурація, знайдений сканером код був би марним: токен видається на конкретний запуск, діє хвилини й приймається лише для репозиторію та гілки з умови довіри. Виявлення й реагування (журнали аудиту, CSPM) розібрано в модулі 12.

Типові помилки розуміння

Section titled “Типові помилки розуміння”

«Ключ у приватному репозиторії безпечний». Видимість репозиторію може змінитися, доступ мають усі учасники, а ключ лишається в історії, у клонах і в логах збірки.

«Права широкі тимчасово, потім звузимо». Звуження нічого не додає до роботи, тому його відкладають назавжди. Вузькі права роблять початковим станом, а розширюють за конкретними помилками.

«Роль AWS є користувачем із паролем». Роль не має власних облікових даних. Її надягають на час сесії, і хто це робить, визначає політика довіри.

«OIDC налаштований, отже безпечно». Федерація без вузької умови на sub довіряє всьому GitHub. Перевіряйте точність умов, а не сам факт федерації.

«MFA закриває будь-який доступ». MFA стосується людей. Ключі й токени навантажень нею не захищені, їх замінюють короткоживучими обліковими даними.

Перевір себе

1. Розробник запушив ключ AWS у публічний репозиторій і за 10 хвилин видалив коміт. Що робити?
2. Чим ключ користувача IAM небезпечніший за роль, яку надягає застосунок?
3. У ролі AWS для GitHub Actions умова довіри перевіряє лише aud = sts.amazonaws.com. Хто зможе її надягнути?
4. Один сервісний акаунт GCP з роллю roles/editor на проєкті обслуговує пʼять застосунків. Що піде не так першим?
5. Політика принципала дозволяє s3:GetObject, а SCP організації забороняє. Результат?
6. CI-завданню треба розгортати ресурси в Azure. Яке рішення найкраще?