Ansible Lesson 26 of 42

Ansible for GCP, In Depth: google.cloud, Application Default Credentials, Workload Identity Federation & Project-Scoped Automation

GCP’s mental model is the cleanest of the three big clouds: a project is a single, hard boundary that holds every resource, every IAM policy, every API quota, every billing line. There is no “tenant + subscription + resource group” hierarchy to memorise — you have organization → folder → project, and the project is the only scope most automation cares about. The auth model is just as clean: every API call is a Google Credential object, resolved through the Application Default Credentials chain (env vars → SA key file → metadata server → gcloud user creds), and the IAM primitive is “principal × role × resource” where principal is one of user:, serviceAccount:, group:, or domain:. Once you internalise project scope and ADC, the modules in google.cloud become mechanical: gcp_<service>_<resource> modules with consistent shape, declarative idempotency, and a dynamic inventory (gcp_compute) that maps GCE labels and metadata into Ansible groups.

This lesson is the exhaustive tour. We start with the GCP mental model — projects, folders, organisations, IAM scopes, labels — and the Application Default Credentials chain that every module uses. We walk google.cloud module-by-module, focusing on the modules you actually use in production: networking (gcp_compute_network, gcp_compute_subnetwork, gcp_compute_firewall, gcp_compute_router, gcp_compute_address), compute (gcp_compute_instance, gcp_compute_instance_template, gcp_compute_instance_group_manager, gcp_compute_target_pool), data (gcp_storage_bucket, gcp_sql_instance, gcp_secret_manager_secret, gcp_kms_key_ring), identity (gcp_iam_role, gcp_iam_service_account, gcp_iam_policy_binding), and Kubernetes (gcp_container_cluster, gcp_container_node_pool). We cover the four authentication modes — ADC default chain, explicit Service Account JSON, gcloud user creds, and Workload Identity Federation for keyless auth from GitHub Actions / GitLab CI / on-prem AAP — and the auth_kind decision matrix. We re-meet the google.cloud.gcp_compute dynamic inventory plugin from a deeper angle than the dynamic inventory lesson, focusing on the GCP-specific knobs (auth_kind, projects:, zones:, filters:, hostnames, vars_prefix). We finish on multi-project patterns, label-driven grouping, idempotency for the awkward modules, GKE-native ops, and packaging a GCP-aware Execution Environment for AAP. Everything targets current Ansible (ansible-core 2.17+, google.cloud 1.4+, the Google Auth Python SDK google-auth / google-auth-oauthlib / google-cloud-* packages, 2026), uses FQCN throughout, and ends with a free hands-on lab that uses a GCP free-tier project plus the always-free e2-micro VM.

Learning objectives

After this lesson you can:

Prerequisites & where this fits

You should already be comfortable with playbooks and tasks, variables and the precedence rules, Jinja templating, roles and collections, and dynamic inventory in general. The companion expert lessons that compound here are Ansible for AWS, Ansible for Azure, Ansible for Kubernetes (for GKE-native ops), and Hybrid Orchestration. In the Ansible Zero-to-Hero programme this is the Cloud expert (GCP) lesson and a textbook EX374-grade topic.

Core concepts

Five mental models carry the whole lesson.

1. Project is the boundary. Every GCP resource lives in exactly one project. Every IAM policy is scoped to organization, folder, project, or resource. Every API quota is per-project. Every API has to be enabled per-project (compute.googleapis.com, container.googleapis.com, …). For Ansible this means project: is a required parameter on essentially every module — set it once via module_defaults, not per task.

2. Application Default Credentials is the auth chain. Every Google client library walks the ADC chain: GOOGLE_APPLICATION_CREDENTIALS env (path to JSON key) → gcloud auth application-default login cache → GCE metadata server (when running on GCE) → external account (Workload Identity Federation). You set the environment; ADC resolves. The Ansible parameter auth_kind lets you pin a specific source.

