Cloud IAM — это система Google Cloud, которая отвечает на один вопрос: «кто и что может делать». Хотите прочитать файл из хранилища, запустить машину, отправить сообщение в тему — каждый раз GCP сверяется: а разрешено ли вам это.

Звучит как скучная бюрократия, но именно тут происходит большинство аварий в облаке. Чаще всего ломают не сложным взломом, а потому что кому-то выдали слишком много прав или JSON-ключ сервисного аккаунта попал в открытый репозиторий. Полчаса на понимание IAM выгоднее, чем потом разбирать инцидент.

код в облаке сервер метаданных какой у меня токен? токен сервисного аккаунта на час

Внутри облака ключей не бывает: к машине или поду привязан сервисный аккаунт, и код берёт временный токен у сервера метаданных, а библиотеки Google делают это сами. Снаружи ту же роль играет федерация удостоверений, и JSON-ключ остаётся для упрямого случая с датой пересмотра.

Обязательно

Пользователи против сервисных аккаунтов

Первое различие, в котором путаются новички, — кому вообще выдают доступ.

Пользователь — это человек: аккаунт Google или корпоративная учётка через federation. Люди заходят в консоль, что-то настраивают, смотрят.

Сервисный аккаунт (service account) — учётная запись для программ и виртуальных машин, а не для человека. Её задача — дать доступ вашему коду. Аналог роли, которую «надевает» сервис, в AWS.

Ключевое правило: для программ, серверов и автоматизации используют сервисные аккаунты, а не личные учётки.

Служебная учётная запись — это и личность, и ресурс

Особенность GCP, из которой растёт половина рабочих приёмов: служебная учётная запись существует в двух ролях одновременно.

Как личность — ей выдают права на ресурсы: «этой учётной записи можно читать из хранилища».

Как ресурс — права выдают на неё саму: «этому человеку можно пользоваться этой учётной записью». И вот вторая половина обычно и остаётся незамеченной.

Отсюда два ключевых механизма.

Работа от имени учётной записи (impersonation). Человек или другая учётная запись может получить временный токен служебной учётной записи и выполнять действия от её имени — без всяких ключей:

gcloud storage ls gs://orders-reports \
  --impersonate-service-account=orders-app@acme-prod.iam.gserviceaccount.com

Для этого нужна роль создателя токенов (roles/iam.serviceAccountTokenCreator) на эту учётную запись. Это и есть правильный ответ на вопрос «как локально отладить код, который в облаке работает от служебной учётной записи»: вы работаете с теми же правами, ничего не скачивая и не храня. Ключ не создаётся вовсе.

Право «пользоваться» учётной записью (roles/iam.serviceAccountUser). Оно нужно, чтобы присоединить учётную запись к ресурсу — к машине, к сервису, к задаче. И здесь прячется путь повышения прав, о котором стоит знать: человек с этим правом может создать машину с мощной служебной учётной записью и выполнить на ней свой код — то есть получить её права, не имея их напрямую.

Практические выводы: право «пользоваться» выдают узко (на конкретную учётную запись, а не на проект), мощные учётные записи не держат в проектах, где у многих есть право создавать ресурсы, и предпочитают работу от имени — она оставляет след в журнале аудита с указанием, кто именно действовал от имени учётной записи.

Права выдают группам

То же правило, что и в любом облаке, и в GCP оно особенно заметно, потому что привязок много: роли выдают группам, а не людям поимённо.

gcloud projects add-iam-policy-binding acme-orders-prod \
  --member="group:orders-developers@acme.com" --role="roles/run.developer"

Что это даёт: приём сотрудника — добавить в группу, уход — убрать; список прав человека виден как список его групп; привязок в политике проекта в разы меньше, и её вообще можно читать глазами.

Как раскладывают группы: по команде и среде (orders-dev, orders-prod с разными ролями), отдельно дежурные, отдельно читатели. Поимённые привязки остаются только как обоснованные исключения — и их видно в политике проекта, потому что там будет user: вместо group:.

Роли и привязки

Выдали доступ на весь проект, а нужен был один бакет — и сервис, у которого утёк ключ, читает всё. Чтобы права можно было резать точно, в Cloud IAM их выдают через пару «роль + привязка».

