The gcp:iam/workloadIdentityPoolProvider:WorkloadIdentityPoolProvider resource, part of the Pulumi GCP provider, configures external identity providers that can authenticate to Google Cloud via Workload Identity Federation. This guide focuses on four capabilities: AWS IAM role federation, OIDC providers (Azure AD and GitHub Actions), attribute mapping and conditional access, and X.509 certificate validation.
Providers belong to WorkloadIdentityPools and reference external identity systems such as AWS accounts, Azure tenants, GitHub repositories, or certificate authorities. The examples are intentionally small. Combine them with your own IAM policy bindings to grant actual resource access.
Connect AWS workloads with minimal configuration
Teams migrating from AWS often need to grant AWS services access to GCP resources without managing long-lived credentials.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const pool = new gcp.iam.WorkloadIdentityPool("pool", {workloadIdentityPoolId: "example-pool"});
const example = new gcp.iam.WorkloadIdentityPoolProvider("example", {
workloadIdentityPoolId: pool.workloadIdentityPoolId,
workloadIdentityPoolProviderId: "example-prvdr",
aws: {
accountId: "999999999999",
},
});
import pulumi
import pulumi_gcp as gcp
pool = gcp.iam.WorkloadIdentityPool("pool", workload_identity_pool_id="example-pool")
example = gcp.iam.WorkloadIdentityPoolProvider("example",
workload_identity_pool_id=pool.workload_identity_pool_id,
workload_identity_pool_provider_id="example-prvdr",
aws={
"account_id": "999999999999",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := iam.NewWorkloadIdentityPool(ctx, "pool", &iam.WorkloadIdentityPoolArgs{
WorkloadIdentityPoolId: pulumi.String("example-pool"),
})
if err != nil {
return err
}
_, err = iam.NewWorkloadIdentityPoolProvider(ctx, "example", &iam.WorkloadIdentityPoolProviderArgs{
WorkloadIdentityPoolId: pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId: pulumi.String("example-prvdr"),
Aws: &iam.WorkloadIdentityPoolProviderAwsArgs{
AccountId: pulumi.String("999999999999"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var pool = new Gcp.Iam.WorkloadIdentityPool("pool", new()
{
WorkloadIdentityPoolId = "example-pool",
});
var example = new Gcp.Iam.WorkloadIdentityPoolProvider("example", new()
{
WorkloadIdentityPoolId = pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId = "example-prvdr",
Aws = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderAwsArgs
{
AccountId = "999999999999",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iam.WorkloadIdentityPool;
import com.pulumi.gcp.iam.WorkloadIdentityPoolArgs;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProvider;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProviderArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderAwsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new WorkloadIdentityPool("pool", WorkloadIdentityPoolArgs.builder()
.workloadIdentityPoolId("example-pool")
.build());
var example = new WorkloadIdentityPoolProvider("example", WorkloadIdentityPoolProviderArgs.builder()
.workloadIdentityPoolId(pool.workloadIdentityPoolId())
.workloadIdentityPoolProviderId("example-prvdr")
.aws(WorkloadIdentityPoolProviderAwsArgs.builder()
.accountId("999999999999")
.build())
.build());
}
}
resources:
pool:
type: gcp:iam:WorkloadIdentityPool
properties:
workloadIdentityPoolId: example-pool
example:
type: gcp:iam:WorkloadIdentityPoolProvider
properties:
workloadIdentityPoolId: ${pool.workloadIdentityPoolId}
workloadIdentityPoolProviderId: example-prvdr
aws:
accountId: '999999999999'
The aws block identifies the AWS account whose IAM roles can authenticate. The workloadIdentityPoolId references the pool this provider belongs to. When an AWS service assumes a role in the specified account, it can exchange AWS credentials for a GCP token.
Filter AWS identities with attribute mapping and conditions
Production environments need fine-grained control over which AWS identities can access GCP resources.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const pool = new gcp.iam.WorkloadIdentityPool("pool", {workloadIdentityPoolId: "example-pool"});
const example = new gcp.iam.WorkloadIdentityPoolProvider("example", {
workloadIdentityPoolId: pool.workloadIdentityPoolId,
workloadIdentityPoolProviderId: "example-prvdr",
displayName: "Name of provider",
description: "AWS identity pool provider for automated test",
disabled: true,
attributeCondition: "attribute.aws_role==\"arn:aws:sts::999999999999:assumed-role/stack-eu-central-1-lambdaRole\"",
attributeMapping: {
"google.subject": "assertion.arn",
"attribute.aws_account": "assertion.account",
"attribute.environment": "assertion.arn.contains(\":instance-profile/Production\") ? \"prod\" : \"test\"",
},
aws: {
accountId: "999999999999",
},
});
import pulumi
import pulumi_gcp as gcp
pool = gcp.iam.WorkloadIdentityPool("pool", workload_identity_pool_id="example-pool")
example = gcp.iam.WorkloadIdentityPoolProvider("example",
workload_identity_pool_id=pool.workload_identity_pool_id,
workload_identity_pool_provider_id="example-prvdr",
display_name="Name of provider",
description="AWS identity pool provider for automated test",
disabled=True,
attribute_condition="attribute.aws_role==\"arn:aws:sts::999999999999:assumed-role/stack-eu-central-1-lambdaRole\"",
attribute_mapping={
"google.subject": "assertion.arn",
"attribute.aws_account": "assertion.account",
"attribute.environment": "assertion.arn.contains(\":instance-profile/Production\") ? \"prod\" : \"test\"",
},
aws={
"account_id": "999999999999",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := iam.NewWorkloadIdentityPool(ctx, "pool", &iam.WorkloadIdentityPoolArgs{
WorkloadIdentityPoolId: pulumi.String("example-pool"),
})
if err != nil {
return err
}
_, err = iam.NewWorkloadIdentityPoolProvider(ctx, "example", &iam.WorkloadIdentityPoolProviderArgs{
WorkloadIdentityPoolId: pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId: pulumi.String("example-prvdr"),
DisplayName: pulumi.String("Name of provider"),
Description: pulumi.String("AWS identity pool provider for automated test"),
Disabled: pulumi.Bool(true),
AttributeCondition: pulumi.String("attribute.aws_role==\"arn:aws:sts::999999999999:assumed-role/stack-eu-central-1-lambdaRole\""),
AttributeMapping: pulumi.StringMap{
"google.subject": pulumi.String("assertion.arn"),
"attribute.aws_account": pulumi.String("assertion.account"),
"attribute.environment": pulumi.String("assertion.arn.contains(\":instance-profile/Production\") ? \"prod\" : \"test\""),
},
Aws: &iam.WorkloadIdentityPoolProviderAwsArgs{
AccountId: pulumi.String("999999999999"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var pool = new Gcp.Iam.WorkloadIdentityPool("pool", new()
{
WorkloadIdentityPoolId = "example-pool",
});
var example = new Gcp.Iam.WorkloadIdentityPoolProvider("example", new()
{
WorkloadIdentityPoolId = pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId = "example-prvdr",
DisplayName = "Name of provider",
Description = "AWS identity pool provider for automated test",
Disabled = true,
AttributeCondition = "attribute.aws_role==\"arn:aws:sts::999999999999:assumed-role/stack-eu-central-1-lambdaRole\"",
AttributeMapping =
{
{ "google.subject", "assertion.arn" },
{ "attribute.aws_account", "assertion.account" },
{ "attribute.environment", "assertion.arn.contains(\":instance-profile/Production\") ? \"prod\" : \"test\"" },
},
Aws = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderAwsArgs
{
AccountId = "999999999999",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iam.WorkloadIdentityPool;
import com.pulumi.gcp.iam.WorkloadIdentityPoolArgs;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProvider;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProviderArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderAwsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new WorkloadIdentityPool("pool", WorkloadIdentityPoolArgs.builder()
.workloadIdentityPoolId("example-pool")
.build());
var example = new WorkloadIdentityPoolProvider("example", WorkloadIdentityPoolProviderArgs.builder()
.workloadIdentityPoolId(pool.workloadIdentityPoolId())
.workloadIdentityPoolProviderId("example-prvdr")
.displayName("Name of provider")
.description("AWS identity pool provider for automated test")
.disabled(true)
.attributeCondition("attribute.aws_role==\"arn:aws:sts::999999999999:assumed-role/stack-eu-central-1-lambdaRole\"")
.attributeMapping(Map.ofEntries(
Map.entry("google.subject", "assertion.arn"),
Map.entry("attribute.aws_account", "assertion.account"),
Map.entry("attribute.environment", "assertion.arn.contains(\":instance-profile/Production\") ? \"prod\" : \"test\"")
))
.aws(WorkloadIdentityPoolProviderAwsArgs.builder()
.accountId("999999999999")
.build())
.build());
}
}
resources:
pool:
type: gcp:iam:WorkloadIdentityPool
properties:
workloadIdentityPoolId: example-pool
example:
type: gcp:iam:WorkloadIdentityPoolProvider
properties:
workloadIdentityPoolId: ${pool.workloadIdentityPoolId}
workloadIdentityPoolProviderId: example-prvdr
displayName: Name of provider
description: AWS identity pool provider for automated test
disabled: true
attributeCondition: attribute.aws_role=="arn:aws:sts::999999999999:assumed-role/stack-eu-central-1-lambdaRole"
attributeMapping:
google.subject: assertion.arn
attribute.aws_account: assertion.account
attribute.environment: 'assertion.arn.contains(":instance-profile/Production") ? "prod" : "test"'
aws:
accountId: '999999999999'
Attribute mapping extracts claims from AWS credentials into GCP principals. The google.subject mapping creates a principal identifier from the AWS role ARN. The attributeCondition restricts access to a specific assumed role. Custom attributes like attribute.environment use CEL expressions to classify workloads based on their ARN patterns. The disabled property prevents token exchange while preserving the configuration.
Authenticate GitHub Actions workflows to GCP
CI/CD pipelines running in GitHub Actions can deploy to GCP without storing service account keys.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const pool = new gcp.iam.WorkloadIdentityPool("pool", {workloadIdentityPoolId: "example-pool"});
const example = new gcp.iam.WorkloadIdentityPoolProvider("example", {
workloadIdentityPoolId: pool.workloadIdentityPoolId,
workloadIdentityPoolProviderId: "example-prvdr",
displayName: "Name of provider",
description: "GitHub Actions identity pool provider for automated test",
disabled: true,
attributeCondition: ` assertion.repository_owner_id == \\"123456789\\" &&
attribute.repository == \\"gh-org/gh-repo\\" &&
assertion.ref == \\"refs/heads/main\\" &&
assertion.ref_type == \\"branch\\"
`,
attributeMapping: {
"google.subject": "assertion.sub",
"attribute.actor": "assertion.actor",
"attribute.aud": "assertion.aud",
"attribute.repository": "assertion.repository",
},
oidc: {
issuerUri: "https://token.actions.githubusercontent.com",
},
});
import pulumi
import pulumi_gcp as gcp
pool = gcp.iam.WorkloadIdentityPool("pool", workload_identity_pool_id="example-pool")
example = gcp.iam.WorkloadIdentityPoolProvider("example",
workload_identity_pool_id=pool.workload_identity_pool_id,
workload_identity_pool_provider_id="example-prvdr",
display_name="Name of provider",
description="GitHub Actions identity pool provider for automated test",
disabled=True,
attribute_condition=""" assertion.repository_owner_id == \"123456789\" &&
attribute.repository == \"gh-org/gh-repo\" &&
assertion.ref == \"refs/heads/main\" &&
assertion.ref_type == \"branch\"
""",
attribute_mapping={
"google.subject": "assertion.sub",
"attribute.actor": "assertion.actor",
"attribute.aud": "assertion.aud",
"attribute.repository": "assertion.repository",
},
oidc={
"issuer_uri": "https://token.actions.githubusercontent.com",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := iam.NewWorkloadIdentityPool(ctx, "pool", &iam.WorkloadIdentityPoolArgs{
WorkloadIdentityPoolId: pulumi.String("example-pool"),
})
if err != nil {
return err
}
_, err = iam.NewWorkloadIdentityPoolProvider(ctx, "example", &iam.WorkloadIdentityPoolProviderArgs{
WorkloadIdentityPoolId: pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId: pulumi.String("example-prvdr"),
DisplayName: pulumi.String("Name of provider"),
Description: pulumi.String("GitHub Actions identity pool provider for automated test"),
Disabled: pulumi.Bool(true),
AttributeCondition: pulumi.String(" assertion.repository_owner_id == \\\"123456789\\\" &&\n attribute.repository == \\\"gh-org/gh-repo\\\" &&\n assertion.ref == \\\"refs/heads/main\\\" &&\n assertion.ref_type == \\\"branch\\\"\n"),
AttributeMapping: pulumi.StringMap{
"google.subject": pulumi.String("assertion.sub"),
"attribute.actor": pulumi.String("assertion.actor"),
"attribute.aud": pulumi.String("assertion.aud"),
"attribute.repository": pulumi.String("assertion.repository"),
},
Oidc: &iam.WorkloadIdentityPoolProviderOidcArgs{
IssuerUri: pulumi.String("https://token.actions.githubusercontent.com"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var pool = new Gcp.Iam.WorkloadIdentityPool("pool", new()
{
WorkloadIdentityPoolId = "example-pool",
});
var example = new Gcp.Iam.WorkloadIdentityPoolProvider("example", new()
{
WorkloadIdentityPoolId = pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId = "example-prvdr",
DisplayName = "Name of provider",
Description = "GitHub Actions identity pool provider for automated test",
Disabled = true,
AttributeCondition = @" assertion.repository_owner_id == \""123456789\"" &&
attribute.repository == \""gh-org/gh-repo\"" &&
assertion.ref == \""refs/heads/main\"" &&
assertion.ref_type == \""branch\""
",
AttributeMapping =
{
{ "google.subject", "assertion.sub" },
{ "attribute.actor", "assertion.actor" },
{ "attribute.aud", "assertion.aud" },
{ "attribute.repository", "assertion.repository" },
},
Oidc = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderOidcArgs
{
IssuerUri = "https://token.actions.githubusercontent.com",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iam.WorkloadIdentityPool;
import com.pulumi.gcp.iam.WorkloadIdentityPoolArgs;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProvider;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProviderArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderOidcArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new WorkloadIdentityPool("pool", WorkloadIdentityPoolArgs.builder()
.workloadIdentityPoolId("example-pool")
.build());
var example = new WorkloadIdentityPoolProvider("example", WorkloadIdentityPoolProviderArgs.builder()
.workloadIdentityPoolId(pool.workloadIdentityPoolId())
.workloadIdentityPoolProviderId("example-prvdr")
.displayName("Name of provider")
.description("GitHub Actions identity pool provider for automated test")
.disabled(true)
.attributeCondition("""
assertion.repository_owner_id == \"123456789\" &&
attribute.repository == \"gh-org/gh-repo\" &&
assertion.ref == \"refs/heads/main\" &&
assertion.ref_type == \"branch\"
""")
.attributeMapping(Map.ofEntries(
Map.entry("google.subject", "assertion.sub"),
Map.entry("attribute.actor", "assertion.actor"),
Map.entry("attribute.aud", "assertion.aud"),
Map.entry("attribute.repository", "assertion.repository")
))
.oidc(WorkloadIdentityPoolProviderOidcArgs.builder()
.issuerUri("https://token.actions.githubusercontent.com")
.build())
.build());
}
}
resources:
pool:
type: gcp:iam:WorkloadIdentityPool
properties:
workloadIdentityPoolId: example-pool
example:
type: gcp:iam:WorkloadIdentityPoolProvider
properties:
workloadIdentityPoolId: ${pool.workloadIdentityPoolId}
workloadIdentityPoolProviderId: example-prvdr
displayName: Name of provider
description: GitHub Actions identity pool provider for automated test
disabled: true
attributeCondition: |2
assertion.repository_owner_id == \"123456789\" &&
attribute.repository == \"gh-org/gh-repo\" &&
assertion.ref == \"refs/heads/main\" &&
assertion.ref_type == \"branch\"
attributeMapping:
google.subject: assertion.sub
attribute.actor: assertion.actor
attribute.aud: assertion.aud
attribute.repository: assertion.repository
oidc:
issuerUri: https://token.actions.githubusercontent.com
The oidc block points to GitHub’s token endpoint. Attribute mapping extracts repository and actor information from GitHub’s JWT tokens. The attributeCondition enforces that only workflows from a specific repository owner, repository, and branch can authenticate. This enables keyless deployment from GitHub Actions to GCP.
Connect Azure AD with minimal OIDC configuration
Azure workloads authenticate to GCP using Azure AD’s OIDC endpoint.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const pool = new gcp.iam.WorkloadIdentityPool("pool", {workloadIdentityPoolId: "example-pool"});
const example = new gcp.iam.WorkloadIdentityPoolProvider("example", {
workloadIdentityPoolId: pool.workloadIdentityPoolId,
workloadIdentityPoolProviderId: "example-prvdr",
attributeMapping: {
"google.subject": "assertion.sub",
},
oidc: {
issuerUri: "https://sts.windows.net/azure-tenant-id",
},
});
import pulumi
import pulumi_gcp as gcp
pool = gcp.iam.WorkloadIdentityPool("pool", workload_identity_pool_id="example-pool")
example = gcp.iam.WorkloadIdentityPoolProvider("example",
workload_identity_pool_id=pool.workload_identity_pool_id,
workload_identity_pool_provider_id="example-prvdr",
attribute_mapping={
"google.subject": "assertion.sub",
},
oidc={
"issuer_uri": "https://sts.windows.net/azure-tenant-id",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := iam.NewWorkloadIdentityPool(ctx, "pool", &iam.WorkloadIdentityPoolArgs{
WorkloadIdentityPoolId: pulumi.String("example-pool"),
})
if err != nil {
return err
}
_, err = iam.NewWorkloadIdentityPoolProvider(ctx, "example", &iam.WorkloadIdentityPoolProviderArgs{
WorkloadIdentityPoolId: pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId: pulumi.String("example-prvdr"),
AttributeMapping: pulumi.StringMap{
"google.subject": pulumi.String("assertion.sub"),
},
Oidc: &iam.WorkloadIdentityPoolProviderOidcArgs{
IssuerUri: pulumi.String("https://sts.windows.net/azure-tenant-id"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var pool = new Gcp.Iam.WorkloadIdentityPool("pool", new()
{
WorkloadIdentityPoolId = "example-pool",
});
var example = new Gcp.Iam.WorkloadIdentityPoolProvider("example", new()
{
WorkloadIdentityPoolId = pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId = "example-prvdr",
AttributeMapping =
{
{ "google.subject", "assertion.sub" },
},
Oidc = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderOidcArgs
{
IssuerUri = "https://sts.windows.net/azure-tenant-id",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iam.WorkloadIdentityPool;
import com.pulumi.gcp.iam.WorkloadIdentityPoolArgs;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProvider;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProviderArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderOidcArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new WorkloadIdentityPool("pool", WorkloadIdentityPoolArgs.builder()
.workloadIdentityPoolId("example-pool")
.build());
var example = new WorkloadIdentityPoolProvider("example", WorkloadIdentityPoolProviderArgs.builder()
.workloadIdentityPoolId(pool.workloadIdentityPoolId())
.workloadIdentityPoolProviderId("example-prvdr")
.attributeMapping(Map.of("google.subject", "assertion.sub"))
.oidc(WorkloadIdentityPoolProviderOidcArgs.builder()
.issuerUri("https://sts.windows.net/azure-tenant-id")
.build())
.build());
}
}
resources:
pool:
type: gcp:iam:WorkloadIdentityPool
properties:
workloadIdentityPoolId: example-pool
example:
type: gcp:iam:WorkloadIdentityPoolProvider
properties:
workloadIdentityPoolId: ${pool.workloadIdentityPoolId}
workloadIdentityPoolProviderId: example-prvdr
attributeMapping:
google.subject: assertion.sub
oidc:
issuerUri: https://sts.windows.net/azure-tenant-id
The issuerUri points to Azure AD’s token endpoint for your tenant. The attributeMapping maps Azure’s standard subject claim (assertion.sub) to the GCP principal identifier (google.subject). This minimal configuration enables Azure managed identities to access GCP resources.
Map Azure managed identities with custom attributes
Azure managed identities often need meaningful names in GCP IAM policies rather than opaque object IDs.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
const pool = new gcp.iam.WorkloadIdentityPool("pool", {workloadIdentityPoolId: "example-pool"});
const example = new gcp.iam.WorkloadIdentityPoolProvider("example", {
workloadIdentityPoolId: pool.workloadIdentityPoolId,
workloadIdentityPoolProviderId: "example-prvdr",
displayName: "Name of provider",
description: "OIDC identity pool provider for automated test",
disabled: true,
attributeCondition: "\"e968c2ef-047c-498d-8d79-16ca1b61e77e\" in assertion.groups",
attributeMapping: {
"google.subject": "\"azure::\" + assertion.tid + \"::\" + assertion.sub",
"attribute.tid": "assertion.tid",
"attribute.managed_identity_name": ` {
\\"8bb39bdb-1cc5-4447-b7db-a19e920eb111\\":\\"workload1\\",
\\"55d36609-9bcf-48e0-a366-a3cf19027d2a\\":\\"workload2\\"
}[assertion.oid]
`,
},
oidc: {
allowedAudiences: [
"https://example.com/gcp-oidc-federation",
"example.com/gcp-oidc-federation",
],
issuerUri: "https://sts.windows.net/azure-tenant-id",
},
});
import pulumi
import pulumi_gcp as gcp
pool = gcp.iam.WorkloadIdentityPool("pool", workload_identity_pool_id="example-pool")
example = gcp.iam.WorkloadIdentityPoolProvider("example",
workload_identity_pool_id=pool.workload_identity_pool_id,
workload_identity_pool_provider_id="example-prvdr",
display_name="Name of provider",
description="OIDC identity pool provider for automated test",
disabled=True,
attribute_condition="\"e968c2ef-047c-498d-8d79-16ca1b61e77e\" in assertion.groups",
attribute_mapping={
"google.subject": "\"azure::\" + assertion.tid + \"::\" + assertion.sub",
"attribute.tid": "assertion.tid",
"attribute.managed_identity_name": """ {
\"8bb39bdb-1cc5-4447-b7db-a19e920eb111\":\"workload1\",
\"55d36609-9bcf-48e0-a366-a3cf19027d2a\":\"workload2\"
}[assertion.oid]
""",
},
oidc={
"allowed_audiences": [
"https://example.com/gcp-oidc-federation",
"example.com/gcp-oidc-federation",
],
"issuer_uri": "https://sts.windows.net/azure-tenant-id",
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iam"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := iam.NewWorkloadIdentityPool(ctx, "pool", &iam.WorkloadIdentityPoolArgs{
WorkloadIdentityPoolId: pulumi.String("example-pool"),
})
if err != nil {
return err
}
_, err = iam.NewWorkloadIdentityPoolProvider(ctx, "example", &iam.WorkloadIdentityPoolProviderArgs{
WorkloadIdentityPoolId: pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId: pulumi.String("example-prvdr"),
DisplayName: pulumi.String("Name of provider"),
Description: pulumi.String("OIDC identity pool provider for automated test"),
Disabled: pulumi.Bool(true),
AttributeCondition: pulumi.String("\"e968c2ef-047c-498d-8d79-16ca1b61e77e\" in assertion.groups"),
AttributeMapping: pulumi.StringMap{
"google.subject": pulumi.String("\"azure::\" + assertion.tid + \"::\" + assertion.sub"),
"attribute.tid": pulumi.String("assertion.tid"),
"attribute.managed_identity_name": pulumi.String(" {\n \\\"8bb39bdb-1cc5-4447-b7db-a19e920eb111\\\":\\\"workload1\\\",\n \\\"55d36609-9bcf-48e0-a366-a3cf19027d2a\\\":\\\"workload2\\\"\n }[assertion.oid]\n"),
},
Oidc: &iam.WorkloadIdentityPoolProviderOidcArgs{
AllowedAudiences: pulumi.StringArray{
pulumi.String("https://example.com/gcp-oidc-federation"),
pulumi.String("example.com/gcp-oidc-federation"),
},
IssuerUri: pulumi.String("https://sts.windows.net/azure-tenant-id"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
return await Deployment.RunAsync(() =>
{
var pool = new Gcp.Iam.WorkloadIdentityPool("pool", new()
{
WorkloadIdentityPoolId = "example-pool",
});
var example = new Gcp.Iam.WorkloadIdentityPoolProvider("example", new()
{
WorkloadIdentityPoolId = pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId = "example-prvdr",
DisplayName = "Name of provider",
Description = "OIDC identity pool provider for automated test",
Disabled = true,
AttributeCondition = "\"e968c2ef-047c-498d-8d79-16ca1b61e77e\" in assertion.groups",
AttributeMapping =
{
{ "google.subject", "\"azure::\" + assertion.tid + \"::\" + assertion.sub" },
{ "attribute.tid", "assertion.tid" },
{ "attribute.managed_identity_name", @" {
\""8bb39bdb-1cc5-4447-b7db-a19e920eb111\"":\""workload1\"",
\""55d36609-9bcf-48e0-a366-a3cf19027d2a\"":\""workload2\""
}[assertion.oid]
" },
},
Oidc = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderOidcArgs
{
AllowedAudiences = new[]
{
"https://example.com/gcp-oidc-federation",
"example.com/gcp-oidc-federation",
},
IssuerUri = "https://sts.windows.net/azure-tenant-id",
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iam.WorkloadIdentityPool;
import com.pulumi.gcp.iam.WorkloadIdentityPoolArgs;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProvider;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProviderArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderOidcArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new WorkloadIdentityPool("pool", WorkloadIdentityPoolArgs.builder()
.workloadIdentityPoolId("example-pool")
.build());
var example = new WorkloadIdentityPoolProvider("example", WorkloadIdentityPoolProviderArgs.builder()
.workloadIdentityPoolId(pool.workloadIdentityPoolId())
.workloadIdentityPoolProviderId("example-prvdr")
.displayName("Name of provider")
.description("OIDC identity pool provider for automated test")
.disabled(true)
.attributeCondition("\"e968c2ef-047c-498d-8d79-16ca1b61e77e\" in assertion.groups")
.attributeMapping(Map.ofEntries(
Map.entry("google.subject", "\"azure::\" + assertion.tid + \"::\" + assertion.sub"),
Map.entry("attribute.tid", "assertion.tid"),
Map.entry("attribute.managed_identity_name", """
{
\"8bb39bdb-1cc5-4447-b7db-a19e920eb111\":\"workload1\",
\"55d36609-9bcf-48e0-a366-a3cf19027d2a\":\"workload2\"
}[assertion.oid]
""")
))
.oidc(WorkloadIdentityPoolProviderOidcArgs.builder()
.allowedAudiences(
"https://example.com/gcp-oidc-federation",
"example.com/gcp-oidc-federation")
.issuerUri("https://sts.windows.net/azure-tenant-id")
.build())
.build());
}
}
resources:
pool:
type: gcp:iam:WorkloadIdentityPool
properties:
workloadIdentityPoolId: example-pool
example:
type: gcp:iam:WorkloadIdentityPoolProvider
properties:
workloadIdentityPoolId: ${pool.workloadIdentityPoolId}
workloadIdentityPoolProviderId: example-prvdr
displayName: Name of provider
description: OIDC identity pool provider for automated test
disabled: true
attributeCondition: '"e968c2ef-047c-498d-8d79-16ca1b61e77e" in assertion.groups'
attributeMapping:
google.subject: '"azure::" + assertion.tid + "::" + assertion.sub'
attribute.tid: assertion.tid
attribute.managed_identity_name: |2
{
\"8bb39bdb-1cc5-4447-b7db-a19e920eb111\":\"workload1\",
\"55d36609-9bcf-48e0-a366-a3cf19027d2a\":\"workload2\"
}[assertion.oid]
oidc:
allowedAudiences:
- https://example.com/gcp-oidc-federation
- example.com/gcp-oidc-federation
issuerUri: https://sts.windows.net/azure-tenant-id
Custom attribute mapping translates Azure object IDs into human-readable workload names using a lookup table. The google.subject combines tenant ID and subscription ID for uniqueness. The attributeCondition filters by Azure AD group membership. The allowedAudiences property restricts which token audiences are accepted, preventing token reuse across different systems.
Trust X.509 certificates from a root CA
On-premises workloads or IoT devices often use X.509 certificates for authentication.
import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";
const pool = new gcp.iam.WorkloadIdentityPool("pool", {workloadIdentityPoolId: "example-pool"});
const example = new gcp.iam.WorkloadIdentityPoolProvider("example", {
workloadIdentityPoolId: pool.workloadIdentityPoolId,
workloadIdentityPoolProviderId: "example-prvdr",
attributeMapping: {
"google.subject": "assertion.subject.dn.cn",
},
x509: {
trustStore: {
trustAnchors: [{
pemCertificate: std.file({
input: "test-fixtures/trust_anchor.pem",
}).then(invoke => invoke.result),
}],
},
},
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std
pool = gcp.iam.WorkloadIdentityPool("pool", workload_identity_pool_id="example-pool")
example = gcp.iam.WorkloadIdentityPoolProvider("example",
workload_identity_pool_id=pool.workload_identity_pool_id,
workload_identity_pool_provider_id="example-prvdr",
attribute_mapping={
"google.subject": "assertion.subject.dn.cn",
},
x509={
"trust_store": {
"trust_anchors": [{
"pem_certificate": std.file(input="test-fixtures/trust_anchor.pem").result,
}],
},
})
package main
import (
"github.com/pulumi/pulumi-gcp/sdk/v9/go/gcp/iam"
"github.com/pulumi/pulumi-std/sdk/go/std"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
pool, err := iam.NewWorkloadIdentityPool(ctx, "pool", &iam.WorkloadIdentityPoolArgs{
WorkloadIdentityPoolId: pulumi.String("example-pool"),
})
if err != nil {
return err
}
invokeFile, err := std.File(ctx, &std.FileArgs{
Input: "test-fixtures/trust_anchor.pem",
}, nil)
if err != nil {
return err
}
_, err = iam.NewWorkloadIdentityPoolProvider(ctx, "example", &iam.WorkloadIdentityPoolProviderArgs{
WorkloadIdentityPoolId: pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId: pulumi.String("example-prvdr"),
AttributeMapping: pulumi.StringMap{
"google.subject": pulumi.String("assertion.subject.dn.cn"),
},
X509: &iam.WorkloadIdentityPoolProviderX509Args{
TrustStore: &iam.WorkloadIdentityPoolProviderX509TrustStoreArgs{
TrustAnchors: iam.WorkloadIdentityPoolProviderX509TrustStoreTrustAnchorArray{
&iam.WorkloadIdentityPoolProviderX509TrustStoreTrustAnchorArgs{
PemCertificate: pulumi.String(invokeFile.Result),
},
},
},
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Gcp = Pulumi.Gcp;
using Std = Pulumi.Std;
return await Deployment.RunAsync(() =>
{
var pool = new Gcp.Iam.WorkloadIdentityPool("pool", new()
{
WorkloadIdentityPoolId = "example-pool",
});
var example = new Gcp.Iam.WorkloadIdentityPoolProvider("example", new()
{
WorkloadIdentityPoolId = pool.WorkloadIdentityPoolId,
WorkloadIdentityPoolProviderId = "example-prvdr",
AttributeMapping =
{
{ "google.subject", "assertion.subject.dn.cn" },
},
X509 = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderX509Args
{
TrustStore = new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderX509TrustStoreArgs
{
TrustAnchors = new[]
{
new Gcp.Iam.Inputs.WorkloadIdentityPoolProviderX509TrustStoreTrustAnchorArgs
{
PemCertificate = Std.File.Invoke(new()
{
Input = "test-fixtures/trust_anchor.pem",
}).Apply(invoke => invoke.Result),
},
},
},
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.gcp.iam.WorkloadIdentityPool;
import com.pulumi.gcp.iam.WorkloadIdentityPoolArgs;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProvider;
import com.pulumi.gcp.iam.WorkloadIdentityPoolProviderArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderX509Args;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolProviderX509TrustStoreArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.FileArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var pool = new WorkloadIdentityPool("pool", WorkloadIdentityPoolArgs.builder()
.workloadIdentityPoolId("example-pool")
.build());
var example = new WorkloadIdentityPoolProvider("example", WorkloadIdentityPoolProviderArgs.builder()
.workloadIdentityPoolId(pool.workloadIdentityPoolId())
.workloadIdentityPoolProviderId("example-prvdr")
.attributeMapping(Map.of("google.subject", "assertion.subject.dn.cn"))
.x509(WorkloadIdentityPoolProviderX509Args.builder()
.trustStore(WorkloadIdentityPoolProviderX509TrustStoreArgs.builder()
.trustAnchors(WorkloadIdentityPoolProviderX509TrustStoreTrustAnchorArgs.builder()
.pemCertificate(StdFunctions.file(FileArgs.builder()
.input("test-fixtures/trust_anchor.pem")
.build()).result())
.build())
.build())
.build())
.build());
}
}
resources:
pool:
type: gcp:iam:WorkloadIdentityPool
properties:
workloadIdentityPoolId: example-pool
example:
type: gcp:iam:WorkloadIdentityPoolProvider
properties:
workloadIdentityPoolId: ${pool.workloadIdentityPoolId}
workloadIdentityPoolProviderId: example-prvdr
attributeMapping:
google.subject: assertion.subject.dn.cn
x509:
trustStore:
trustAnchors:
- pemCertificate:
fn::invoke:
function: std:file
arguments:
input: test-fixtures/trust_anchor.pem
return: result
The x509 block defines a trust store with root certificate anchors. The trustAnchors array contains PEM-encoded certificates that serve as trust roots. The attributeMapping extracts the Common Name from the certificate’s Distinguished Name (assertion.subject.dn.cn) and maps it to the GCP principal. Any certificate that chains to these trust anchors can authenticate.
Beyond these examples
These snippets focus on specific provider-level features: AWS, Azure, and GitHub OIDC federation, attribute mapping and conditional access, and X.509 certificate-based authentication. They’re intentionally minimal rather than complete federation configurations.
The examples reference pre-existing infrastructure such as WorkloadIdentityPool resources, external identity provider configurations (AWS accounts, Azure tenants, GitHub repos), and certificate files for X.509 providers. They focus on configuring the provider rather than provisioning the surrounding IAM infrastructure.
To keep things focused, common provider patterns are omitted, including:
- SAML 2.0 identity providers (saml block)
- Custom JWKS upload for OIDC (jwksJson)
- Intermediate CAs for X.509 trust chains
- IAM policy bindings to grant actual resource access
These omissions are intentional: the goal is to illustrate how each provider type is wired, not provide drop-in federation modules. See the Workload Identity Pool Provider resource reference for all available configuration options.
Let's configure GCP Workload Identity Pool Providers
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Configuration & Setup
aws, oidc, saml, x509) are mutually exclusive. You must choose exactly one provider type per WorkloadIdentityPoolProvider resource.workloadIdentityPoolId and workloadIdentityPoolProviderId must be 4-32 characters, contain only [a-z0-9-], and cannot use the gcp- prefix (reserved for Google).workloadIdentityPoolId, workloadIdentityPoolProviderId, and project properties cannot be changed after creation. Modifying these requires recreating the resource.Attribute Mapping & Identity Federation
attributeMapping is required and must include google.subject. For AWS providers, a default mapping is applied if none is defined, but custom mappings must also include google.subject.assertion.arn to google.subject). OIDC providers require you to explicitly define custom mappings, and they must include google.subject (e.g., {"google.subject": "assertion.sub"}).[a-z0-9_]), expressions can be up to 2048 characters, and the total size of all mapped attributes must not exceed 8KB.oidc.issuerUri to https://token.actions.githubusercontent.com and define attributeMapping with google.subject mapped to assertion.sub. You can also map GitHub-specific claims like assertion.actor and assertion.repository.Provider Lifecycle & Behavior
Advanced Configuration
saml property with idpMetadataXml, loading the XML content from a file using std.file() (e.g., std.file({input: "metadata.xml"}).then(invoke => invoke.result)).oidc.jwksJson property to provide the JSON Web Key Set directly instead of relying on the issuer’s JWKS endpoint.