3. Workload Identity Federation is the keyless future. WIF lets a non-GCP identity (a GitHub Actions OIDC token, a GitLab CI JWT, an AWS IAM role, an Azure managed identity, or any OIDC-issuing IdP) impersonate a GCP service account without a JSON key. The pattern: configure a Workload Identity Pool + Provider in GCP, federate a non-GCP identity, point Ansible at the resulting external_account credential file. Net result: GitHub Actions runs Ansible against GCP with zero long-lived secrets.

4. Labels are the inventory. GCP labels (environment=prod, role=web, team=platform) flow into the gcp_compute plugin’s keyed_groups. A consistent label schema turns “all hosts” into clean cross-cutting groups. GCP also supports resource-level labels on most things (VMs, disks, buckets, SQL instances), so the schema scales beyond compute.

5. Most gcp_* modules are present/absent only. Like Azure, GCP modules don’t expose the seven-state network-module API. state: present reconciles; state: absent deletes. The module computes the diff from current → desired internally. The two awkwardnesses are: (a) properties that are immutable after creation (machine_type changes need a stop, then resize, then start — handled by gcp_compute_instance_machine_type rather than re-running gcp_compute_instance); (b) the name-based identity is global within a project for some resources (firewall rules) and per-zone for others (instances).

Keep these terms straight: project (scope boundary), organization/folder (parent containers), service account (automation identity in GCP IAM), Application Default Credentials (ADC) (the standard auth-chain), auth_kind (Ansible’s selector: application/serviceaccount/accesstoken/machineaccount), Workload Identity Federation (keyless cross-cloud identity), gcp_compute plugin (dynamic inventory), labels (the inventory key), scopes (compute-engine OAuth scopes — almost always cloud-platform for full access).

The GCP mental model

  Organization (acme.com)
   ├── Folder: production
   │    ├── Project: prod-eu-app  (id: prod-eu-app-7fa2)
   │    │    ├── VPC: prod-eu-vpc
   │    │    ├── VM: prod-web-eu-1   (zone: europe-west1-b)
   │    │    └── SQL: prod-app-db    (region: europe-west1)
   │    └── Project: prod-us-app
   ├── Folder: staging
   │    └── Project: stg-eu-app
   └── Folder: sandbox
        └── Project: sandbox-engineer-X

  IAM bindings live at: organization | folder | project | resource
  IAM principals: user:, serviceAccount:, group:, domain:

Authentication — the four modes

auth_kind When to use What you set Risk
application (ADC) Default; let the chain resolve GOOGLE_APPLICATION_CREDENTIALS env or gcloud auth application-default login Depends on what’s in the env
serviceaccount Explicit JSON key file service_account_file: parameter Long-lived JSON key on disk
accesstoken Short-lived OAuth token (e.g. from gcloud auth print-access-token) access_token: parameter Token expires; refresh logic on you
machineaccount Control node is a GCE VM nothing — uses GCE metadata server Almost nothing — no key on disk

Pattern A — control node on GCE (recommended)

Run AAP on a GCE VM with an attached service account. Modules use auth_kind: machineaccount. Zero credentials anywhere:

- name: Create VPC (uses GCE metadata creds)
  google.cloud.gcp_compute_network:
    name: prod-eu-vpc
    auto_create_subnetworks: false
    auth_kind: machineaccount
    project: prod-eu-app-7fa2
    state: present

Pattern B — Workload Identity Federation (keyless from anywhere)

Configure WIF in GCP:

PROJECT_ID=prod-eu-app-7fa2
POOL_ID=github-actions-pool
PROVIDER_ID=github-provider
SA_EMAIL=ansible-automation@$PROJECT_ID.iam.gserviceaccount.com

# 1. create the pool + OIDC provider
gcloud iam workload-identity-pools create $POOL_ID \
  --location=global --display-name="GitHub Actions"

gcloud iam workload-identity-pools providers create-oidc $PROVIDER_ID \
  --location=global \
  --workload-identity-pool=$POOL_ID \
  --issuer-uri=https://token.actions.githubusercontent.com \
  --attribute-mapping="google.subject=assertion.sub,attribute.repository=assertion.repository"

