The gcp:iam/workloadIdentityPoolProvider:WorkloadIdentityPoolProvider resource, part of the Pulumi GCP provider, configures external identity providers that can authenticate to Google Cloud without service account keys. This guide focuses on three capabilities: AWS IAM role federation, OIDC provider configuration for Azure and GitHub, and X.509 certificate-based authentication.
Providers belong to WorkloadIdentityPool resources and reference external identity systems such as AWS accounts, Azure tenants, or certificate authorities. The examples are intentionally small. Combine them with IAM policy bindings to grant actual access to GCP resources.
Connect AWS workloads with minimal configuration
Teams migrating from AWS often need to grant AWS services access to GCP resources without managing 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 presents credentials, GCP validates the account ID matches before issuing a token.
Filter AWS credentials 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'
The attributeMapping block extracts claims from AWS credentials and maps them to GCP attributes. The google.subject mapping determines the principal identifier in IAM bindings. The attributeCondition filters credentials, accepting only those from a specific assumed role. Custom attributes like attribute.environment enable conditional access based on AWS resource paths.
Authenticate GitHub Actions workflows to GCP
CI/CD pipelines in GitHub Actions can deploy to GCP using OIDC tokens instead of 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 configures GitHub’s token endpoint as the issuer. The attributeCondition restricts access to a specific repository owner, repository, and branch. The attributeMapping extracts GitHub-specific claims like actor and repository for audit logging and conditional access.
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, with the tenant ID embedded in the URL. The attributeMapping maps Azure’s standard sub claim to google.subject. This minimal configuration enables Azure managed identities to exchange tokens for GCP credentials.
Map Azure managed identities with custom attributes
Azure deployments with multiple managed identities need to extract Azure-specific claims for access control.
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
The allowedAudiences property restricts which token audiences are accepted. The attributeMapping extracts Azure tenant ID (tid) and object ID (oid), then uses a dictionary lookup to map object IDs to human-readable workload names. The attributeCondition checks group membership before accepting credentials.
Trust X.509 certificates from a root CA
On-premises workloads with PKI infrastructure can authenticate using X.509 certificates.
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 CA certificates. The trustAnchors array lists PEM-encoded certificates that anchor the trust chain. The attributeMapping extracts the common name from the certificate’s distinguished name as the subject. GCP validates that presented certificates chain to these trust anchors before issuing tokens.
Beyond these examples
These snippets focus on specific provider-level features: AWS, OIDC, SAML, and X.509 identity providers, attribute mapping and conditional access, and audience restrictions and custom claims. They’re intentionally minimal rather than full 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 and SAML providers. They focus on configuring the provider rather than provisioning IAM bindings or service accounts.
To keep things focused, common provider patterns are omitted, including:
- IAM policy bindings to grant provider access to GCP resources
- Service account impersonation configuration
- JWKS JSON configuration for custom OIDC providers
- Intermediate CA certificates for X.509 trust chains
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
Provider Configuration & Types
aws, oidc, saml, x509) are mutually exclusive. You must choose exactly one provider type per WorkloadIdentityPoolProvider resource.oidc property with issuerUri set to https://token.actions.githubusercontent.com. You can add attributeCondition to restrict access by repository owner, branch, or other assertion fields.oidc.jwksJson property to provide your JSON Web Key Set directly instead of relying on automatic discovery.Attribute Mapping Requirements
attributeMapping that includes a mapping to google.subject. For example: {"google.subject": "assertion.sub"}. This is mandatory for OIDC providers.attributeMapping that maps assertion.arn to google.subject. However, if you define custom mappings, you must include google.subject.[a-z0-9_]. Each mapping expression has a 2048-character limit, and the total size of all mapped attributes must not exceed 8KB when evaluated.Immutability & Lifecycle
workloadIdentityPoolId, workloadIdentityPoolProviderId, and project properties are immutable. Changing these requires recreating the resource.disabled to false.Naming & Character Limits
gcp- prefix is reserved for use by Google and cannot be specified in workloadIdentityPoolId or workloadIdentityPoolProviderId.[a-z0-9-]. The displayName has a 32-character limit, description has a 256-character limit, and google.subject cannot exceed 127 characters.