IAM (Identity and Access Management) — это система AWS, которая отвечает на один вопрос: «кто и что может делать». Хотите прочитать файл из хранилища, запустить виртуальную машину, отправить сообщение в очередь — каждый раз AWS сверяется с IAM: а разрешено ли вам это вообще.
Звучит как скучная бюрократия, но именно тут происходит большинство аварий в облаке. Чаще всего ломают не сложным взломом, а потому что кому-то выдали слишком много прав или ключ доступа случайно попал в открытый репозиторий на GitHub. Поэтому потратить полчаса на понимание IAM выгоднее, чем потом разбирать инцидент. Давайте по порядку.
Порядок решения один для всего AWS: сначала ищут явный запрет, и он перебивает любые разрешения; потом нужен хотя бы один явный Allow; если его нет, действует неявный запрет по умолчанию. Между аккаунтами разрешить должны обе стороны.
Root и первые пять минут в аккаунте
Прежде чем говорить о пользователях и ролях, надо упомянуть того, кто стоит над ними обоими.
Root-пользователь — это учётная запись, на которую регистрировали аккаунт: email и пароль. Она не подчиняется политикам IAM: запретить ей что-либо внутри аккаунта нельзя (только политика уровня организации ставит ей потолок). То есть это не «самый главный администратор», а сущность вне системы прав.
Что с ним делают в первый же день:
- Включают второй фактор. Без него один подобранный или утёкший пароль означает потерю аккаунта целиком: злоумышленник сможет сменить контакты, создать себе права и отключить платёжные ограничения.
- Удаляют ключи доступа, если они есть. Программе доступ от root не нужен никогда; наличие таких ключей — первое, на что смотрит любой аудит.
- Заводят обычного администратора (а лучше сразу вход через IAM Identity Center) и дальше работают под ним.
- Записывают, у кого есть доступ к root. Обычно это один-два человека, а пароль и второй фактор лежат в хранилище секретов компании, а не у сотрудника в телефоне.
Список задач, для которых root действительно нужен, короткий и лежит в документации: сменить платёжные данные, изменить план поддержки, закрыть аккаунт, восстановить доступ, снять некоторые ограничения на хранилище. Всё остальное делается обычными правами.
Пользователи против ролей
Это первое и главное различие, в котором новички путаются, и правило тут одно: людям — пользователи, программам, серверам и автоматизации — роли. Почему так — ниже.
IAM-пользователь — это постоянная учётная запись. У неё есть имя, а к нему можно завести долгоживущие ключи доступа (access key и secret key) — что-то вроде логина и пароля, только для программ. Ключей может не быть вовсе (человек просто входит в консоль по паролю), а может быть сразу два — именно так ключ и меняют без простоя: завели второй, перевели на него приложение, старый удалили. Сами по себе ключи не меняются: создали и пользуетесь, пока не отзовёте.
IAM-роль — это не учётная запись, а набор прав, который можно временно «надеть». Аналогия: пользователь — это ваш постоянный паспорт, а роль — гостевой бейдж на проходной, который выдают на пару часов и который сам по себе ничего не значит без вас. Процесс «надеть роль» называется assume role (принять роль), и в ответ вы получаете не вечные ключи, а временные учётные данные (credentials), которые сами протухают через час-другой.
Ключевое правило, которое стоит запомнить сразу: для программ, серверов и автоматизации используют роли, а не пользователей с ключами.
Почему так:
- Ключи пользователя живут вечно, поэтому рано или поздно утекают — в код, в логи, в историю команд терминала, в скриншот. И утёкший ключ работает, пока кто-то вручную не спохватится.
- Креды роли выдаются на минуты-часы и обновляются автоматически. Даже если такой набор утечёт, через час он уже бесполезен.
На практике это выглядит так: ваше приложение крутится на виртуальной машине (EC2), в контейнере (ECS) или в Kubernetes (EKS). Вы привязываете к нему роль — и приложение получает права через неё. В коде и в конфигах нет ни одного ключа. Когда новичок спрашивает «а как моему сервису достучаться до хранилища S3?» — правильный ответ почти всегда «через роль», а не «положи ключи в переменные окружения».
Как устроены политики
Сами по себе права описываются политикой (policy) — это документ в формате JSON, перечисляющий, что можно, а что нельзя. Вот самая простая политика — «разрешить чтение объектов из конкретного бакета (контейнера хранилища) S3»:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::my-bucket/*"
}
]
}
Разберём по полям:
Version— версия языка политик. Дата2012-10-17не значит, что документ устарел; это просто фиксированный идентификатор актуальной грамматики, его всегда пишут именно так.Effect—Allow(разрешить) илиDeny(запретить).Action— что именно:s3:GetObjectэто «скачать объект». У каждого сервиса свой список действий.Resource— над чем: здесь это ARN (Amazon Resource Name, глобальный адрес ресурса) конкретного бакета. Хвост/*важнее, чем кажется:arn:aws:s3:::my-bucket/*— это объекты внутри бакета, аarn:aws:s3:::my-bucketбез хвоста — сам бакет. Действия над объектами (s3:GetObject) просят первый адрес, а получение списка файлов (s3:ListBucket) — второй. Отсюда и классическое «политику написал, файл скачивается, а список не отдаётся».
Политики бывают двух видов, и эта пара важна:
- Identity-based (политика на личности) — привязана к пользователю или роли. Читается как «этой роли можно читать из этого бакета».
- Resource-based (политика на ресурсе) — привязана к самому ресурсу. Читается наоборот: «этот бакет разрешает доступ такой-то роли или аккаунту». Такие политики нужны, например, чтобы открыть доступ из другого аккаунта или для сервисов вроде S3 и очередей SQS.
Как AWS принимает решение, можно свести к трём правилам:
- По умолчанию запрещено всё (это называется implicit deny, неявный запрет). Если ни одна политика явно не разрешила действие — оно запрещено.
- Доступ разрешается, только если есть явный
Allow. Внутри одного аккаунта хватает одного Allow — в identity-политике или в resource-политике, неважно в какой. Между аккаунтами разрешить должны обе стороны: identity-политика у того, кто обращается, и resource-политика у ресурса. Исключение, на котором спотыкаются все, — KMS (сервис ключей шифрования): там политика самого ключа обязана разрешить доступ, и одной политики на роли не хватит никогда. - Явный
Denyсильнее любогоAllow. Если хоть где-то стоит запрет на это действие — всё, доступа нет, и никакие разрешения это не перебьют.
Дополнительно у каждого правила можно задать блок Condition (условие), который ещё сильнее сужает доступ: «только если запрос пришёл из такой-то сети», «только с подтверждением через MFA (второй фактор)», «только с шифрованием». В JSON это выглядит так — правило сработает только при входе с MFA:
"Condition": { "Bool": { "aws:MultiFactorAuthPresent": "true" } }
И есть ещё два механизма, которые режут права сверху — про них полезно знать заранее, потому что именно они объясняют самые загадочные отказы. SCP (service control policy) — правило уровня AWS Organizations: оно ничего не разрешает, а ставит потолок на весь дочерний аккаунт, и то, что не проходит по SCP, внутри аккаунта не включить ничем. Permissions boundary — такой же потолок, только навешенный на конкретную роль или пользователя. Когда Allow вроде есть, а доступа нет, «где-то выше» — это обычно одно из этих двух.
Least privilege — минимум прав
Это главный принцип всей безопасности IAM: давать ровно столько прав, сколько нужно для задачи, и ни строчкой больше.
Самый частый дефект новичка — написать "Action": "*" и "Resource": "*", то есть «можно всё со всем». Так делают «чтобы не возиться» — и именно это потом превращается в инцидент: одна утёкшая такая роль открывает злоумышленнику весь аккаунт.
На практике least privilege — это итеративный процесс, а не разовая настройка:
- Начните узко — дайте минимум, который точно нужен.
- Запустите, посмотрите, чего не хватает.
- Добавьте недостающее. Повторяйте.
Второй шаг — тот, из-за которого процесс обычно и останавливается, поэтому разберём его по инструментам.
Где видно отказ. Каждый отказанный вызов попадает в журнал вызовов API — CloudTrail. Искать надо записи с полем errorCode равным AccessDenied (иногда UnauthorizedOperation — так отвечает часть вызовов к сети и машинам). В журнале же видно, кто вызывал (userIdentity), что (eventName) и с каким ресурсом, — то есть ровно то, чего не хватает политике.
aws cloudtrail lookup-events --lookup-attributes AttributeKey=EventName,AttributeValue=GetObject \
--max-results 20 --query 'Events[].CloudTrailEvent' --output text | jq 'select(.errorCode)'
Что читать в самом сообщении об отказе. Современный текст отказа от AWS не абстрактный — он называет и личность, и действие, и, главное, какой вид политики запретил:
User: arn:aws:sts::123456789012:assumed-role/orders-task/abc is not authorized to perform:
secretsmanager:GetSecretValue on resource: arn:aws:secretsmanager:eu-central-1:123456789012:secret:orders/db-AbCdEf
because no identity-based policy allows the secretsmanager:GetSecretValue action
Последняя строка и есть подсказка, где чинить. no identity-based policy allows — не хватает прав у самой роли, добавляйте действие в её политику. with an explicit deny in a resource-based policy — запрет стоит на стороне ресурса (например, в политике бакета), и права роли тут не помогут. with an explicit deny in a service control policy — запрет на уровне организации, и разрешить его внутри аккаунта нельзя вовсе, надо идти к тем, кто управляет организацией. Эти три варианта требуют совершенно разных действий, и различить их можно только прочитав сообщение целиком, а не первое слово AccessDenied.
Чем сузить уже выданное. У IAM есть два штатных инструмента, и оба стоят того, чтобы знать их по имени.
Last Accessed — на странице роли или политики AWS показывает, какими сервисами и действиями роль реально пользовалась за последние месяцы. Всё, чем не пользовались ни разу за девяносто дней, — первый кандидат на удаление из политики.
IAM Access Analyzer — отдельный сервис, который делает две разные полезные вещи. Первая: находит ресурсы, доступные снаружи аккаунта или организации (публичный бакет, роль с доверием к чужому аккаунту, очередь, открытая всем) — это регулярная проверка, которую включают один раз на организацию. Вторая, более интересная для этого раздела: генерация политики по журналу вызовов. Указываете роль и период — анализатор читает CloudTrail и составляет политику ровно из тех действий, которые роль совершала:
IAM → Roles → orders-task → Generate policy → период и источник CloudTrail
Получившуюся политику не прикладывают слепо: в период могли не попасть редкие операции (ежемесячный отчёт, аварийный путь), и их надо дописать руками. Но как отправная точка вместо "Action": "*" это то, что превращает «сужу права» из недельной задачи в получасовую.
Да, это дольше, чем выдать всё сразу. Но «узко и по факту» — это та граница, которая отделяет нормальную работу от заголовка про очередную утечку данных.
STS и временные учётные данные
За всеми временными учётными данными стоит отдельный сервис — STS (Security Token Service, сервис выдачи токенов безопасности). Когда кто-то «принимает роль», под капотом вызывается операция AssumeRole, и STS возвращает короткоживущий набор: access key, secret key и токен сессии. По умолчанию они живут час, максимум можно настроить до 12 часов. Оговорка на будущее: если роль принимают из-под другой роли (так часто выходит при доступе между аккаунтами), потолок жёсткий — час, и никакая настройка его не поднимет.
Команда вручную выглядит так:
aws sts assume-role \
--role-arn arn:aws:iam::123456789012:role/my-app-role \
--role-session-name demo-session
Самое полезное для новичка — понять, что на этом механизме построено почти всё:
- Роль виртуальной машины (instance role) незаметно дёргает STS за вас — SDK сам получает и обновляет учётные данные, вам не надо ничего писать.
- В Kubernetes (EKS) то же самое делают механизмы IRSA или более новый Pod Identity — они выдают поду временные учётные данные роли.
- Доступ между аккаунтами — это assume роли в чужом аккаунте.
- Вход через корпоративную учётку (федерация) — тоже выдача временных учётных данных.
Как только в голове укладывается «учётные данные временные, и берутся они через assume» — большинство вопросов «а откуда сервис вообще берёт доступ без ключей в коде» отпадает само.
Доступ между аккаунтами
В AWS аккаунты — это основная граница изоляции: по умолчанию из одного аккаунта в другой не достучаться никак. Когда такой доступ всё же нужен (например, сервис из аккаунта A должен читать данные в аккаунте B), его делают через роль, а не через общие ключи.
Схема такая:
- В аккаунте-владельце ресурса (B) заводят роль.
- К роли цепляют trust policy (политику доверия) — она говорит «эту роль разрешено принимать аккаунту A».
- К той же роли цепляют identity-политику с нужными правами (например, чтение бакета).
- Сервис из аккаунта A вызывает
AssumeRoleдля этой роли, получает временные учётные данные и работает с ними.
Важно: между аккаунтами не передают общие ключи. Доверие настраивается декларативно через trust policy, а реальный доступ всегда идёт через временные учётные данные.
Где это применяется
IAM — это слой «кто что может делать» поверх сетевого слоя «кто до кого вообще может достучаться». Вместе они дают полноценную защиту: минимальная сеть плюс минимальные права. Поэтому осваивать их стоит в паре.
Где вы столкнётесь с IAM сразу:
- Любой ваш сервис в облаке (виртуальные машины, бессерверные функции, контейнеры) получает доступ к другим сервисам через роль.
- Конвейеры доставки кода (CI/CD) тоже работают через роли, а не через зашитые ключи — это разбирается в принципах конвейера доставки.
- В Kubernetes доступ подов к облачным сервисам настраивается через роли — см. деплой и конфигурацию.
Типичные ошибки новичков, которых стоит избегать с первого дня:
- Класть долгоживущие ключи пользователя в код или переменные окружения вместо использования роли.
- Выдавать
"*"вActionилиResource«чтобы заработало», а потом забыть сузить. - Удивляться, что доступа нет, хотя
Allowесть — почти всегда виноват явныйDenyгде-то выше или забытый implicit deny (нигде не разрешили). - Хранить ключи в общем доступе для связи между аккаунтами вместо настройки роли с trust policy.
Глубже: управляемые политики и встроенныерасширенное
Политику можно приложить двумя способами, и разница видна не сразу, а через полгода.
Управляемая политика (managed) — отдельный объект с именем, который можно приложить к нескольким ролям и пользователям. Правишь в одном месте — меняется у всех. У них есть версии, и можно откатиться на предыдущую.
Встроенная политика (inline) — документ, вписанный прямо в роль или пользователя. Существует только вместе с ним, удаляется вместе с ним и никуда больше не прикладывается.
Что выбирают: почти всегда управляемую. Встроенная оправдана в одном случае — когда права настолько специфичны для этой роли, что отдельный объект только запутает, и важно, чтобы политика исчезла вместе с ролью.
И отдельно про готовые политики AWS. Кроме ваших есть набор готовых, написанных самой AWS (их видно по префиксу arn:aws:iam::aws:policy/). Практика «навесил готовую из списка, потом разберусь» — то, с чего реально начинают, и знать про эти политики надо две вещи.
Первая: самые употребительные из них — очень широкие. AdministratorAccess — это буквально «всё со всем». PowerUserAccess — всё, кроме управления правами. ReadOnlyAccess — чтение всего, включая содержимое хранилищ и значения параметров; это не безобидная политика, как кажется по названию. Есть и осмысленные узкие: AmazonS3ReadOnlyAccess, AmazonRDSDataFullAccess.
Вторая: их нельзя менять. Если готовая политика почти подходит, но нужно чуть сузить, её копируют в свою управляемую политику и правят копию. И AdministratorAccess, выданный «на время, чтобы разобраться», надо снимать в тот же день — эта формулировка и есть самая частая причина того, что через год у половины ролей права администратора.
Глубже: IAM глобаленрасширенное
Мелкая деталь, которая экономит час непонимания: почти всё в AWS привязано к региону, а IAM — нет. Роли, политики, пользователи, поставщики входа существуют в аккаунте целиком и видны из любого региона.
Отсюда две вещи. Роль, созданную «во Франкфурте», не нужно создавать заново «в Ирландии» — она уже есть, потому что региона у неё нет вовсе. И обратное: удаление роли действует сразу везде, поэтому «удалю, тут же ничего нет» — плохая идея, если в другом регионе на неё что-то ссылается.
К слову, журнал вызовов API из предыдущего раздела, наоборот, региональный: вызовы IAM (они обслуживаются в Северной Вирджинии) ищут именно там, а не в своём рабочем регионе. Это вторая половина того же недоумения — «отказ был, а в журнале пусто».
Коротко
- Root стоит вне IAM: второй фактор, никаких ключей, отдельный администратор и запись о том, у кого есть доступ.
- Людям пользователи (лучше вход через Identity Center), программам и автоматизации роли: ключи пользователя живут вечно и утекают, учётные данные роли живут час и обновляются сами.
- Политика это JSON из Effect, Action, Resource и Condition; identity-политика висит на роли, resource-политика на ресурсе, а хвост /* в ARN отделяет объекты от самого бакета.
- Решение принимается так: по умолчанию запрет, нужен явный Allow (между аккаунтами с обеих сторон), явный Deny сильнее всего, а SCP и permissions boundary режут права сверху.
- Управляемые политики вместо встроенных; готовые AdministratorAccess и ReadOnlyAccess шире, чем кажутся, их копируют и сужают, а не правят.
- Минимум прав это процесс: отказ ищут в CloudTrail по AccessDenied, текст отказа называет вид политики, Last Accessed и Access Analyzer показывают, что сузить.
- Временные учётные данные выдаёт STS через AssumeRole: на нём стоят роль машины, IRSA и Pod Identity, доступ между аккаунтами через trust policy и федерация.
- IAM глобален, а журнал вызовов IAM живёт в Северной Вирджинии: «отказ был, а в журнале пусто» лечится сменой региона в CloudTrail.
Что почитать дальше
- Безопасность и наблюдаемость — где хранят секреты и ключи шифрования.
- Основы инфраструктуры как кода — роли и политики как код вместо консоли.
- Сеть в AWS — первый слой защиты: кто до кого дотянется.
- Учётные записи и права в облаке — общая модель для всех провайдеров.