# 2. allow your SA to be impersonated by the federation
gcloud iam service-accounts add-iam-policy-binding $SA_EMAIL \
  --role=roles/iam.workloadIdentityUser \
  --member="principalSet://iam.googleapis.com/projects/$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')/locations/global/workloadIdentityPools/$POOL_ID/attribute.repository/myorg/myrepo"

In GitHub Actions:

# .github/workflows/ansible.yml
permissions:
  id-token: write
  contents: read

steps:
  - uses: google-github-actions/auth@v2
    with:
      workload_identity_provider: projects/123456/locations/global/workloadIdentityPools/github-actions-pool/providers/github-provider
      service_account: ansible-automation@prod-eu-app-7fa2.iam.gserviceaccount.com

  - run: ansible-playbook play.yml

The auth@v2 action writes an external_account credential file and points GOOGLE_APPLICATION_CREDENTIALS at it. Your Ansible play uses auth_kind: application — it picks up the federated identity transparently. Zero JSON keys committed anywhere.

Pattern C — Service Account JSON key (legacy / on-prem)

gcloud iam service-accounts create ansible-automation
gcloud iam service-accounts keys create ~/sa.json \
  --iam-account=ansible-automation@$PROJECT_ID.iam.gserviceaccount.com
gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:ansible-automation@$PROJECT_ID.iam.gserviceaccount.com" \
  --role=roles/editor

Then either:

- module_defaults:
    group/google.cloud.gcp:
      auth_kind: serviceaccount
      service_account_file: /etc/ansible/sa.json
      project: prod-eu-app-7fa2

…or set GOOGLE_APPLICATION_CREDENTIALS=/etc/ansible/sa.json and use auth_kind: application.

auth_kind decision matrix

Where Ansible runs auth_kind Why
Engineer laptop with gcloud auth application-default login application Reads ADC cache
GitHub Actions / GitLab CI with WIF application Reads federated external_account
AAP Controller on GCE machineaccount Uses metadata server
AAP Container Group on GKE with Workload Identity (k8s) machineaccount GKE Workload Identity injects the metadata bridge
AAP Controller on-prem with SA key serviceaccount Explicit JSON key file
Short-lived demo / break-glass accesstoken gcloud auth print-access-token

google.cloud — the headline modules

# requirements.yml
collections:
  - name: google.cloud
    version: ">=1.4.0"
ansible-galaxy collection install -r requirements.yml
pip install requests google-auth google-auth-httplib2
Module Purpose Idempotent? Notes
gcp_compute_network VPCs Yes auto_create_subnetworks: false for custom mode
gcp_compute_subnetwork Subnets Yes Per-region
gcp_compute_firewall Firewall rules Yes Project-scoped, applies to a network
gcp_compute_address Static IPs Yes Regional or global
gcp_compute_router Cloud Router Yes Required for Cloud NAT
gcp_compute_instance VM instances Idempotent on name: + zone Per-zone naming
gcp_compute_instance_template Templates Yes The unit of MIG
gcp_compute_instance_group_manager Managed Instance Groups Yes Regional or zonal
gcp_compute_target_pool Target pools (legacy LB) Yes Use gcp_compute_backend_service for new LBs
gcp_storage_bucket GCS buckets Yes Names globally unique
gcp_sql_instance Cloud SQL Yes database_version: POSTGRES_16 etc.
gcp_iam_role Custom IAM roles Yes Project or org scope
gcp_iam_service_account Service accounts Yes Per-project
gcp_kms_key_ring / gcp_kms_crypto_key KMS Yes Per-region
gcp_secret_manager_secret Secret Manager Yes Use lookups to read secrets
gcp_container_cluster GKE clusters Idempotent on name: Heavy module — Terraform usually wins for cluster creation
gcp_container_node_pool GKE node pools Yes Day-2 ops on existing clusters

A canonical play with module_defaults:

- name: Provision a web tier in eu-prod
  hosts: localhost
  gather_facts: false
  connection: local
  module_defaults:
    group/google.cloud.gcp:
      auth_kind: machineaccount
      project: prod-eu-app-7fa2
  tasks:
    - name: VPC
      google.cloud.gcp_compute_network:
        name: prod-eu-vpc
        auto_create_subnetworks: false
        state: present

    - name: Subnet
      google.cloud.gcp_compute_subnetwork:
        name: web-eu-w1
        region: europe-west1
        ip_cidr_range: 10.42.1.0/24
        network:
          selfLink: projects/prod-eu-app-7fa2/global/networks/prod-eu-vpc
        private_ip_google_access: true
        state: present

    - name: Firewall  allow HTTPS
      google.cloud.gcp_compute_firewall:
        name: allow-https
        network:
          selfLink: projects/prod-eu-app-7fa2/global/networks/prod-eu-vpc
        direction: INGRESS
        allowed:
          - ip_protocol: tcp
            ports: ["443"]
        source_ranges: ["0.0.0.0/0"]
        target_tags: ["web"]
        state: present

    - name: Web VM
      google.cloud.gcp_compute_instance:
        name: prod-web-eu-1
        machine_type: e2-medium
        zone: europe-west1-b
        disks:
          - auto_delete: true
            boot: true
            initialize_params:
              source_image: projects/ubuntu-os-cloud/global/images/family/ubuntu-2404-lts
              disk_size_gb: 30
              disk_type: pd-balanced
        network_interfaces:
          - subnetwork:
              selfLink: projects/prod-eu-app-7fa2/regions/europe-west1/subnetworks/web-eu-w1
            access_configs:
              - name: External NAT
                type: ONE_TO_ONE_NAT
        tags:
          items: ["web"]
        labels:
          environment: prod
          role: web
        metadata:
          ssh-keys: "ansible:{{ ssh_pubkey }}"
        state: present
      register: vm

Notice the selfLink: references — every cross-resource pointer in google.cloud is a selfLink (a fully-qualified URL into the GCP API), not just a name. This is verbose but unambiguous.

gcp_compute dynamic inventory — GCP-specific knobs

Knob Default Purpose
auth_kind (none — required) Same selector as modules
projects: (none — required) List of project IDs to enumerate
zones: (all) Pre-filter by zone — performance lever
filters: (none) API-side filter expression (status = RUNNING AND labels.environment = prod)
hostnames: [name] What field becomes the Ansible host name
vars_prefix: gcp_ Prefix for hostvars
compose: (none) Same universal lever — Jinja-derived hostvars
keyed_groups: (none) Same universal lever — groups by key
groups: (none) Same universal lever — named groups via Jinja
cache: / cache_plugin: / cache_timeout: (none) Cache the inventory query

Production-grade GCP inventory file:

# inventory/prod.gcp.yml
plugin: google.cloud.gcp_compute
auth_kind: machineaccount
projects:
  - prod-eu-app-7fa2
  - prod-us-app-3a91
zones:
  - europe-west1-b
  - europe-west1-c
  - us-central1-a
filters:
  - "status = RUNNING AND labels.environment = prod"
hostnames:
  - name
compose:
  ansible_host: networkInterfaces[0].networkIP
  env: labels.environment | default('unknown')
  role: labels.role | default('unknown')
keyed_groups:
  - prefix: label
    key: labels
  - prefix: zone
    key: zone | basename
  - prefix: machine
    key: machineType | basename
  - prefix: project
    key: project_id
groups:
  prod_eu: labels.environment == 'prod' and zone is search('europe-')
  needs_patch: labels.patched is not defined or labels.patched != 'true'
cache: true
cache_plugin: jsonfile
cache_connection: /var/cache/ansible_inventory
cache_timeout: 600

filters: is the single biggest performance lever — it’s a server-side filter expression in the GCE API’s filter language. Use it aggressively on big projects.

Multi-project patterns

GCP makes multi-project automation easy because projects are first-class.

Option A — single inventory, multiple projects

projects: in one inventory file lists all the projects you want to enumerate. The plugin stitches them together.

Option B — one inventory file per project

Cleaner for large fleets:

# inventory/prod-eu.gcp.yml
plugin: google.cloud.gcp_compute
projects: [prod-eu-app-7fa2]
auth_kind: machineaccount