Роль (role) — набор разрешений. По ширине прав они делятся на три класса:

  • базовые (basic) — Owner, Editor, Viewer на весь проект (широкие, для практики почти всегда слишком грубые). Раньше их называли примитивными; в документации Google это слово больше не используется, искать нужно «basic roles»;
  • предопределённые (predefined) — узкие сервисные роли вида roles/storage.objectAdmin (объекты в хранилище), roles/cloudsql.client (подключение к базе), roles/pubsub.publisher (публикация в тему). Это то, что нужно на практике;
  • пользовательские (custom) — свой набор разрешений, когда предопределённых не хватает.

Привязка (binding) — назначение «кому — какую роль — на каком ресурсе». Роль выдают на организацию, папку, проект или отдельный ресурс, и права наследуются вниз: роль на проект действует на все ресурсы внутри него. Обычно доступ выдают на уровне проекта.

Важная деталь, на которой спотыкаются пришедшие из AWS: привязки умеют только разрешать. Политика ресурса — это сумма всех привязок: если хоть одна даёт право, право есть. Строчки «а вот этому — запретить», как explicit Deny в AWS, внутри неё не существует. Запреты в GCP живут отдельно — это deny-политики, их пишут отдельным документом, и проверяются они раньше разрешающих. Пока вы их не завели, единственный способ отобрать право — убрать роль.

Так выглядит привязка: сервисному аккаунту приложения заказов — роль на объекты хранилища во всём проекте:

gcloud projects add-iam-policy-binding my-project \
  --member="serviceAccount:orders-app@my-project.iam.gserviceaccount.com" \
  --role="roles/storage.objectAdmin"

После запуска команда печатает обновлённую политику проекта целиком — вашу строку в ней видно сразу. Проверить, что легло, можно через gcloud projects get-iam-policy my-project, а снимается привязка той же командой с remove-iam-policy-binding.

Доступ без ключей: metadata и Workload Identity

Главное правило: ваш код не должен носить с собой ключи. Как приложение получает доступ, зависит от того, где оно работает:

  • На виртуальной машине Compute Engine к ней привязывают сервисный аккаунт, и приложение получает временный токен прямо из сервера метаданных — без секретов в коде. Библиотеки Google находят его автоматически. Но одной роли тут мало: у машины есть ещё области доступа (access scopes), выбранные при её создании. Это второй фильтр поверх ролей, и классический тупик выглядит так: роль выдана, а вызов всё равно падает с отказом, потому что у машины области по умолчанию — например, хранилище только на чтение. Совет Google простой: ставьте машине полную область cloud-platform, а права режьте ролями IAM, чтобы они были в одном месте, а не в двух.
  • В GKE используют Workload Identity — механизм, который связывает Kubernetes ServiceAccount с сервисным аккаунтом GCP, и под получает временный токен по той же модели.
  • Извне облака (например, из CI не в GCP) раньше использовали JSON-ключ сервисного аккаунта — но это долгоживущий секрет и главный источник утечек. Современный способ — Workload Identity Federation: внешняя система (GitHub Actions, другой облачный провайдер) обменивает своё удостоверение на временный токен GCP без вечного ключа. Если ключ всё же нужен, его держат в защищённом хранилище, а не в git, и ротируют.

Правило: внутри облака — привязанный сервисный аккаунт и метаданные; federation вместо JSON-ключа; сам ключ — только там, где иначе никак.

Least privilege — минимум прав

Главный принцип всей безопасности: давать ровно столько прав, сколько нужно, и ни ролью больше.

Самый частый дефект новичка — выдать сервисному аккаунту Editor на весь проект «чтобы просто заработало». Так делают, чтобы не возиться, — и именно это потом превращается в инцидент: одна утёкшая учётка открывает весь проект.

Отдельная ловушка — сервисный аккаунт по умолчанию у Compute Engine. Исторически Google сам выдавал ему Editor на весь проект: машина, поднятая в два клика, работает с правами, которые вы бы ей руками никогда не дали. В организациях, созданных после 3 мая 2024 года, эта автоматическая выдача по умолчанию отключена (за неё отвечает ограничение iam.automaticIamGrantsForDefaultServiceAccounts), а вот в проектах постарше она осталась — стоит зайти и посмотреть, с какой ролью живёт аккаунт по умолчанию.

На практике least privilege — итеративный процесс: начните узко (только нужные предопределённые роли), запустите, посмотрите по отказам, чего не хватает, добавьте недостающую роль. Инструмент рекомендаций (IAM Recommender) подсказывает, какие выданные права реально не используются, — их стоит убирать.

