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

Kubernetes RBAC

RBAC в Kubernetes — это deny-by-default, но грабли в выдачах: wildcard-глагол, право создавать поды или привязка cluster-admin тихо равны захвату кластера. Наименьшие привилегии здесь — дисциплина по каждому глаголу, а не галочка.

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

Коллега в три часа ночи отлаживает капризный деплой, и самый быстрый способ убрать ошибку — однострочник, который хоть раз набирал каждый: kubectl create clusterrolebinding ci-debug --clusterrole=cluster-admin --serviceaccount=ci:runner. Пайплайн зеленеет, тикет закрывается, никто это не откатывает. Через полгода под этого CI-раннера пробивают через несвязанный баг в приложении — и поскольку токен его service-account примонтирован в /var/run/secrets/kubernetes.io/serviceaccount/token и привязан к cluster-admin, атакующий получает не один под. Он получает каждый секрет в каждом неймспейсе, возможность запланировать привилегированный под на любой ноде и путь к самому хосту. RBAC всё это время был включён. Он сказал «да», потому что кто-то ему так велел.

К концу урока ты сможешь прочитать пару Role/RoleBinding и точно сказать, что она выдаёт, распознать три привязки, которые тихо равны захвату кластера, и спроектировать service-account, который делает свою работу и ничего сверх того.

Четыре существительных, и почему два из них — ловушка

RBAC в Kubernetes собран ровно из четырёх видов объектов, и вся модель безопасности живёт в том, как ты их комбинируешь.

  • Role — это неймспейс-ограниченный список правил: кортежи apiGroups, resources и verbs (get, list, watch, create, update, patch, delete). Role не выдаёт ничего, пока не привязана.
  • ClusterRole — та же форма, но в области всего кластера: она может называть кластерные ресурсы (nodes, persistentvolumes) и переиспользоваться между неймспейсами.
  • RoleBinding прикрепляет Role (или ClusterRole) к субъекту внутри одного неймспейса.
  • ClusterRoleBinding прикрепляет ClusterRole к субъекту по всему кластеру.

Субъект — обычно ServiceAccount, та идентичность, под которой работает каждый под. Вот что упускают: по умолчанию каждый под получает токен service-account, примонтированный в его файловую систему, и этот токен и есть учётка пода к API-серверу. Поэтому радиус поражения любой выдачи RBAC — это «всё, что атакующий сможет запустить в поде, использующем этот service-account». RBAC действительно работает по принципу deny-by-default: свежий service-account не может практически ничего. Но опасность не в дефолте. Она в правах, которые ты добавляешь, потому что две комбинации превращают мелкую ошибку в полную компрометацию: ClusterRoleBinding (на весь кластер, а не на один неймспейс) и встроенная ClusterRole cluster-admin (каждый глагол на каждом ресурсе, включая *).

Грабли cluster-admin, по порядку

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

ГраблиЧто реально выдаётПочему случаетсяФикс по наименьшим привилегиям
привязка cluster-adminКаждый глагол на каждом ресурсе, все неймспейсы — полный захватОтладка «убрать ошибку»; скопированные значения HelmУзкая Role с 3-4 реально используемыми глаголами
wildcard глагол/ресурс (*)Сегодняшние ресурсы и каждый будущий, что добавит оператор«Пока не знаю точные глаголы, ужму позже»Перечисли глаголы явно; не отгружай verbs: [”*“]
create pods / pods/execЗапланировать привилегированный под или войти exec — пивот к хосту/другим SAВыглядит как обычный глагол приложения; ревьюеры пропускаютСчитай create pods привилегированным; закрой Pod Security + политикой
get/list secretsЧитать каждый секрет в области, включая токены других SA«Приложению нужен один секрет» → выдали на весь глаголОграничь через resourceNames; предпочти projected/CSI-секреты
escalate / bind на роляхВыдать себе права, которых нет — повышение привилегийСпрятано в ClusterRole оператора, которую никто не аудитНикогда не выдавай escalate/bind рабочим нагрузкам

Сквозная мысль: в RBAC нет правила deny. Нельзя «вычесть» право задним числом — субъект может делать то, что даёт объединение всех привязанных правил, и если хоть одно говорит «да», то это «да». Именно поэтому избыточная выдача так опасна: нет страховочного правила, которое тебя поймает, поэтому наименьшие привилегии приходится обеспечивать в момент записи, глагол за глаголом. Поведение агрегации усугубляет это: ClusterRole с меткой rbac.authorization.k8s.io/aggregate-to-edit: "true" автоматически вливаются во встроенную роль edit, так что оператор кастомного ресурса может тихо расширить то, что могут делать пользователи с привязкой edit, не трогая твои привязки.

Частая ошибка