# inventory/prod-us.gcp.yml
plugin: google.cloud.gcp_compute
projects: [prod-us-app-3a91]
auth_kind: machineaccount

Point inventory: at the directory; merging is automatic.

Option C — one play per project (for provisioning)

For provisioning plays (where you’re calling gcp_compute_* modules), one play per project with module_defaults setting project::

- import_playbook: plays/project-prod-eu.yml
- import_playbook: plays/project-prod-us.yml
- import_playbook: plays/project-stg.yml

Label strategy

Same shape as AWS tags / Azure tags — required first, governed via Organization Policy:

Label Required Purpose
environment Yes prod/stg/dev
role Yes web/db/worker
owner Yes Team email (with hyphens — labels can’t have @)
costcenter Yes Finance attribution
project_id_app Recommended Distinguishes app-level project IDs
patchgroup Recommended Drives OS patching automation

Enforce with the compute.requireOsLogin and custom Organization Policies that mandate label keys.

Idempotency & check-mode for awkward modules

Module Idempotency Sharp edge
gcp_compute_instance Idempotent on name: + zone machine_type: change requires stop → resize → start (use gcp_compute_instance_machine_type instead)
gcp_compute_firewall Idempotent on name: (project-global) Firewalls are project-global; check naming collisions
gcp_storage_bucket Globally unique name: Watch for collisions across all of GCP
gcp_sql_instance Idempotent on name: Some properties require failover/restart
gcp_container_cluster Idempotent on name: Don’t manage with Ansible if Terraform owns the cluster
gcp_iam_* bindings: updates can be additive or replacing — read the docs

GKE-native ops

For GKE-native ops (deploying workloads into a cluster) use the kubernetes.core collection, not google.cloud. The latter operates the cluster object (creates/scales node pools, upgrades the cluster); the former operates resources inside the cluster (Deployments, Services, ConfigMaps).

- name: Get GKE credentials and run a Deployment
  hosts: localhost
  gather_facts: false
  tasks:
    - name: Fetch kubeconfig
      ansible.builtin.command:
        cmd: gcloud container clusters get-credentials prod-eu --region europe-west1 --project prod-eu-app-7fa2

    - name: Apply manifest
      kubernetes.core.k8s:
        state: present
        src: manifests/web-deployment.yaml

Hands-on free lab — GCP free-tier

GCP gives every new account $300 credit + an always-free e2-micro VM in us-central1/-east1/-east4. The lab uses both.

# create a project (or use existing)
gcloud projects create my-ansible-lab --name="Ansible Lab"
gcloud config set project my-ansible-lab
gcloud auth application-default login
gcloud services enable compute.googleapis.com storage.googleapis.com

# install collection + deps
ansible-galaxy collection install google.cloud
pip install requests google-auth google-auth-httplib2
# play.yml
- hosts: localhost
  gather_facts: false
  connection: local
  module_defaults:
    group/google.cloud.gcp:
      auth_kind: application
      project: my-ansible-lab
  tasks:
    - name: VPC
      google.cloud.gcp_compute_network:
        name: lab-vpc
        auto_create_subnetworks: false
        state: present

    - name: Subnet
      google.cloud.gcp_compute_subnetwork:
        name: lab-sub
        region: us-central1
        ip_cidr_range: 10.42.1.0/24
        network:
          selfLink: projects/my-ansible-lab/global/networks/lab-vpc
        state: present

    - name: Firewall
      google.cloud.gcp_compute_firewall:
        name: lab-allow-ssh
        network:
          selfLink: projects/my-ansible-lab/global/networks/lab-vpc
        direction: INGRESS
        allowed:
          - ip_protocol: tcp
            ports: ["22"]
        source_ranges: ["0.0.0.0/0"]
        state: present

    - name: e2-micro (always-free)
      google.cloud.gcp_compute_instance:
        name: lab-vm
        machine_type: e2-micro
        zone: us-central1-a
        disks:
          - auto_delete: true
            boot: true
            initialize_params:
              source_image: projects/debian-cloud/global/images/family/debian-12
              disk_size_gb: 10
              disk_type: pd-standard
        network_interfaces:
          - subnetwork:
              selfLink: projects/my-ansible-lab/regions/us-central1/subnetworks/lab-sub
            access_configs:
              - name: External NAT
                type: ONE_TO_ONE_NAT
        labels:
          environment: lab
          role: vm
        state: present
