GCP для инженеров AWS: как ваши инстинкты AWS применимы (и где они подводят)
Вы уже знаете, как организовывать аккаунты, выдавать разрешения и инициализировать состояние в AWS. Вот как делать то же самое в Google Cloud - концепции, которые легко переносятся, и четыре места, где ваша мышечная память AWS будет активно вводить вас в заблуждение.
Если вы свободно владеете AWS и теперь смотрите на Google Cloud, хорошая новость в том, что ~80% ваших инстинктов переносятся напрямую: существует иерархия для организации вещей, ролевой способ предоставления доступа, подход OIDC для бесключевого CI и процедура инициализации "холодного старта" вашего state backend. Плохая новость - это остальные 20% - и они сосредоточены в нескольких высоконагруженных местах, где выполнение "подхода AWS" приводит к запутанному отказу, а не к очевидной ошибке. Этот пост - это слой перевода: те же задачи, которые вы выполняете в AWS, выполненные в GCP, с указанием ловушек.
Краткая версия, если вы прочитаете только один абзац: Иерархия GCP (organization -> folder -> project -> resource)
чисто сопоставляется с AWS Organizations -> OU -> account -> resource, но три вещи нарушают вашу мышечную память. IAM - это
политика, разрешающая только доступ, привязанная к дереву ресурсов и наследуемая вниз - к пользователю не прикрепляется никаких политик. Все
API сервисов проекта изначально отключены, и ничего не работает, пока вы не включите каждый из них. И вы не принимаете роли, вы
выдаете себя за service accounts, которые сами являются ресурсами со своей собственной политикой доступа. Все ниже расширяет эти положения.
Самое большое изменение: разрешения находятся на дереве, а не на идентификаторах
В AWS ментальная модель - "прикрепить политику к идентификатору". Вы создаете пользователя или роль, прикрепляете к ней JSON, и разрешение перемещается вместе с субъектом. Политики ресурсов существуют, но политика, прикрепленная к идентификатору, является центром тяжести.
GCP инвертирует это. Политика IAM - это набор привязок - пар (member, role) - прикрепленных к узлу в иерархии ресурсов
(organization, folder, project или отдельный ресурс). Политика находится на объекте, к которому осуществляется доступ,
а не на идентификаторе, осуществляющем доступ. Ваш эффективный доступ в любой точке - это объединение каждой привязки, унаследованной
от корня до этого узла. Предоставьте roles/compute.admin группе на уровне folder, и каждый project под этим folder унаследует его.
Если вы работали с Azure RBAC, это покажется знакомым - это роль в определенной области с наследованием вниз. Правило, которое вас спасет:
Когда GCP что-то отклоняет, перестаньте искать "политику на пользователе". Ищите привязку на org, folder,
projectили resource - и помните, что она наследуется вниз, поэтому важное разрешение может находиться на три уровня выше.
Несколько особенностей, отличающихся от AWS:
- Роли бывают трех видов. Примитивные роли (
roles/owner,roles/editor,roles/viewer) - это грубое наследуемое трио - избегайте их в реальных проектах. Предопределенные роли - это детализированные роли для каждого сервиса, которые вы должны использовать (roles/storage.objectViewer,roles/compute.instanceAdmin.v1, ...). Пользовательские роли вы создаете сами, когда предопределенный набор слишком широк. - Базовая модель является аддитивной и разрешающей только. Нет
Effect: Denyдля каждого оператора, встроенного в каждую политику, как это есть в AWS. Эффективный доступ - это просто объединение разрешений. - Запрет - это отдельный слой. Когда вам действительно нужно жесткое "никогда, независимо от разрешений", вы пишете политику запрета IAM -
отдельный объект, прикрепленный к org/folder/
project, который оценивается до разрешений. Это самое близкое к встроенному операторуDeny, но он намеренно вынесен за рамки. - Ограничители - это еще одна вещь: Organization Policy Service. Ограничения, такие как
constraints/compute.vmExternalIpAccessилиconstraints/iam.disableServiceAccountKeyCreation, являются аналогом SCP в GCP. Они прикрепляются на уровне org/folder/project, наследуются вниз и ограничивают что может существовать или быть настроено, а не кто может что вызывать. Думайте "ограничитель в форме SCP", а не "роль IAM".
Таким образом, если AWS дает вам одну грамматику разрешений/запретов внутри IAM, GCP распределяет эту работу между привязками разрешений, политиками запрета и ограничениями org-политики. Те же результаты, три механизма.
Все является проектом - и его API изначально отключены
Проект - это фундаментальная единица GCP. Это приблизительный аналог аккаунта AWS: граница изоляции, область IAM
и цель биллинга - все сразу. Но project гораздо легче, чем аккаунт - его дешево создавать, легко удалять,
предназначен для создания десятками. Идиоматический шаблон - один project на рабочую нагрузку на окружение (app-qa, app-prod),
а не несколько общих аккаунтов, разделенных тегами.
Три вещи, касающиеся проектов, не имеют чистого эквивалента в AWS:
- У проекта есть три идентификатора, и различия могут быть критичными. Идентификатор проекта - это глобально уникальная, выбранная человеком,
неизменяемая строка (
acme-app-prod-7f3a) - это то, что вы указываете почти в каждой команде и пути к ресурсу. Номер проекта - это глобально уникальное целое число, присваиваемое GCP. Отображаемое имя изменяемо и косметично. Выбирайте ID тщательно; вы никогда не сможете его изменить. - API сервисов отключены по умолчанию. Это самая распространенная ошибка в первый день. Прежде чем вы сможете создать VM,
вы включаете
compute.googleapis.com; перед созданием бакета -storage.googleapis.com; и так далее, для каждого проекта. Ваш первый "отказ" в GCP обычно вовсе не отсутствие роли IAM - этоAPI [compute.googleapis.com] not enabled on project. В AWS сервисы просто есть; в GCP каждыйproject- это чистый лист, и вы включаете именно те поверхности, которые собираетесь использовать. (В Terraform этоgoogle_project_service; из CLI -gcloud services enable.) - Проекты являются естественной границей радиуса поражения и квот. Квоты, бюджеты и большинство настроек по умолчанию
привязаны к
project, поэтому создание новогоprojectдля эксперимента - это обычный, дешевый шаг, а не церемония, как в случае с аккаунтом AWS.
Сервисные аккаунты: вы выдаете себя, вы не принимаете роли
В AWS роль - это набор разрешений, которые субъект принимает через STS, ограниченный политикой доверия. В GCP эквивалентным рабочим инструментом является сервисный аккаунт (SA), и он работает иначе, что сбивает с толку каждого инженера AWS.
Сервисный аккаунт - это и идентификатор, и ресурс. У него есть email (deployer@acme-app-prod.iam.gserviceaccount.com),
он находится внутри проекта, и - что крайне важно - у него есть собственная политика IAM, регулирующая, кто может его использовать.
Эта вторая половина - это та часть, которая не имеет аналога в AWS:
- Чтобы действовать как сервисный аккаунт, субъекту нужна роль на самом SA -
roles/iam.serviceAccountTokenCreator(для создания кратковременных токенов и выдачи себя за него) илиroles/iam.serviceAccountUser(для прикрепления его к создаваемому ресурсу, такому как VM или сервис Cloud Run). Это двустороннее разрешение, о котором забывают специалисты AWS: предоставление вашему субъекту CI широких правprojectбесполезно, если он не может стать deployer SA. - Вы выдаете себя за SA, запрашивая токен (
generateAccessToken), а не принимая роль с рукопожатием политики доверия. Разрешение на выдачу себя находится как обычная привязка IAM к ресурсу SA - нет отдельного документа доверия. - Ключи сервисных аккаунтов существуют, и их по большей части следует избегать. Загруженный JSON ключ - это долгоживущие учетные данные и классический вектор утечки; многие организации отключают создание ключей на уровне всей организации с помощью упомянутого ранее ограничения. Следует использовать бесключевые альтернативы.
- Бесключевой CI - это Workload Identity Federation - та же идея OIDC, что и федерация OIDC в AWS. Ваши GitHub Actions или внешняя рабочая нагрузка представляют токен OIDC, пул идентификаторов рабочих нагрузок доверяет издателю, и GCP возвращает кратковременные учетные данные для SA. Никаких хранимых секретов. (Внутри GKE аналогом является Workload Identity, который связывает сервисный аккаунт Kubernetes с сервисным аккаунтом Google - прямой аналог IRSA в AWS.)
Перевод в одну строку: роль AWS, которую вы принимаете через политику доверия, становится сервисным аккаунтом GCP, за который вы выдаете себя через привязку создателя токена на SA.
Домен идентификации: Cloud Identity, Workspace и организация
GCP отделяет идентификацию от ресурсов, но гораздо мягче, чем Azure. Узел организации создается для проверенного домена,
принадлежащего аккаунту Cloud Identity или Google Workspace. Этот каталог - пользователи и группы - администрируется
в консоли Admin (admin.google.com), что отличается от консоли Cloud, где вы управляете ресурсами.
- Пользователи и группы создаются в каталоге; доступ предоставляется в IAM. Вы не создаете "пользователя GCP" так, как создаете пользователя IAM в AWS. Человек существует в Cloud Identity/Workspace (или федеративно подключен из вашего IdP), и вы ссылаетесь на него - в идеале как на группу - в привязках IAM к дереву ресурсов. Лучшая практика - привязки к группам, никогда к отдельным пользователям.
- Нет отдельного хранилища "пользователей IAM", как в AWS. Внешние IdP (Okta, Entra ID и так далее) федеративно подключаются к Cloud Identity; это норма для доступа сотрудников.
- Две ловушки, которые нужно запомнить: специальные члены
allUsers(буквально любой в интернете, неаутентифицированный) иallAuthenticatedUsers(любой с любым аккаунтом Google). Привязка роли к любому из них - это способ случайного публичного доступа к бакетам. Относитесь к ним так же, как кPrincipal: "*"в политике бакета S3.
Приблизительная аналогия: организация плюс ее домен Cloud Identity - это примерно "AWS Organization, объединенная с каталогом IAM Identity Center" - но повседневная работа с ресурсами происходит через привязки IAM к дереву, а не через политику, прикрепленную к идентификатору.
Биллинг - это отдельный объект, который вы связываете с проектами
Платежный аккаунт в GCP - это отдельный ресурс - он не является узлом в иерархии org -> folder -> project.
Проекты связываются с платежным аккаунтом (каждый project - ровно с одним), и один платежный аккаунт может финансировать
множество проектов.
- У него есть свой IAM.
roles/billing.admin,roles/billing.user,roles/billing.creatorнаходятся на платежном аккаунте, отдельно от ваших ролей ресурсов. В частности, чтобы прикрепить новыйprojectк платежному аккаунту, вам нужнаroles/billing.userна этом платежном аккаунте - широкие праваprojectсами по себе не помогут. - "Я могу развернуть" ничего не говорит о "Я могу создать платный проект". Чтобы создать
project, который может нести расходы, вам нужны какresourcemanager.projectCreator(на уровне org/folder), так иbilling.user(на платежном аккаунте). Пропустите второе, и созданиеprojectнаполовину удастся, превратившись вproject, который на самом деле ничего не может запустить.
Это мягче, чем жесткая стена коммерческого уровня Azure - биллинг GCP действительно интегрирован в Cloud IAM, поэтому он
отображается в тех же интерфейсах gcloud и Terraform, а не в совершенно отдельном мире. Но это все еще отдельный объект
с отдельными ролями, и это второй по распространенности сюрприз "но я же администратор" после неотключенных API.
Имена, идентификаторы и один сетевой сюрприз
Каждый ресурс GCP имеет относительное имя ресурса, такое как projects/acme-app-prod/zones/us-central1-a/instances/web-1
(и полностью квалифицированную форму //compute.googleapis.com/...). Идентификатор project сопровождает каждую строку журнала
и вызов API - та же работа, что и аккаунт ARN в AWS - поэтому, как и в Azure, ваши имена ресурсов могут опускать то, что
уже закодировано в project. Одни и те же короткие имена могут безопасно повторяться в ваших проектах -dev, -qa и -prod.
Сетевая ловушка, которую стоит отметить сразу, потому что она незаметно нарушает инстинкты AWS: сеть VPC в GCP - это глобальный ресурс, а ее подсети - региональные. В AWS VPC привязана к одному региону; в GCP одна VPC охватывает каждый регион, и вы создаете региональные подсети внутри нее. Единая глобальная VPC с региональными подсетями - это настройка по умолчанию, а не экзотическая многорегиональная конфигурация - не используйте VPC peering для того, что уже дают вам подсети.
Краткая карта AWS -> GCP
Держите это рядом в течение первого месяца:
- Organization -> organization. Та же идея, но org GCP привязана к вашему домену Cloud Identity/Workspace.
- Organizational Unit (OU) -> folder. Вложенный узел группировки; folders могут содержать folders.
- Account ->
project. Единица изоляции, IAM и биллинга - но легкая и одноразовая, создаваемая десятками. - SCP (guardrail) -> Organization Policy constraint в области org/folder/
project- ограничивает то, что может существовать или быть настроено, наследуется вниз. - IAM identity-attached policy -> IAM binding (member, role) на узле дерева. Нет политики на пользователе; разрешение находится на ресурсе и наследуется вниз.
- IAM role you assume (via STS + trust policy) -> service account you impersonate (через привязку создателя токена на SA). Помните о двустороннем разрешении.
- Explicit Deny statement -> IAM deny policy - отдельный объект, оцениваемый до разрешений.
- IRSA (IAM Roles for Service Accounts) -> Workload Identity (GKE) / Workload Identity Federation (внешний CI) - та же идея OIDC, бесключевая.
- "The service is just available" -> сначала enable its API per project (
google_project_service). Нет эквивалента в AWS. - ARN in logs -> имя ресурса (
projects/<id>/...); контекстprojectструктурирован, а не закодирован в имени.
Инициализация состояния Terraform, перевод
Вот место, где ваш AWS runbook почти работает, а затем ломается на нулевом шаге.
Инициализация AWS, которую вы знаете: холодный старт бэкенда состояния в управляющем аккаунте (локальное состояние, затем миграция бэкенда в себя), хранение состояния бэкендов для каждого OU в этом корневом бэкенде и создание дочерних аккаунтов с использованием их собственных бэкендов. Инвариант, который делает это чистым, заключается в том, что вы всегда можете выполнить инициализацию из управляющего аккаунта, потому что он всегда существует и может содержать бакет S3.
GCP нарушает этот инвариант с самого начала так же, как и Azure: всегда существующий объект - это organization, но узел org
не может содержать ресурсы. Бакет GCS находится в проекте, а project нуждается в родителе и (для выполнения чего-либо реального)
в ссылке на биллинг и включенных API. Таким образом, "корневой аккаунт" GCP - это начальный проект, который вы сознательно назначаете -
идиоматическое название что-то вроде prj-bootstrap или начальный проект Cloud Foundation Toolkit.
Переведенный поток, когда org и платежный аккаунт уже существуют (обычный случай):
- Один холодный старт, навсегда: создайте начальный
projectимперативно (gcloud projects create), включите на нем bootstrap API (cloudresourcemanager,cloudbilling,serviceusage,iam,storage), привяжите биллинг и создайте бакет состояния GCS с локальным состоянием Terraform - затемinit -migrate-stateв этот бакет. - Сервисный аккаунт для инициализации с ролями на уровне org: предоставьте ему
resourcemanager.projectCreator,billing.userи ваши роли администратора org-policy/IAM на узле организации, чтобы он мог создавать и управлять каждым последующимproject. - Все остальное - это обычное применение: дополнительные projects, folders и их ресурсы создаются Terraform, выдающим себя
за этот bootstrap SA, состояние каждого
projectнаходится подprefixв одном бэкенде GCS.
С абсолютного нуля порядок принудительный - сначала начальный project, затем бакет состояния - потому что бэкенд является
бакетом GCS, а бакету нужен project, чтобы существовать. И есть небольшая загвоздка "курица или яйцо", как и в Azure:
провайдер google нуждается в project и включенных API для выполнения чего-либо, поэтому вы создаете самый первый project
и включаете его API с помощью императивного вызова gcloud, а затем включаете его в Terraform. (Модуль
terraform-google-modules/bootstrap содержит именно эту процедуру seed-project-plus-SA.)
И вот где GCP действительно проще, чем мышечная память AWS: бэкенд в seed-project плюс ресурсы в member не нуждаются
ни в одном из механизмов доверия AWS "звезда" - ни в role_arn бэкенда, ни в assume_role провайдера, ни в двусторонних
политиках доверия. Сервисный аккаунт на уровне org с правильными ролями работает в масштабах всей org, потому что IAM наследуется
вниз; провайдер "переключается" между projects, просто устанавливая project; и он становится идентификатором развертывания,
устанавливая impersonate_service_account. Межпроектное взаимодействие - это параметр, а не переговоры о доверии. (Вы ужесточите
это позже с помощью пользовательских ролей, SA для каждого project и выделенных идентификаторов CI - но даже тогда это
привязки ролей в областях, а не рукопожатие политики доверия.) Если вы хотите углубиться в кодификацию любой из сторон,
экзамен HashiCorp Terraform Authoring & Operations Pro построен именно на этих шаблонах состояния и провайдера.
Четыре места, где ваши инстинкты AWS будут активно вводить вас в заблуждение
Если вы забудете все остальное, запомните это:
- Нет политики на пользователе. Перестаньте искать JSON, прикрепленный к идентификатору. Разрешения - это привязки
(member, role)на org, folder,projectили resource, и они наследуются вниз. Разрешение, которое вам нужно, может находиться на три уровня выше. - Ничего не работает, пока вы не включите API. Ваш первый 403 на новом
projectобычно означаетAPI not enabled, а не отсутствие роли. Каждый сервис отключен, пока вы не включите его для каждогоproject. - Вы выдаете себя за сервисные аккаунты, вы не принимаете роли. И SA - это ресурс со своей собственной политикой доступа -
предоставление вашему субъекту широких прав
projectбесполезно без привязки создателя токена на SA. - Биллинг - это отдельный объект. "Я могу развернуть что угодно" ничего не говорит о "Я могу создать платный
projectили привязать платежный аккаунт". Другой ресурс, другие роли -billing.userна платежном аккаунте, а не администраторproject.
Какие сертификации охватывают каждую сторону
Управление облаком - иерархия, идентификация, ограничители и состояние - является основой экзаменов по архитектуре и администрированию в обоих облаках, поэтому подготовка к ним также является самым быстрым способом закрепить вышеуказанные концепции. Если у вас уже есть учетные данные AWS, то учетные данные Google Cloud в той же строке - ваш естественный следующий шаг.
Со стороны AWS (знания, с которых вы переводите):
- AWS Certified Cloud Practitioner (CLF-C02) - основы аккаунтов, IAM и Organizations.
- AWS Certified Solutions Architect - Associate (SAA-C03) - IAM, многоаккаунтная структура и основная архитектура.
- AWS Certified Solutions Architect - Professional (SAP-C02) - многоаккаунтные Organizations, SCP и кросс-аккаунтный доступ в масштабе.
- AWS Certified Security - Specialty (SCS-C03) - глубокое изучение IAM, SCP и управление ключами.
Со стороны Google Cloud (знания, на которые вы переводите):
- Google Cloud Digital Leader - организации, проекты, IAM и биллинг на базовом уровне.
- Google Cloud Associate Cloud Engineer - повседневная работа: проекты, привязки IAM, сервисные аккаунты
и
gcloud. - Google Cloud Professional Cloud Architect - иерархия org/folder/
project, проектирование целевой зоны и управление в масштабе. - Google Cloud Professional Cloud Security Engineer - глубокое изучение IAM, политики org, безопасность сервисных аккаунтов и управление ключами.
Прагматичный путь, если вы сегодня сертифицированы AWS: начните с Cloud Digital Leader, чтобы сопоставить терминологию, затем
перейдите к Associate Cloud Engineer (который находится в плоскости project и IAM, которую вы будете использовать чаще всего),
и добавьте Professional Cloud Architect или Professional Cloud Security Engineer в зависимости от того, склоняется ли ваша работа
к архитектуре или безопасности.
Итог
GCP не сложнее AWS - он факторизован иначе. AWS прикрепляет разрешения к идентификаторам, предоставляет вам тяжеловесный аккаунт со всем включенным и сворачивает большую часть полномочий в IAM. GCP вешает разрешения на дерево ресурсов, которое наследуется вниз, дает вам дешевые одноразовые projects, которые начинаются как чистые листы, и заставляет вас выдавать себя за service accounts вместо принятия ролей. Переведите концепции один раз - политики перемещаются от идентификаторов к дереву, аккаунты становятся projects с отключенными API, роли становятся service accounts, за которые вы выдаете себя, а биллинг - это отдельный объект, который вы связываете - и остальное это терминология. Закрепите это с помощью вышеуказанных сертификатов, и те части, которые казались произвольными отказами, начнут восприниматься как связный, продуманный дизайн.