Самое частое реальное повышение привилегий — не сам cluster-admin, а create pods в сочетании с отсутствием ограничений Pod Security. Если service-account может создать под, атакующий, владеющий этим SA, может запланировать под с примонтированным hostPath: / или hostPID: true, считать учётки kubelet с ноды и пивотнуть к каждой рабочей нагрузке на этой ноде — включая те, у которых токены куда мощнее. Поэтому «может ли этот SA создавать поды?» — самый сигнальный вопрос в ревью RBAC, и поэтому create pods обязан идти в паре с профилем Pod Security Admission restricted, чтобы вообще что-то значить.

Проектирование service-account по наименьшим привилегиям

Зрелый рефлекс — строить выдачи снизу вверх от наблюдаемой потребности, а не сверху вниз от удобства. Порядок работы:

  1. Старт от deny. У нового ServiceAccount нет прав. Сопротивляйся желанию привязать широкую встроенную роль «чтобы разблокироваться».
  2. Перечисли реальные глаголы. Запусти нагрузку, зафиксируй, какие вызовы API она делает (аудит-логи или kubectl auth can-i --list), и выдай ровно их — get/list/watch на конкретных ресурсах, без wildcard.
  3. Предпочитай Role вместо ClusterRole, RoleBinding вместо ClusterRoleBinding. Держи выдачу в одном неймспейсе, если ресурс не является истинно кластерным. Неймспейс-выдача ограничивает радиус поражения одним неймспейсом.
  4. Ограничивай секреты через resourceNames. Если приложению нужен один секрет — назови его; не выдавай весь глагол secrets.
  5. Выключай монтаж токена, когда он не нужен. Поставь automountServiceAccountToken: false на подах, которые никогда не зовут API-сервер — большинство подов приложений не зовёт, а непримонтированный токен нельзя украсть.
  6. Аудит через kubectl auth can-i. Перед отгрузкой спроси кластер напрямую: kubectl auth can-i create pods --as=system:serviceaccount:app:web -n app должно вернуть no.
Выбери лучший вариант

Бэкенд-поду для старта нужно прочитать один ConfigMap и один Secret в своём неймспейсе. CI красный, потому что SA не может их прочитать. Выбери верную выдачу.

Викторина

Role выдаёт `verbs: [list]` на `secrets` в одном неймспейсе, привязана к ServiceAccount пода. Под скомпрометирован. Что атакующий сделает с примонтированным токеном?

Викторина

Почему `create pods` — настолько сигнальное право для пометки в ревью RBAC, даже без явной привязки cluster-admin?

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

Упорядочь шаги проектирования service-account по наименьшим привилегиям, от первого к последнему:

  1. 1 Старт от deny — свежий ServiceAccount без привязок
  2. 2 Перечисли точные глаголы, которые нагрузка реально вызывает
  3. 3 Выдай неймспейс-ограниченную Role (предпочти Role вместо ClusterRole), ограниченную resourceNames
  4. 4 Привяжи её через RoleBinding к этому одному ServiceAccount
  5. 5 Проверь через `kubectl auth can-i`, что ничего лишнего не разрешено
Вспомните перед уходом
  1. 01
    Пройди шаг за шагом, как одна привязка ClusterRoleBinding к cluster-admin на CI service-account превращается в полную компрометацию кластера при пробое одного пода.
  2. 02
    Почему `list secrets` опаснее, чем кажется, и какая безопасная альтернатива по наименьшим привилегиям?
Итог

RBAC в Kubernetes собран из четырёх объектов — Role и ClusterRole (правила глагол/ресурс) плюс RoleBinding и ClusterRoleBinding (которые прикрепляют их к субъекту, обычно ServiceAccount). Модель действительно deny-by-default и только разрешающая: свежий SA не может ничего, а объединение всех привязанных правил — это то, что может его авто-примонтированный токен, и нет deny-правила, чтобы отозвать выдачу. Поэтому грабли — это всегда переизбыточные выдачи, а не дефолты: привязка cluster-admin (каждый глагол везде), wildcard-глагол, покрывающий и будущие ресурсы, create pods (запланировать привилегированный под, пивотнуть к ноде), list secrets (прочитать каждый секрет, включая чужие токены) и escalate/bind (выдать себе больше). Наименьшие привилегии — дисциплина момента записи: старт от deny, перечисли реальные глаголы, предпочти неймспейс-ограниченные Role + RoleBinding, ограничь секреты через resourceNames, выключи монтаж токена, когда он не нужен, и проверь через kubectl auth can-i. Теперь, видя привязку в ревью, твой первый вопрос: кто субъект, кластерная ли она и может ли создавать поды или читать секреты?

Практика

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

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

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

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

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

Trademarks belong to their respective owners. Editorial reference only.