open atlas
↑ К треку
Безопасность облака и инфраструктуры CLOUD · 01 · 02

Least-privilege policies

Узкая политика выдаёт ровно те действия и ресурсы, что нужны роли. Подстановочные знаки (`Action:*`, `Resource:*`) кажутся удобными и тихо становятся радиусом поражения. Permission boundary ограничивает потолок прав роли — ограждение, нужное least privilege на масштабе.

CLOUD Middle ◷ 15 min
Уровень
ОсновыJuniorMiddleSenior

Сервису нужно прочитать один объект конфигурации из одного S3-бакета. В тикете написано «выдайте роли доступ к S3», поэтому кто-то прикрепляет AmazonS3FullAccess — управляемую политику, дающую s3:* на Resource: *. Работает, деплой зелёный, все забыли. Через два года ключ доступа этой же роли утекает через переменную окружения, попавшую в отчёт о падении. Атакующий получает не один объект конфигурации. Он получает s3:GetObject на каждый бакет в аккаунте, s3:DeleteBucket, s3:PutBucketPolicy, чтобы сделать любой бакет публичным, и s3:PutObject, чтобы подложить payload в бакет вашего статического сайта. Один подстановочный знак, выданный ради чтения одного объекта, стал всей плоскостью данных аккаунта. Никто не решал давать сервису такую власть. Политика просто никогда не сказала «нет».

К концу урока ты будешь знать, как написать политику, выдающую ровно те действия и ресурсы, что нужны роли, почему подстановочные знаки превращают маленькую утечку в крупный пробой и как permission boundary ограничивает ущерб даже тогда, когда кто-то всё равно написал небрежную политику.

Как на самом деле выглядит узкая политика

Least privilege — это одно правило: у субъекта должны быть ровно те права, что нужны для его работы, ровно столько времени, сколько нужно, — и ни одним правом больше. Сложность не в принципе, а в том, что удобная и правильная политики выглядят почти одинаково, и удобная отгружается быстрее.

IAM-политика отвечает на два вопроса для каждого запроса: какие действия (s3:GetObject, dynamodb:Query) и на каких ресурсах (конкретный ARN бакета, конкретная таблица). Узкая политика называет оба. Сервис, читающий один объект конфигурации, должен держать вот это:

{
  "Effect": "Allow",
  "Action": "s3:GetObject",
  "Resource": "arn:aws:s3:::acme-config/service-x/*"
}

Одно действие, один префикс ресурса. Если этот ключ утечёт, атакующий получит доступ на чтение к одной папке в одном бакете — сдержанный, скучный инцидент. Радиус поражения — это политика, и ты намеренно написал политику маленькой.

Рефлекс, который надо выработать: начни с deny, добавь единственное действие, которое можешь назвать, ограничь его единственным ARN, который можешь назвать, и остановись. Каждый раз, тянясь к *, ты говоришь «я не знаю, какие действия или ресурсы здесь нужны», — а атакующий, укравший учётку, отлично знает, что делать с этой неопределённостью.

Чем кусаются подстановочные знаки

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

Action: "s3:*" расширяет, что может субъект. Сервису нужен был GetObject; подстановочный знак заодно вручил ему PutObject, DeleteObject, PutBucketPolicy, PutBucketAcl. Теперь учётка для чтения может перезаписать данные, удалить их или сделать приватный бакет публичным. Resource: "*" расширяет, где это применяется — с одного бакета на каждый бакет, включая ещё не существующие. Два знака компонуются: s3:* на * — это полный контроль над всем твоим объектным хранилищем из учётки, выданной ради чтения файла конфигурации.

Есть и более тихая цена: подстановочные знаки делают аудит невозможным. Когда политика говорит s3:GetObject на именованном ARN, рецензент может прочитать её и точно знать, что роль умеет. Когда она говорит s3:* на *, единственный честный ответ на «что эта роль может?» — «всё со всем», и радиус поражения такого размера никто не способен осмыслить. Узкие политики самодокументируемы; подстановочные знаки стирают документацию.

Почему это работает

Почему iam:* заслуживает особого страха, даже выше s3:*? Потому что IAM-права самоусиливаются. Роль с iam:PutRolePolicy или iam:AttachRolePolicy может выдать себе — или любой роли — любое право в аккаунте. Это повышение привилегий: атакующему не нужно опасное право напрямую, нужно лишь право его назначать. Роль с iam:* и больше ничем фактически является админом аккаунта, потому что шаг первый — написать себе админскую политику. Именно поэтому и существует следующее ограждение — permission boundary: чтобы сделать «выдай себе больше» невозможным, даже когда iam:PutRolePolicy присутствует.

Permission boundaries: ограждение, нужное least privilege на масштабе

Написать одну узкую политику легко. Удержать узкими все политики, по сотням ролей и десяткам инженеров, у каждого из которых есть право создавать роли, — вот настоящая проблема. Её решают permission boundaries.

Permission boundary — это политика, прикреплённая к субъекту, задающая максимум прав, которые он когда-либо может иметь, — потолок, а не выдача. Эффективные права субъекта — это пересечение его identity-политик и его boundary: право разрешено, только если обе его разрешают. Так что даже если разработчик (или атакующий, скомпрометировавший роль разработчика) прикрепит AdministratorAccess к новой роли, boundary обрежет это обратно до того, что boundary разрешает.