Только не торопитесь с выводами после правки прав: изменения IAM применяются не сразу. Обычно новая роль начинает действовать через пару минут, иногда — через семь и дольше. Отказ сразу после выдачи роли почти всегда означает «ещё не доехало», а не «настроено неправильно», — подождите и повторите, а не выдавайте Editor от отчаяния.

Как читать отказ

Права выдавать научились — осталось разобраться, что делать, когда их не хватает. В GCP отказ выглядит так:

PERMISSION_DENIED: Permission 'storage.objects.get' denied on resource
'projects/_/buckets/orders-reports/objects/2026-09/report.csv' (or it may not exist)

Три части здесь полезны: какое разрешение не хватило (storage.objects.get), на каком ресурсе и оговорка «или он может не существовать» — GCP намеренно не различает «нет прав» и «нет ресурса», чтобы не выдавать существование объектов.

Дальше два инструмента.

Средство разбора политик (Policy Troubleshooter). Вы указываете, кто, какое разрешение и на каком ресурсе — и оно отвечает, есть ли доступ, и главное, почему: какая привязка его даёт или чего не хватает, с учётом наследования от организации и папок.

gcloud policy-intelligence troubleshoot-policy iam \
  --principal-email=orders-app@acme-prod.iam.gserviceaccount.com \
  --permission=storage.objects.get \
  --resource=//storage.googleapis.com/projects/_/buckets/orders-reports

Это первое, куда идут: оно экономит перебор ролей вручную и учитывает то, что человек обычно забывает — наследование и запреты.

Журналы аудита (Cloud Audit Logs). Все административные операции пишутся всегда; отказы видны там же, с указанием личности, разрешения и ресурса. Для операций с данными (чтение файла, запрос к базе) журналирование включается отдельно и стоит денег — поэтому по умолчанию отказ на чтении объекта в журнале не появится, и это стоит знать заранее.

И практический порядок разбора: прочитать текст отказа целиком → найти в нём разрешение → прогнать средство разбора политик → проверить, не действует ли запрет или ограничение организации (о них раздел ниже) → и только потом искать ошибку в коде.

Ключи можно запретить целиком

В списке типичных ошибок стоит долгоживущий ключ служебной учётной записи, и у этой ошибки есть механизм, который делает её невозможной: ограничение организации iam.disableServiceAccountKeyCreation.

Включённое, оно означает, что создать ключ нельзя — ни в консоли, ни командой, никому, включая владельца организации. А раз ключей нет, то нет и утечек ключей.

gcloud resource-manager org-policies enable-enforce \
  iam.disableServiceAccountKeyCreation --organization=123456789012

Как после этого работают те случаи, где раньше брали ключ:

  • Код в GCP — служебная учётная запись присоединена к ресурсу, токен приходит из метаданных. Ключ не нужен изначально.
  • Код вне GCP (другое облако, свой сервер, конвейер) — федерация удостоверений: внешняя личность получает временный токен GCP по доверию. Ключ не нужен.
  • Локальная разработка — работа от имени учётной записи (см. раздел выше). Ключ не нужен.
  • Совсем упрямый случай (старый инструмент, который умеет только ключ) — точечное исключение для одного проекта, с причиной и датой пересмотра.

Рядом полезно включить и срок жизни ключей (iam.serviceAccountKeyExpiryHours), если полный запрет пока невозможен: ключ перестаёт работать через заданное время, и «вечный ключ в репозитории» становится невозможным сам по себе.

Числа и границы

Несколько величин, которые полезно держать в голове.

Токен из метаданных живёт около часа (3600 секунд) и обновляется библиотекой автоматически. Практическое следствие: после отзыва прав у учётной записи работающее приложение может продолжать работать до истечения текущего токена — то есть «отозвали доступ» действует не мгновенно, а в пределах часа.

Число привязок в политике ограничено (порядка полутора тысяч на ресурс) — и это ещё один довод за группы: поимённые привязки заканчиваются быстрее, чем кажется, в большой организации.

Служебных учётных записей ограниченное число на проект (порядка сотни) — редко становится проблемой, но встречается в проектах, где заводят учётную запись на каждую задачу.

