Skip to main content

GCP Workload Identity Federation Setup

This guide walks through configuring a Google Cloud project that USDN can authenticate to using Workload Identity Federation — no service account keys are created, downloaded, or stored on the USDN platform. Once configured, the Cloud Accounts page in the USDN portal can validate access, discover VPC networks, subnetworks and firewall tags, list boot images from your project, and launch AdWanOS devices on Compute Engine.

Current Scope

GCP supports onboarding, validation, resource discovery, and the deploy lifecycle (launch, poll, terminate). Image listing covers images in your own project only — a USDN-published Compute Engine image is pending a Marketplace decision, so until then you supply the image reference yourself.

How It Works​

USDN mints a short-lived JWT signed by its OIDC issuer, exchanges it at Google's Security Token Service for a federated token, then impersonates the service account you nominate. Every Compute call is made as that service account.

Two things make this safe: USDN holds no key material, and the federated identity itself has no permissions — it can only impersonate the one service account you bind it to, and only with the roles you grant that account.

Prerequisites​

  • A GCP project with permission to create workload identity pools, service accounts, and IAM bindings (roles/iam.workloadIdentityPoolAdmin and roles/iam.serviceAccountAdmin, or roles/owner)
  • The Compute Engine API enabled on the project (gcloud services enable compute.googleapis.com)
  • The USDN OIDC issuer URL: <USDN_OIDC_ISSUER> (provided during onboarding, e.g. https://api.usdn.example.com)
  • Access to the USDN portal with an active organization

The portal shows you the exact issuer, audience, and subject values for your organization on step 1 of the Cloud Accounts setup wizard. Use those rather than the examples below — the subject in particular is specific to your organization.

Step 1: Create the Workload Identity Pool and OIDC Provider​

Using the Google Cloud console​

  1. Go to IAM & Admin → Workload Identity Federation and click Create pool.
  2. Give the pool a name; note the Pool ID (e.g. usdn-pool). It cannot start with gcp-.
  3. Add a provider of type OpenID Connect (OIDC) and note the Provider ID (e.g. usdn-provider).
  4. Set Issuer (URL) to <USDN_OIDC_ISSUER>.
  5. Under Audience, select Allowed audiences and enter the audience the portal shows. It ends with your organization ID — the examples below use usdn-gcp-federation-9, but yours will differ, so copy it from the wizard.
  6. Under Attribute mapping, map google.subject to assertion.sub.
  7. Click Save.
caution

A provider's issuer URI and audience cannot be changed after creation. If you enter the wrong value you have to delete the provider and create it again, so copy both from the portal rather than typing them.

Using the gcloud CLI​

PROJECT_ID="my-project"
POOL_ID="usdn-pool"
PROVIDER_ID="usdn-provider"
ISSUER="<USDN_OIDC_ISSUER>"

gcloud iam workload-identity-pools create "$POOL_ID" \
--project="$PROJECT_ID" \
--location="global" \
--display-name="USDN"

gcloud iam workload-identity-pools providers create-oidc "$PROVIDER_ID" \
--project="$PROJECT_ID" \
--location="global" \
--workload-identity-pool="$POOL_ID" \
--issuer-uri="$ISSUER" \
--allowed-audiences="usdn-gcp-federation-9" \
--attribute-mapping="google.subject=assertion.sub"

Why an allowed audience rather than the default​

Google's default audience for a provider is the provider's own full resource name, which does not exist until the pool does — so it cannot be shown to you before you create the pool. USDN mints its own audience instead and you accept it with --allowed-audiences.

The value is GCP-specific, so a token minted for another cloud cannot be replayed against your pool, and it ends with your USDN organization ID, so a token minted for another USDN customer cannot be exchanged at your pool either. That second property is what makes your provider — not just your IAM binding — reject tokens that were not minted for you.

Step 2: Create the Service Account​

This is the identity USDN acts as. No key is created or downloaded.

Using the console​

  1. Go to IAM & Admin → Service Accounts and click Create service account.
  2. Name it something recognisable, e.g. usdn-deploy.
  3. Grant it Compute Admin (roles/compute.admin) so it can launch and terminate instances.
  4. Click Done. Do not create a key.

Using the gcloud CLI​

SA_NAME="usdn-deploy"
SA_EMAIL="${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"

gcloud iam service-accounts create "$SA_NAME" \
--project="$PROJECT_ID" \
--display-name="USDN cloud deploy"

gcloud projects add-iam-policy-binding "$PROJECT_ID" \
--member="serviceAccount:${SA_EMAIL}" \
--role="roles/compute.admin"

Permission Summary​

RoleGranted onNeeded for
roles/compute.viewerProjectConnection test, resource discovery, image listing
roles/compute.adminProjectLaunching, polling and terminating instances (includes the above)
roles/iam.workloadIdentityUserThe service accountLetting USDN's federated identity impersonate it (step 3)

If you only want to onboard and discover for now, roles/compute.viewer is enough — the connection test will pass and deploys will fail with a permission error.

Step 3: Grant USDN Permission to Impersonate​

This binding is what turns a verified token into access. Without it the connection test fails with invalid_grant.

The portal renders the exact command on step 4 of the wizard, with your values filled in. It looks like this:

gcloud iam service-accounts add-iam-policy-binding \
usdn-deploy@my-project.iam.gserviceaccount.com \
--role=roles/iam.workloadIdentityUser \
--member="principal://iam.googleapis.com/projects/123456789012/locations/global/workloadIdentityPools/usdn-pool/subject/usdn-deploy-9"

The --member principal has four parts you can check by eye:

  • projects/123456789012 — your project number, not the project ID
  • workloadIdentityPools/usdn-pool — the pool from step 1
  • subject/usdn-deploy-9 — the subject the portal shows for your organization
  • the role is on the service account, not the project

In the portal, go to Cloud Accounts → Add integration → Google Cloud Platform and supply:

FieldWhere to find it
Project IDProject selector, or gcloud config get-value project — the human-readable id
Project NumberProject dashboard, or gcloud projects describe $PROJECT_ID --format='value(projectNumber)'
Workload Identity Pool IDThe Pool ID from step 1
Workload Identity Provider IDThe Provider ID from step 1
Service Account EmailEnds in .iam.gserviceaccount.com
RegionDefault region for deploys, e.g. us-central1

Click Connect & Test. USDN exchanges a token, impersonates the service account, and reads the project through the Compute API. A pass means all three of federation, impersonation and Compute access work.

Deploying a Device​

Once the account is connected, Deploy on the Cloud Accounts page collects a site, region, machine type, image and networking.

  • Image — a name in your project (adwanos-1-4-2), a full path (projects/my-project/global/images/adwanos-1-4-2), an image family path (projects/my-project/global/images/family/adwanos), or a self-link copied from the console.
  • Network — if you pick a VPC without a subnet, the deploy is rejected when the VPC is custom-mode, because Compute requires a subnetwork for those. Pick the subnet as well.
  • Firewall — GCP has no attachable security group, so USDN offers the network tags your firewall rules target and sets the chosen tag on the instance.
  • Zone — you choose a region; USDN picks an available zone inside it and records which one.
  • External IP — instances get one so the agent can reach the platform to register.

Troubleshooting​

Connection test fails with "Workload identity federation failed"​

The token exchange or the impersonation was rejected. In order of likelihood:

  1. The provider's allowed audience does not match the audience shown in the wizard.
  2. The attribute mapping does not map google.subject to assertion.sub.
  3. The service account is missing the roles/iam.workloadIdentityUser binding from step 3, or the principal in that binding does not match the subject shown in the wizard (a copy-paste with a stray space will do this).

Connection test fails with "cannot read project … Grant it roles/compute.viewer"​

Federation worked and impersonation worked — the service account itself lacks project access, or the Compute Engine API is not enabled on the project.

Connection test fails with "Project … was not found"​

The project ID is wrong, or the service account cannot see that project.

Connection test fails with "has project number X, but this account is configured with Y"​

The pool named in your configuration lives in a different project than the one you are deploying into. Check the project number field against gcloud projects describe.

Resource discovery returns empty lists​

Each resource type is listed independently, so a missing permission narrows the form rather than emptying it. An empty subnets list means no subnetworks exist in the selected region, or compute.subnetworks.list is denied. An empty firewall tags list means your rules do not target any network tags — rules that target the whole network have no tag to offer.

Deploy fails with "Quota … exceeded" or "does not have enough resources"​

These come back from Compute after the instance create is accepted, and USDN surfaces them on the deployment. Raise the quota, choose a different machine type, or pick another region.

Image list is empty or missing an image you expect​

Only images in your own project are listed, and deprecated or not-yet-ready images are filtered out. You can always paste an image path directly in the deploy form.

Security Posture​

  • No key material. USDN stores your project ID and number, pool and provider IDs, and the service account address. None of those are secrets.
  • Short-lived assertions. Every exchange uses a freshly minted JWT with a 15 minute lifetime, verified by Google against the public JWKS on the USDN issuer.
  • Scoped subject. The subject is specific to your USDN organization, so another organization's token cannot satisfy your binding.
  • Scoped audience. The audience is specific to your organization too, so another organization's token is rejected by your provider before the binding is even consulted. This matters because the binding in step 3 is the subject-pinned form; if you replace it with a pool-wide principalSet://.../workloadIdentityPools/<pool>/* binding, the subject stops being checked and the audience becomes the control that still holds.
  • You hold the off switch. Removing the roles/iam.workloadIdentityUser binding revokes USDN's access immediately, with no involvement from us.

Revoking Access​

# Immediate: stop USDN impersonating the service account
gcloud iam service-accounts remove-iam-policy-binding "$SA_EMAIL" \
--role="roles/iam.workloadIdentityUser" \
--member="principal://iam.googleapis.com/projects/<PROJECT_NUMBER>/locations/global/workloadIdentityPools/<POOL_ID>/subject/<SUBJECT>"

# Or remove the trust entirely
gcloud iam workload-identity-pools providers delete "$PROVIDER_ID" \
--project="$PROJECT_ID" --location="global" --workload-identity-pool="$POOL_ID"

Disconnecting the account in the USDN portal stops USDN from attempting any further calls, but the GCP-side binding is the authoritative revocation.