ansible-playbook play.yml --diff
ansible-playbook play.yml --diff   # second run — changed=0

Inventory test:

# inv.gcp.yml
plugin: google.cloud.gcp_compute
auth_kind: application
projects: [my-ansible-lab]
hostnames: [name]
keyed_groups:
  - prefix: label
    key: labels
ansible-inventory -i inv.gcp.yml --graph

Tear down:

ansible localhost -m google.cloud.gcp_compute_instance \
  -a "name=lab-vm zone=us-central1-a project=my-ansible-lab auth_kind=application state=absent"

Common mistakes & troubleshooting

ImportError: No module named google.auth. The Execution Environment doesn’t have google-auth. Bake requests, google-auth, google-auth-httplib2 into your EE.

PermissionDenied on every API call. The service account / federated identity lacks the right role. Start with roles/editor for lab; lock down to per-API roles (roles/compute.admin, roles/storage.admin) in production.

Inventory returns 0 hosts. Either: (a) enable_plugins doesn’t list google.cloud.gcp_compute; (b) the file isn’t named *.gcp.yml; © auth_kind doesn’t match what your environment actually has; (d) projects: is missing or wrong; (e) filters: excludes everything.

API not enabled. Run gcloud services enable compute.googleapis.com (and any others you need). Ansible doesn’t auto-enable APIs.

Firewall name collision across networks. Firewall names are project-global, not network-scoped. Use prefixes (prod-eu-allow-https).

gcp_compute_instance rebuilds the VM unexpectedly. You changed machine_type: or the boot disk. Use gcp_compute_instance_machine_type for size changes; boot disk is essentially write-once.

Workload Identity Federation token expired mid-play. Long plays past 1h can hit token expiry. Configure ttl: 3600s on the federation provider; for very long plays, refresh the token explicitly in a pre-task or split the work into multiple shorter plays.

shell: gcloud compute instances create … everywhere. Replace with gcp_compute_instance. The CLI is for humans; the module is for automation.

Best practices

Security notes

Interview & exam Q&A

Q1. What’s the auth chain a google.cloud module walks? The Application Default Credentials chain: explicit module params → GOOGLE_APPLICATION_CREDENTIALS env (path to JSON or external_account file) → gcloud auth application-default login cache → GCE metadata server. Pinned by auth_kind:.

Q2. Why prefer Workload Identity Federation to a Service Account JSON key? WIF is keyless: a federated OIDC identity (GitHub Actions OIDC token, AWS role, Azure MI) impersonates a GCP service account via short-lived tokens. No JSON key on disk, no rotation burden, audit trail in Cloud Audit Logs shows the federated principal.

Q3. What’s the difference between auth_kind: application and auth_kind: serviceaccount? application resolves via ADC — let the chain pick the right credential. serviceaccount pins a specific JSON key file via service_account_file:. In production, prefer application so the same play works on engineer laptops, CI, and AAP.

Q4. Why is module_defaults with group/google.cloud.gcp important? Every gcp_* module needs auth_kind and project. Without module_defaults, every task repeats them, and inevitable drift causes auth bugs. Set them once at play level.

Q5. How does the gcp_compute plugin handle multiple projects? projects: is a list — the plugin enumerates VMs across each. Or use one inventory file per project; both files are merged when inventory: points at the directory.

Q6. What’s the most performance-impactful inventory knob? filters: — server-side filter expression in GCE API syntax. A 5,000-instance project filtered by labels.environment = prod returns 200 rows in one API call.

Q7. When would you prefer google.cloud.gcp_container_cluster over Terraform for GKE? For day-2 ops on a cluster that already exists (scaling node pools, enabling features, upgrading). For creation of new GKE clusters Terraform usually wins because of state-file dependency tracking.