Предопределённые роли против своих. Предопределённая роль содержит набор разрешений, который меняет Google — обычно расширяет при появлении новых возможностей. Это удобно (не надо следить) и означает, что права могут незаметно вырасти. Своя роль содержит ровно то, что вы перечислили, и не меняется сама — зато следить за новыми разрешениями придётся вам. Отсюда практика: предопределённые роли для обычной работы, свои — для чувствительных мест, где точный список важнее удобства.

Где это применяется

Cloud IAM — это слой «кто что может делать» поверх сетевого слоя «кто до кого вообще может достучаться». Вместе они дают полноценную защиту: минимальная сеть плюс минимальные права.

Где вы столкнётесь с IAM сразу:

  • Любой ваш сервис (виртуальные машины, функции, контейнеры) получает доступ через привязанный сервисный аккаунт.
  • Конвейеры доставки кода работают через Workload Identity Federation, а не через зашитые JSON-ключи.
  • Секреты и шифрование — соседняя тема: где хранить пароли, в безопасности и наблюдаемости.

Типичные ошибки новичков:

  • Класть JSON-ключ сервисного аккаунта в код или git вместо привязки аккаунта к машине.
  • Выдавать Editor/Owner широко «чтобы заработало», а потом забыть сузить до предопределённых ролей.
  • Плодить JSON-ключи там, где работает Workload Identity Federation.
Дополнительно: при первом чтении можно пропустить

Глубже: где всё-таки запрет: IAM Deny и ограничения организациирасширенное

«Привязки умеют только разрешать» ставит вопрос, который задают все пришедшие из AWS: а как запретить? Например, запретить сотрудникам с широкой ролью удалять базы или запретить создавать ключи сервисных аккаунтов в принципе. Механизмов два, и оба живут отдельно от привязок.

Политики запрета IAM (IAM Deny policies). Отдельный тип политики, который проверяется раньше разрешений: если запрет совпал по субъекту и разрешению, доступа нет, какие бы роли ни были выданы. Пишут их на уровне организации или папки, для узкого набора разрешений (cloudsql.instances.delete для всех, кроме группы администраторов) и с исключениями по принципалам. Это не замена узким ролям, а страховка от широких: у команды остаётся Editor на своём проекте, но удалить прод-базу она не может.

Ограничения организации (organization policy). Правила о том, какие ресурсы вообще можно создавать и в каком виде, независимо от прав: запрет создавать ключи сервисных аккаунтов (iam.disableServiceAccountKeyCreation), запрет публичного доступа к бакетам (storage.publicAccessPrevention), запрет внешних адресов у машин (compute.vmExternalIpAccess), список разрешённых регионов (gcp.resourceLocations), обязательные защищённые машины. Их ставят на организацию и наследуют вниз, и это самый дешёвый способ закрыть половину типичных ошибок раздела ещё до того, как кто-то их совершит. Свежая организация без этих пяти ограничений это выбор, а не умолчание.

Периметр вокруг данных. Права отвечают «кто может», а не «откуда»: утёкшие учётные данные с правом на бакет читают его из любой точки интернета. VPC Service Controls рисуют периметр вокруг проектов и сервисов: вызов API хранилища или BigQuery проходит только изнутри периметра (из вашей сети или через приватный доступ), а снаружи отвергается даже с валидным токеном. Это защита от утечки данных, а не от ошибок прав, и её включают для проектов с персональными данными.

Как это укладывается с остальным: привязки дают минимум прав, запреты страхуют от широких ролей, ограничения организации запрещают опасные конфигурации, периметр закрывает доступ извне. Проверяют результат одним инструментом: анализатор политик показывает, кто и через что имеет разрешение на ресурс, с учётом наследования и запретов, и это первое, что открывают при вопросе «почему у него есть доступ».

Коротко

  • Людям пользователи, программам сервисные аккаунты; JSON-ключ в коде это главный источник утечек.
  • Права выдают парой роль плюс привязка на организацию, папку, проект или ресурс, и они наследуются вниз; узкие предопределённые роли вместо Editor.
  • Внутри облака код берёт токен из метаданных или через Workload Identity, снаружи через федерацию удостоверений; изменения прав применяются минуты.
  • Привязки только разрешают: запрет делают политики IAM Deny, опасные конфигурации закрывают ограничения организации, доступ извне отсекает периметр VPC Service Controls.

Что почитать дальше