Канонический сценарий — делегированное создание ролей. Ты позволяешь разработчикам создавать роли для собственных сервисов — это хорошо для скорости, — но требуешь, чтобы каждая создаваемая ими роль несла контролируемый тобой boundary. Теперь разработчик может выдать своему сервису s3:GetObject на свой бакет, но не может создать роль с iam:* или доступом к продакшен-базе, потому что boundary это запрещает, а пересечение побеждает. Boundary превращает «доверяй каждому инженеру написать идеальную политику» в «доверяй одной boundary-политике и дай инженерам быстро двигаться внутри неё».

Identity-политика говоритBoundary говоритЭффективно (пересечение)Почему
s3:GetObjects3:*s3:GetObjectОбе разрешают; побеждает более узкая выдача
s3:*s3:GetObject, s3:PutObjects3:GetObject, s3:PutObjectBoundary — это потолок; подстановочный знак обрезан
iam:* (админ)без iam:*запрещеноЭскалация заблокирована: boundary её не разрешал
dynamodb:Queryтолько s3:*запрещеноНет в boundary → нет пересечения → нет доступа

Boundary не заменяет узкие политики — это страховочный рубеж. Identity-политика — место, где ты выражаешь намерение (эта роль читает конфиг); boundary — место, где ты выражаешь предел (ни одна роль в этом аккаунте не должна трогать IAM или продакшен-данные). Нужны оба: узкие политики, чтобы типовой случай был корректен, и boundary, чтобы единственная небрежная политика не стала компрометацией аккаунта.

Как рецензировать политику по-сеньорски

Когда политика приходит к тебе на ревью, ты сканируешь три вещи по порядку. Первое — подстановочные знаки: любой Action: "*", "s3:*" или Resource: "*" — это вопрос, не обязательно баг, но он должен быть обоснован, и «так было проще» не обоснование. Второе — опасные глаголы: iam:*, iam:PutRolePolicy, iam:PassRole, sts:AssumeRole на широком ресурсе, *:Delete* — всё, что может менять чужие права или уничтожать данные. Третье — охват ресурсов: называет ли каждый statement конкретные ARN, которых касается, или оставляет Resource: "*", потому что никто их не перечислил?

Сеньорский ход — снижать права со временем, а не только пропускать новые. Облачные провайдеры отдают данные access-analyzer / last-accessed: какие действия роль реально использовала за последние 90 дней. Роль с s3:*, которая вызывала только GetObject и ListBucket, сама сообщает свою настоящую политику — сгенерируй узкую из наблюдаемого использования и замени подстановочный знак. Least privilege — не разовая выдача, которую ты получаешь правильной при создании; это храповик, который ты подтягиваешь по мере того, как узнаёшь, что роль на самом деле делает.

Выбери лучший вариант

У сервисной роли сейчас `AmazonS3FullAccess` (`s3:*` на `*`), но по данным last-accessed она вызывала только `s3:GetObject` и `s3:ListBucket` на одном бакете. Выбери правильный способ привести её к least privilege.

Викторина

Единственное право роли — `iam:PutRolePolicy` на `*`. Ни `s3:*`, ни `dynamodb:*`, ничего больше. Насколько она опасна?

Викторина

У роли identity-политика разрешает `s3:*`, а permission boundary разрешает только `s3:GetObject` и `s3:ListBucket`. Роль пробует `s3:DeleteObject`. Что произойдёт и почему?

Расставь шаги по порядку

Упорядочь шаги, чтобы привести пере-привилегированную роль (`s3:*` на `*`) к least privilege:

  1. 1 Вытяни данные last-accessed / access-analyzer, чтобы увидеть, какие действия роль реально использовала
  2. 2 Напиши политику, перечисляющую только эти наблюдаемые действия
  3. 3 Ограничь Resource каждого statement конкретными ARN, которых роль касалась
  4. 4 Замени политику с подстановочным знаком и прикрепи permission boundary как потолок
  5. 5 Перепроверь last-accessed через цикл, чтобы поймать действие, которое ты срезал слишком агрессивно
Вспомните перед уходом
  1. 01
    Объясни, почему один подстановочный знак вроде `s3:*` на `Resource: *` так опасен, даже когда роль всегда лишь читает один объект.
  2. 02
    Что такое permission boundary, чем он отличается от identity-политики и почему это контроль, делающий least privilege выживаемым на масштабе?
Итог

Least privilege — это одно правило: субъект держит ровно те действия, на ровно тех ресурсах, что ему нужны, — и ничего больше. Ловушка в том, что удобная и правильная политики выглядят почти одинаково, а удобная (AmazonS3FullAccess, s3:* на *) отгружается быстрее. Подстановочные знаки — доминирующий режим отказа: Action: * расширяет, что роль умеет, Resource: * расширяет, где, и вместе они превращают утёкшую учётку для чтения в полный контроль над объектным хранилищем, стирая любую возможность аудита радиуса поражения. IAM-глаголы вроде iam:PutRolePolicy ещё хуже, потому что право выдавать права — это право выдать себе всё; это эскалация привилегий. Permission boundaries — ограждение, делающее это выживаемым на масштабе: потолок, чьё пересечение с identity-политикой обрезает любую пере-выдачу, так что делегированное создание ролей остаётся быстрым без доверия каждому инженеру написать идеальную политику. И least privilege — это храповик, а не разовая выдача: со временем снижай права к наблюдаемому last-accessed использованию. В следующий раз, увидев s3:* на роли, читающей один бакет, твой первый вопрос: что эта роль реально вызывала и какой один ARN я могу ей задать?

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 7 завершено
Связанные уроки
углубляется в

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

Примени это

Примени этот урок в реальном проекте.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources2
expand
  1. 01
  2. 02

Trademarks belong to their respective owners. Editorial reference only.