Q8. Difference between GKE Workload Identity and Workload Identity Federation? Workload Identity (GKE feature) lets pods in a GKE cluster impersonate a GCP service account via the cluster’s metadata bridge. Workload Identity Federation (IAM feature) lets external identities (GitHub Actions, AWS, Azure) impersonate a GCP service account via OIDC. Different scopes, same goal: keyless auth.

Q9. What goes into a production GCP EE? ansible-builder with google.cloud, the SDK (requests, google-auth, google-auth-httplib2, google-cloud-storage, google-cloud-secret-manager if you read secrets), the gcloud CLI (for GKE auth bridge), and your shared utility collections.

Q10. How do you handle multi-project IAM consistently? Group IAM bindings by team in YAML, loop gcp_iam_policy_binding over them. The data file is your audit trail: who has what role at what scope.

Q11. When does gcp_compute_instance rebuild the VM? When you change a property that isn’t in-place mutable: machine_type:, the boot disk’s source_image:, network attachments. Use the dedicated machine-type module for size changes; boot disk is write-once.

Q12. Why is selfLink: so prevalent in google.cloud? Because GCP cross-resource references are URL-shaped — projects/X/global/networks/Y — and unambiguous across projects, regions, and zones. Verbose but precise; you’ll never accidentally reference the wrong VPC in another project.

Q13. How do you read a Secret Manager secret at play time? community.google.gcp_secret_manager_secret lookup, or google.cloud.gcp_secret_manager_secret module with state: present for management; lookup for reading. Combine with module_defaults so credentials never appear in role defaults.

Q14. What’s the correct auth choice for AAP Container Groups in GKE? Configure GKE Workload Identity on the cluster, annotate the EE pod’s ServiceAccount with iam.gke.io/gcp-service-account=<SA-email>, set auth_kind: machineaccount in plays. The cluster’s metadata bridge does the rest.

Quick check

  1. What auth_kind should an AAP Controller running on a GCE VM use?
  2. How do you authenticate a GitHub Actions runner to GCP without a JSON key?
  3. Which inventory plugin knob does server-side filtering?
  4. Why is project: always required on gcp_* modules?
  5. What’s the relationship between google.cloud.gcp_container_cluster and kubernetes.core?

(Answers: machineaccount; Workload Identity Federation with google-github-actions/auth@v2; filters: (uses GCE API filter syntax); because every resource lives in exactly one project — there is no implicit default; the former operates the cluster object, the latter operates resources inside the cluster.)

Exercise

With your free-tier project:

  1. Create a service account and either run gcloud auth application-default login (laptop) or attach the SA to a tiny e2-micro and use auth_kind: machineaccount.
  2. Write a play that creates a VPC, subnet, firewall, and an e2-micro always-free VM with proper labels.
  3. Add an add_host step using the VM’s external IP and a wait_for_connection to confirm SSH.
  4. Build a gcp_compute inventory file pointing at your project; verify --graph shows label_environment_lab etc.
  5. (Stretch) Set up Workload Identity Federation for a GitHub Actions repo and run the play from CI keylessly.
  6. Run with --check --diff. Then for real. Then again — changed=0.

Certification mapping

Cert Coverage
EX374 — Red Hat Certified Specialist in Ansible Automation Direct: cloud collections, dynamic inventory, EE.
Google Associate Cloud Engineer Indirect: project / IAM / VPC mental model.
Google Professional Cloud DevOps Engineer Direct: deployment automation, federated auth.

Glossary

Next steps

You can now drive GCP from Ansible. With AWS, Azure, and GCP under your belt, continue with Ansible for Windows for the third major OS family, Ansible for Kubernetes for cluster-internal ops on GKE/EKS/AKS, and Hybrid Multi-Cloud Orchestration to compose all three clouds in a single workflow.

ansiblegcpgoogle.cloudcompute-engineiamgkeworkload-identity-federationEX374
Need this built for real?

Vinod is a Senior Cloud Architect (22+ yrs) — available for Azure / AWS / GCP architecture, landing zones, and migrations.

Work with me

Comments