AWSエンジニアのためのGCP: AWSの直感がどう活かされ(そしてどこで通用しないか)
AWSでアカウントを整理し、権限を付与し、ステートをブートストラップする方法はご存知でしょう。Google Cloudで同じことを行う方法 - きれいにマッピングされる概念と、AWSの筋肉の記憶が積極的に誤解を招く4つのポイントをご紹介します。
AWSに精通していて、今Google Cloudを見つめているなら、朗報です。直感の約80%は直接移行できます。物事を整理するための階層、アクセスを付与するためのロールベースの方法、キーレスCIのためのOIDCの仕組み、そして「ステートバックエンドをコールドスタートする」ブートストラップのプロセスがあります。悪いニュースは残りの20%です。これは、AWS流のやり方をすると、明白なエラーではなく、混乱を招く拒否が発生する、いくつかのトラフィックの多い場所に集中しています。この記事は翻訳レイヤーです。AWSで行うのと同じ作業をGCPで行い、その落とし穴を指摘します。
もし1つの段落だけ読むなら、短いバージョンは次のとおりです。GCPの階層(organization -> folder -> project -> resource)は、AWS Organizations -> OU -> account -> resourceにきれいにマッピングされますが、3つの点で筋肉の記憶が通用しません。IAMはリソースツリーにバインドされ、下位に継承される許可のみのポリシーであり、ユーザーにポリシーはアタッチされません。プロジェクトのサービスAPIはすべて初期状態でオフになっており、それぞれを有効にするまで何も機能しません。そして、ロールをアシュームするのではなく、サービスアカウントを偽装します。サービスアカウント自体も独自のアクセスポリシーを持つリソースです。 以下では、これらを詳しく説明します。
最大の変化: 権限はアイデンティティではなくツリーに存在する
AWSでは、メンタルモデルは「ポリシーをアイデンティティにアタッチする」です。ユーザーまたはロールを作成し、それにJSONをホチキス止めすると、権限はプリンシパルとともに移動します。リソースポリシーは存在しますが、アイデンティティにアタッチされたポリシーが中心です。
GCPはそれを逆転させます。IAMポリシーは、リソース階層のノード(organization、folder、project、または個々のリソース)にアタッチされたバインディング - (member, role) のペア - のセットです。 ポリシーはアクセスされるものに存在し、アクセスを行うアイデンティティには存在しません。任意の時点での実効アクセスは、ルートからそのノードまで継承されたすべてのバインディングの結合です。フォルダレベルのグループに roles/compute.admin を付与すると、そのフォルダ配下のすべてのプロジェクトがそれを継承します。
Azure RBACに触れたことがあるなら、これは馴染み深く感じるでしょう - 下方継承を伴うスコープごとのロールです。あなたを救うルール:
GCPが何かを拒否した場合、「ユーザーのポリシー」を探すのをやめてください。org、folder、project、またはresourceのバインディングを探し、それが下位に継承されることを覚えておいてください。したがって、重要な付与は3レベル上にあるかもしれません。
AWSとは異なるいくつかの具体的な点:
- ロールには3つの種類があります。 プリミティブロール(
roles/owner、roles/editor、roles/viewer)は、粗いレガシーな3つのロールです - 実際の環境では避けてください。事前定義ロールは、実際に使用すべききめ細かいサービスごとのロールです(roles/storage.objectViewer、roles/compute.instanceAdmin.v1、...)。カスタムロールは、事前定義されたセットが広すぎる場合に自分で作成するものです。 - 基本モデルは加算的で許可のみです。 AWSのように、すべてのポリシーにステートメントごとの
Effect: Denyが織り込まれているわけではありません。実効アクセスは、許可の結合にすぎません。 - 拒否は別のレイヤーです。 「付与に関わらず、決して許可しない」という厳格な要件がある場合、IAM拒否ポリシーを作成します - これはorg/folder/projectにアタッチされる個別のオブジェクトで、許可の前に評価されます。これはインラインの
Denyステートメントに最も近いものですが、意図的に帯域外にあります。 - ガードレールはさらに別のものです: Organization Policy Serviceです。
constraints/compute.vmExternalIpAccessやconstraints/iam.disableServiceAccountKeyCreationのような制約は、GCPにおけるSCPsのアナログです。これらはorg/folder/projectにアタッチされ、下位に継承され、誰が何を呼び出せるかではなく、何が存在できるか、または設定できるかを制限します。「SCPのようなガードレール」と考えてください。「IAMロール」ではありません。
つまり、AWSがIAM内で1つの許可/拒否の文法を提供するのに対し、GCPは許可バインディング、拒否ポリシー、および組織ポリシーの制約にその役割を分散させます。結果は同じですが、メカニズムは3つあります。
すべてがプロジェクト - そしてそのAPIはオフから始まる
プロジェクトはGCPの基本的な単位です。これはAWSアカウントのおおよそのアナログです。分離境界、IAMスコープ、および課金ターゲットを兼ね備えています。しかし、プロジェクトはアカウントよりもはるかに軽量です - 作成が安価で、削除が容易で、多数作成されることを意図しています。慣用的なパターンは、環境ごとにワークロードごとに1つのプロジェクト(app-qa、app-prod)であり、タグで分割された少数の共有アカウントではありません。
プロジェクトに関する3つの点は、AWSにきれいに相当するものはありません。
- プロジェクトには3つの識別子があり、その違いが問題になります。 プロジェクトIDは、グローバルに一意で人間が選択する不変の文字列(
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では、すべてのプロジェクトは白紙の状態であり、使用する予定のサービスのみを有効にします。(Terraformではgoogle_project_service、CLIからはgcloud services enableを使用します。) - プロジェクトは自然な爆発半径とクォータの境界です。 クォータ、予算、およびほとんどのデフォルトはプロジェクトごとであるため、実験のために新しいプロジェクトを立ち上げるのは、AWSアカウントのような儀式ではなく、通常の安価な行動です。
サービスアカウント: 偽装するのであって、アシュームするのではありません
AWSでは、ロールはプリンシパルがSTSを通じてアシュームする権限のセットであり、信頼ポリシーによってゲートされます。GCPでは、同等の主力は**サービスアカウント(SA)**であり、すべてのAWSエンジニアを戸惑わせる方法で動作が異なります。
サービスアカウントはアイデンティティとリソースの両方です。メールアドレス(deployer@acme-app-prod.iam.gserviceaccount.com)を持ち、プロジェクト内に存在し、そして - 決定的に重要なことですが - 誰がそれを使用できるかを管理する独自のIAMポリシーを持っています。 その後半は、AWSの反射神経が通用しない部分です。
- サービスアカウントとして機能するには、プリンシパルはSA自体にロールが必要です -
roles/iam.serviceAccountTokenCreator(短命のトークンを発行して偽装するため)またはroles/iam.serviceAccountUser(VMやCloud Runサービスなど、作成するリソースにアタッチするため)。これはAWSの人が忘れがちな両面付与です。CIプリンシパルに広範なプロジェクト権限を与えても、デプロイヤーSAになれないのであれば無意味です。 - SAを偽装するには、信頼ポリシーのハンドシェイクでロールをアシュームするのではなく、トークンを要求します(
generateAccessToken)。偽装する権限は、SAリソース上の通常のIAMバインディングとして存在し、個別の信頼ドキュメントはありません。 - サービスアカウントキーは存在しますが、ほとんどの場合避けるべきです。 ダウンロードされたJSONキーは長期間有効な認証情報であり、古典的な漏洩経路です。多くの組織では、前述の制約を通じて組織全体でキーの作成を無効にしています。キーレスの代替手段を使用すべきです。
- キーレスCIはWorkload Identity Federationです - AWSのOIDCフェデレーションと同じOIDCの考え方です。GitHub Actionsまたは外部ワークロードがOIDCトークンを提示し、ワークロードアイデンティティプールが発行者を信頼すると、GCPはSAの短命な認証情報を返します。秘密は保存されません。(GKE内では、アナログはWorkload Identityであり、KubernetesサービスアカウントをGoogleサービスアカウントにバインドします - AWSのIRSAの直接の対応物です。)
一行で翻訳すると:信頼ポリシーを通じてアシュームするAWSロールは、SA上のトークン作成者バインディングを通じて偽装するGCPサービスアカウントになります。
アイデンティティドメイン: Cloud Identity、Workspace、および組織
GCPはアイデンティティとリソースを分離しますが、Azureよりもはるかに穏やかです。組織ノードは、Cloud IdentityまたはGoogle Workspaceアカウントが所有する検証済みドメインに対して作成されます。そのディレクトリ - ユーザーとグループ - は、リソースを管理するCloudコンソールとは異なる画面であるAdminコンソール(admin.google.com)で管理されます。
- ユーザーとグループはディレクトリで作成され、アクセスはIAMで付与されます。 AWSでIAMユーザーを作成するように「GCPユーザー」を作成することはありません。人間はCloud Identity/Workspaceに存在し(またはIdPからフェデレーションされ)、リソースツリー上のIAMバインディングで、理想的にはグループとして参照します。ベストプラクティスは、個々のユーザーではなくグループへのバインディングです。
- AWSのような独立した「IAMユーザー」ストアはありません。 外部IdP(Okta、Entra IDなど)はCloud Identityにフェデレーションされます。これが従業員のアクセスにおける標準です。
- 覚えておくべき2つの落とし穴: 特別なメンバー
allUsers(文字通りインターネット上の誰でも、認証なし)とallAuthenticatedUsers(任意のGoogleアカウントを持つ誰でも)です。どちらかにロールをバインドすると、バケットが誤って公開されてしまいます。S3バケットポリシーのPrincipal: "*"と同じように扱ってください。
大まかな類推:組織とそのCloud Identityドメインは、おおよそ「IAM Identity Centerのディレクトリと融合したAWS Organization」です - しかし、日常のリソース作業は、アイデンティティにアタッチされたポリシーではなく、ツリー上のIAMバインディングを通じて行われます。
請求はプロジェクトにリンクする別のオブジェクト
GCPの請求アカウントはそれ自体がリソースであり、org -> folder -> projectの階層のノードではありません。プロジェクトは請求アカウントにリンクし(各プロジェクトは正確に1つに)、1つの請求アカウントで多くのプロジェクトに資金を提供できます。
- 独自のIAMを持っています。
roles/billing.admin、roles/billing.user、roles/billing.creatorは、リソースロールとは別に、請求アカウント上に存在します。特に、新しいプロジェクトを請求アカウントにアタッチするには、その請求アカウントにroles/billing.userが必要です - 広範なプロジェクト権限だけでは不十分です。 - 「デプロイできる」ことは「課金可能なプロジェクトを作成できる」こととは関係ありません。 課金が発生する可能性のあるプロジェクトを立ち上げるには、
resourcemanager.projectCreator(org/folderレベル)とbilling.user(請求アカウント上)の両方が必要です。後者が欠けていると、プロジェクト作成は半成功し、実際には何も実行できないプロジェクトになってしまいます。
これはAzureの厳格な商用プレーンの壁よりも柔軟です - GCPの請求はCloud IAMに組み込まれているため、完全に別の世界ではなく、同じ gcloud やTerraformのインターフェースに表示されます。しかし、それでも異なる役割を持つ個別のオブジェクトであり、有効化されていないAPIの次に多い「でも私は管理者なのに」という驚きです。
名前、ID、そして1つのネットワークの驚き
すべてのGCPリソースには、projects/acme-app-prod/zones/us-central1-a/instances/web-1 のような相対リソース名(および完全修飾された //compute.googleapis.com/... 形式)があります。プロジェクトIDはすべてのログ行とAPI呼び出しとともに伝達されます - これはAWSのARNアカウントと同じ役割です - そのため、Azureと同様に、リソースの名前はプロジェクトがすでにエンコードしているものを省略できます。同じ短い名前は、-dev、-qa、-prod プロジェクト間で安全に繰り返すことができます。
AWSの直感に静かに反するため、事前に指摘しておくべきネットワークの落とし穴:GCPのVPCネットワークはグローバルリソースであり、そのサブネットはリージョンです。 AWSではVPCは1つのリージョンにスコープされますが、GCPでは1つのVPCがすべてのリージョンにまたがり、その中にリージョンサブネットを切り分けます。リージョンサブネットを持つ単一のグローバルVPCがデフォルトであり、エキゾチックなマルチリージョン設定ではありません - サブネットがすでに提供していることをVPCピアリングで実現しようとしないでください。
AWS -> GCP クイックマップ
最初の1ヶ月間はこれを手元に置いてください:
- Organization -> organization。同じ考え方ですが、GCPの組織はCloud Identity/Workspaceドメインにバインドされています。
- Organizational Unit (OU) -> folder。ネスト可能なグループ化ノード。フォルダはフォルダを含むことができます。
- Account -> project。分離、IAM、および課金単位 - しかし軽量で使い捨て可能、多数作成されます。
- SCP(ガードレール) -> org/folder/projectスコープでのOrganization Policy constraint - 何が存在できるか、または設定できるかを制限し、下位に継承されます。
- IAM identity-attached policy -> ツリーノード上のIAM binding
(member, role)。ユーザーにポリシーはありません。付与はリソース上に存在し、下位に継承されます。 - IAM role you assume (via STS + trust policy) -> service account you impersonate(SA上のトークン作成者バインディングを介して)。両面付与を覚えておいてください。
- Explicit
Denystatement -> IAM deny policy - 別のオブジェクトで、許可の前に評価されます。 - IRSA (IAM Roles for Service Accounts) -> Workload Identity (GKE) / Workload Identity Federation (外部CI) - 同じOIDCの考え方で、キーレスです。
- 「サービスはただ利用可能」 -> まずプロジェクトごとにそのAPIを有効にする(
google_project_service)。AWSに相当するものはありません。 - ログ内のARN -> リソース名(
projects/<id>/...)。プロジェクトコンテキストは構造化されており、名前でエンコードされていません。
Terraformステートのブートストラップ、翻訳済み
ここでは、AWSのランブックがほとんど機能するものの、ステップゼロで破綻する場所があります。
ご存知のAWSブートストラップ:管理アカウントでステートバックエンドをコールドスタートし(ローカルステート、その後バックエンド自体に移行)、OUごとのバックエンドのステートをそのルートバックエンドに保持し、独自のバックエンドを使用してメンバーアカウントを作成します。それをクリーンにする不変の原則は、管理アカウントは常に存在し、S3バケットを保持できるため、常に管理アカウントからブートストラップできることです。
GCPは、Azureと同じように、生成時にその不変の原則を破ります。常に存在するオブジェクトは組織ですが、組織ノードはリソースを保持できません。GCSバケットはプロジェクト内に存在し、プロジェクトには親と(実際に何かを行うには)請求リンクと有効化されたAPIが必要です。したがって、GCPの「ルートアカウント」は意識的に選定するシードプロジェクトです - 慣用的な名前は prj-bootstrap やCloud Foundation Toolkitのシードプロジェクトのようなものです。
組織と請求アカウントがすでに存在する場合(一般的なケース)の翻訳されたフロー:
- 一度限りのコールドスタート: シードプロジェクトを命令的に作成し(
gcloud projects create)、その上でブートストラップAPIを有効にし(cloudresourcemanager、cloudbilling、serviceusage、iam、storage)、請求をリンクし、ローカルTerraformステートでGCSステートバケットを作成します - その後、init -migrate-stateでそのバケットに移行します。 - 組織レベルのロールを持つブートストラップサービスアカウント:
resourcemanager.projectCreator、billing.user、および組織ポリシー/IAM管理者ロールを組織ノードで付与し、すべてのダウンストリームプロジェクトを作成および管理できるようにします。 - その他すべては通常の適用: 追加のプロジェクト、フォルダ、およびそれらのリソースは、TerraformがそのブートストラップSAを偽装して作成され、各プロジェクトのステートは1つのGCSバックエンドの
prefixの下に存在します。
完全にゼロから始める場合、順序は強制されます - シードプロジェクトが最初、ステートバケットが2番目 - なぜならバックエンドはGCSバケットであり、バケットは存在するプロジェクトを必要とするからです。そして、Azureと同様に小さな鶏と卵の問題があります。google プロバイダは何かをするためにプロジェクトと有効化されたAPIを必要とするため、最初のプロジェクトを作成し、命令的な gcloud コールでそのAPIを有効にし、その後Terraformに採用します。(terraform-google-modules/bootstrap モジュールは、まさにこのシードプロジェクトとSAの連携をパッケージ化しています。)
そして、GCPがAWSの筋肉の記憶よりも真にシンプルなのはここです。シードプロジェクト内のバックエンドとメンバー内のリソースは、AWSのハブアンドスポークの信頼メカニズムを必要としません - バックエンドの role_arn も、プロバイダの assume_role も、両面信頼ポリシーもありません。適切なロールを持つ組織レベルのサービスアカウントは、IAMが下位に継承されるため組織全体で機能します。プロバイダは project を設定するだけでプロジェクト間を「ホップ」し、impersonate_service_account を設定することでデプロイヤーのアイデンティティになります。クロスプロジェクトはパラメータであり、信頼交渉ではありません。(後でカスタムロール、プロジェクトごとのSA、専用のCIアイデンティティでこれを強化しますが、それでもスコープでのロールバインディングであり、信頼ポリシーのハンドシェイクではありません。)どちらかの側を深くコード化したい場合、HashiCorp Terraform Authoring & Operations Pro試験は、まさにこれらのステートとプロバイダのパターンを中心に構築されています。
AWSの直感が積極的に誤解を招く4つのポイント
他のすべてを忘れても、これだけは覚えておいてください:
- ユーザーにポリシーはありません。 アイデンティティにホチキス止めされたJSONを探すのはやめてください。権限はorg、folder、project、またはresource上の
(member, role)バインディングであり、下位に継承されます。必要な付与は3レベル上にあるかもしれません。 - APIを有効にするまで何も機能しません。 新しいプロジェクトでの最初の403エラーは、通常、ロールの不足ではなく
API not enabledです。すべてのサービスは、プロジェクトごとにオンにするまでオフになっています。 - サービスアカウントを偽装するのであって、ロールをアシュームするのではありません。 そしてSAは独自のアクセスポリシーを持つリソースです - プリンシパルに広範なプロジェクト権限を与えても、SA上のトークン作成者バインディングがなければ無意味です。
- 請求は別のオブジェクトです。 「何でもデプロイできる」ことは、「課金可能なプロジェクトを作成したり、請求アカウントをリンクしたりできる」こととは関係ありません。異なるリソース、異なるロール - プロジェクト管理者ではなく、請求アカウント上の
billing.userです。
各側面を深く掘り下げる認定資格
クラウドガバナンス - 階層、アイデンティティ、ガードレール、およびステート - は、両方のクラウドのアーキテクチャおよび管理試験のバックボーンであるため、それらの学習は上記の概念を定着させる最速の方法でもあります。すでに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、SCPs、および大規模なクロスアカウントアクセス。
- AWS Certified Security - Specialty (SCS-C03) - IAMの詳細、SCPs、およびキー管理。
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の詳細、組織ポリシー、サービスアカウントセキュリティ、およびキー管理。
現在AWS認定をお持ちの場合の実用的なパス:Cloud Digital Leaderから始めて語彙をマッピングし、次にAssociate Cloud Engineer(最も使用するプロジェクトとIAMの領域)に進み、仕事がアーキテクチャ寄りかセキュリティ寄りかに応じてProfessional Cloud ArchitectまたはProfessional Cloud Security Engineerを追加します。
まとめ
GCPはAWSよりも難しいわけではありません - 異なる要素に分解されているだけです。AWSは権限をアイデンティティにホチキス止めし、すべてがオンになった重厚なアカウントを提供し、ほとんどの権限をIAMに集約します。GCPは、下位に継承されるリソースツリーに権限をぶら下げ、白紙の状態から始まる安価で使い捨て可能なプロジェクトを提供し、ロールをアシュームする代わりにサービスアカウントを偽装させます。一度概念を翻訳してください - ポリシーはアイデンティティからツリーへ移動し、アカウントはAPIがオフのプロジェクトになり、ロールは偽装するサービスアカウントになり、請求はリンクする別のオブジェクトになります - そうすれば残りは語彙です。上記の認定でそれを習得すれば、恣意的な拒否のように感じられた部分が、一貫性のある意図的な設計として理解できるようになります。