IAM и модель разделённой ответственности
AWS отвечает за безопасность самого облака; ты — за то, что внутри него, и граница сдвигается от сервиса к сервису. IAM — то, как ты чертишь свою половину: identities, JSON-политики и правило, где explicit deny всегда бьёт allow и implicit deny.
У стартапа утекает S3-бакет со счетами клиентов. Вопрос после инцидента прямой: это вина AWS? Нет. AWS держал диски зашифрованными, дата-центр запертым, а сам сервис S3 — пропатченным, но разработчик повесил на CI-пользователя IAM-политику с "Action": "s3:*" и "Resource": "*", зашил долгоживущий access key этого пользователя в публичный GitHub-репозиторий, и скрапер нашёл его за девять минут. Каждый провал в этой цепочке был на стороне клиента — на той стороне границы, которую AWS проводит очень осознанно. Знать, где именно проходит эта граница, и как настроить свою половину через IAM, — это разница между защищённым аккаунтом и пробоиной, ждущей скрапера.
К концу урока ты будешь знать, где именно проходит граница ответственности по каждому типу сервиса, как читать и писать IAM-политику, не отдающую аттакующему весь аккаунт, и почему единственный явный Deny бьёт любой Allow в стеке.
Модель разделённой ответственности: где AWS заканчивается, а ты начинаешься
AWS формулирует это в двух фразах: AWS отвечает за безопасность самого облака; ты отвечаешь за безопасность внутри облака. AWS владеет железом, глобальной инфраструктурой (регионы, availability zones, физическая сеть), гипервизором и внутренностями каждого управляемого сервиса. Ты владеешь своими данными, тем, кто может их трогать, и тем, как всё настроено. Утёкший бакет со счетами лежал в сервисе S3, который AWS держит пропатченным и надёжным, — но политика бакета, IAM-разрешения и засвеченный ключ были твоими.
Ключевой нюанс в том, что граница сдвигается в зависимости от типа сервиса. Чем сервис управляемее, тем больше берёт на себя AWS:
- EC2 (сырая виртуальная машина): AWS даёт тебе пропатченное железо и гипервизор. Ты патчишь гостевую ОС, настраиваешь файрвол (security group), управляешь приложением и шифруешь диски. Это максимум ответственности, который ты можешь нести.
- Контейнеры на ECS/Fargate: AWS дополнительно управляет хостовой ОС и рантаймом контейнеров; на тебе по-прежнему содержимое образа, IAM task role и код приложения.
- Lambda: AWS управляет ОС, рантаймом и масштабированием. На тебе только код функции, её IAM execution role и зависимости.
- S3 / DynamoDB (полностью управляемые): AWS гоняет весь сервис целиком. Тебе остаются контроль доступа, выбор шифрования и сами данные.
Одна ответственность не сдвигается никогда, на любом сервисе: управление идентичностью и доступом всегда твоё. Именно об этой половине и весь урок.
▸Почему это работает
Почему граница двигается? Потому что «ответственность» идёт за «контролем». Нельзя пропатчить ОС, в которую ты не можешь зайти, — поэтому на Lambda, где нет управляемой тобой ОС, патчинг на AWS. Но ты всегда можешь решить, кому позволено вызывать эту Lambda, поэтому управление доступом неустранимо твоё на каждом сервисе. Читая диаграмму разделённой ответственности, спрашивай про любой пункт: «у кого есть рычаг, чтобы это изменить?» — тот за это и отвечает.
IAM identities и политики: словарь
Зачем этот словарь важен на практике? Потому что каждая неправильно настроенная политика доступа — от утёкшего бакета со счетами до эксплойта с повышением привилегий — это либо неверный тип identity, либо слишком широкая политика. Освоив словарь, ты перестанешь делать такие ошибки по умолчанию.
IAM (Identity and Access Management — управление идентичностью и доступом) — глобальный сервис, который решает, кто что может делать. У него две половины: identities (кто) и политики (что).
Identities бывают трёх видов:
- Users — долгоживущая identity для человека или легаси-системы, опционально с паролем и/или access-ключами.
- Groups — корзина пользователей с общими политиками; ты вешаешь политику на группу, и каждый участник её наследует. Группа — организационное удобство, а не identity, которую можно assume.
- Roles («роли») — identity без постоянных credentials. Принципал (EC2-инстанс, Lambda-функция, пользователь из другого аккаунта) assume-ит роль и получает короткоживущие, автоматически ротируемые credentials от STS (Security Token Service — сервис временных токенов доступа). Роль — выбор сеньора по умолчанию, почему — ниже.
Разрешения выражаются политиками: JSON-документами из statement’ов, в каждом до четырёх ключевых ключей.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject", "s3:PutObject"],
"Resource": "arn:aws:s3:::invoices-prod/uploads/*",
"Condition": { "StringEquals": { "aws:RequestedRegion": "eu-central-1" } }
}
]
}- Effect —
AllowилиDeny. - Action — API-операции, например
s3:GetObject. Wildcard’ы легальны (s3:*) и опасны. - Resource — ARN’ы, к которым это применяется.
*означает «любой ресурс», что почти всегда слишком широко. - Condition — необязательные условия (регион, source IP, наличие MFA, совпадение тега), которые должны выполниться, чтобы statement применился.
Политика выше даёт ровно два действия, на ровно один префикс бакета, в ровно одном регионе. Сравни с политикой, которая слила счета:
{
"Effect": "Allow",
"Action": "*",
"Resource": "*"
}"Action": "*" на "Resource": "*" — это администраторский доступ ко всему аккаунту. Повешенный на CI-пользователя, чей ключ сбежал, это разница между «атакующий может прочитать один префикс загрузок» и «атакующий владеет твоим аккаунтом». Выдавать только то, что принципалу нужно, и ничего сверх, — это принцип наименьших привилегий, самая несущая идея в IAM.
IAM также накладывает жёсткие квоты, формирующие структуру доступа, и сеньоры проектируют с их учётом: один документ managed-политики ограничен 6 144 символами, к одной роли/пользователю/группе можно прикрепить максимум 10 managed-политик, а аккаунт по умолчанию ограничен примерно 5 000 ролей и 300 customer-managed политик (часть — мягкие лимиты, которые можно поднять). Эти потолки — причина, по которой команды сходятся на нескольких переиспользуемых, хорошо ограниченных managed-политиках плюс permissions boundaries, а не пишут руками отдельную inline-политику под каждый принципал — такой подход быстро упирается в лимит символов и лимит прикреплений и становится неаудируемым задолго до этого.
Как решается запрос: deny побеждает
Когда принципал делает запрос, AWS собирает каждую применимую политику — identity-based политики на пользователе/роли, resource-based политики на цели, плюс boundaries и SCP, если они есть, — и применяет одно правило, которое надо держать в голове:
- По умолчанию — deny. Запрос без подходящего
Allowотклоняется. Это implicit deny. - Явный
Allowперебивает implicit deny — если какая-то применимая политика разрешает действие и ничто его не запрещает, запрос проходит. - Явный
Denyперебивает всё. Если любая применимая политика запрещает действие, запрос отклоняется, сколько бы allow’ов ни было.
То есть приоритет такой: explicit deny > explicit allow > implicit (дефолтный) deny. Deny — это гарантия; Allow действует только в отсутствие Deny. Поэтому гардрейлы пишут через deny — SCP, запрещающий отключать CloudTrail, не сможет отменить никакой allow, выданный админом аккаунта.
| Применимые политики говорят… | Результат | Почему |
|---|---|---|
| Ни один statement не совпал с действием | Deny | Implicit (дефолтный) deny — ничто не разрешило |
Один Allow, ни одного Deny | Allow | Allow перебивает implicit deny |
Allow и Deny | Deny | Explicit deny перебивает любой allow |
Практика сеньора: роли вместо ключей, root под замком
Механизм выше безопасен ровно настолько, насколько безопасны credentials, которые его кормят. Рекомендации AWS по identity однозначны и встречаются на экзамене:
- Предпочитай роли долгоживущим access-ключам. Роль выдаёт короткоживущие credentials, которые сами истекают и ротируются; утёкшая сессия роли быстро умирает, утёкший access key работает, пока кто-нибудь не заметит. Дай EC2 instance profile (роль для инстанса), а Lambda — execution role вместо зашитых ключей. Для доступа между аккаунтами пусть другой аккаунт assume-ит роль — никогда не копируй ключи между аккаунтами.
- Никогда не зашивай credentials в код или образы. Никаких access-ключей в исходниках, в слое контейнера или в переменных окружения, закоммиченных в git. Используй роль, прикреплённую к compute, или доставай секреты из Secrets Manager / SSM Parameter Store в рантайме.
- Запри root-пользователя. Root аккаунта может всё и не может быть ограничен IAM-политиками. Включи на нём MFA, удали его access-ключи полностью и используй его только для горстки задач, которые действительно требуют root. Повседневная работа идёт через IAM-роли/пользователей с наименьшими привилегиями.
- Наименьшие привилегии, потом ужимай. Начинай с минимума, выдавай конкретные действия на конкретные ресурсы, добавляй
Condition-условия (требуй MFA — многофакторную аутентификацию, ограничивай регион/IP) и используй IAM Access Analyzer, чтобы найти разрешения, которыми никто на деле не пользуется.
Вместе эти четыре практики сворачивают радиус поражения любого единичного сбоя: короткоживущие credentials роли ограничивают окно атакующего, ограниченный scope политики сужает то, до чего он может дотянуться, отсутствие зашитых ключей убирает самый лёгкий вектор утечки, а заблокированный root не даёт захватить аккаунт целиком. Пропусти любую одну — остальные три слабеют: цепочка держится на самом слабом звене.
Настоящее напряжение здесь — наименьшие привилегии против операционного трения, и у каждого края свой сценарий отказа. Переужмёшь — и инженеры ловят AccessDenied посреди инцидента, не могут выкатиться, а реакция-предохранитель и есть катастрофа: кто-то вешает AdministratorAccess «просто разблокировать деплой» и никогда не снимает — самый частый способ, которым аккаунты с наименьшими привилегиями тихо сползают в избыточные. Недоужмёшь — воссоздашь радиус поражения из истории с утёкшими счетами. Сеньорское решение — не выбрать сторону, а сделать ужимание дешёвым: выводи политики из реального использования (Access Analyzer генерирует политику наименьших привилегий из истории CloudTrail), выдавай временно повышенный доступ через короткоживущие assume-роли вместо постоянных грантов и относись к wildcard-политике как к красному флагу на код-ревью, а не как к удобству.
- 01Объясни правило оценки IAM-политик и почему гардрейлы пишут как Deny-statement'ы.
- 02Почему предпочитать IAM-роли долгоживущим access-ключам, и как это применяется к EC2, Lambda и доступу между аккаунтами?
Модель разделённой ответственности делит безопасность надвое: AWS отвечает за безопасность самого облака — железо, глобальная инфраструктура, гипервизор и внутренности управляемых сервисов, — а ты отвечаешь за безопасность внутри облака — твои данные, твоя конфигурация доступа и, на менее управляемых сервисах, гостевая ОС, security group и приложение. Граница двигается вместе с сервисом: на EC2 ты патчишь ОС и держишь файрвол; на Lambda или S3 AWS забирает ОС и рантайм, а тебе остаются код и — всегда — контроль доступа. IAM — то, как ты чертишь свою половину. У него есть identities — users, groups и (выбор сеньора) roles, выдающие короткоживущие credentials, — и JSON-политики из Effect, Action, Resource и Condition. Запросы решаются одним правилом: по умолчанию implicit deny, явный Allow его перебивает, а явный Deny перебивает всё — поэтому гардрейлы пишут как deny. Несущие практики: наименьшие привилегии (выдавай минимум, ограничивай конкретными ресурсами, добавляй Condition-условия), роли вместо долгоживущих ключей (instance profile для EC2, execution role для Lambda, assume-role между аккаунтами), никогда не зашивать credentials в код или образы и держать root-пользователя за MFA с удалёнными access-ключами. Пробоина с утёкшими счетами — это все эти правила, нарушенные разом, на стороне клиента той границы, которую AWS проводит очень осознанно. Теперь, когда видишь wildcard-политику или долгоживущий access key в конфиге приложения, ты знаешь, что менять, и понимаешь, почему модель default-deny делает эту ошибку твоей с первого дня.
Практика
Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.
Что-то непонятно?
Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.
Примени это
Примени этот урок в реальном проекте.