Configure GCP Workload Identity Pools

The gcp:iam/workloadIdentityPool:WorkloadIdentityPool resource, part of the Pulumi GCP provider, defines a workload identity pool that groups external or Google Cloud workload identities for IAM policy assignment. This guide focuses on three capabilities: basic pool creation for external federation, metadata and state control, and mTLS certificate issuance for Google Cloud workloads.

Pools operate in two modes: FEDERATION_ONLY (for external identities like AWS or GitHub Actions, requires provider resources) or TRUST_DOMAIN (for Google Cloud workloads like GKE or Compute Engine, requires CA pools and trust anchors). The examples are intentionally small. Combine them with WorkloadIdentityPoolProvider resources and IAM bindings for complete authentication flows.

Create a minimal pool for external identity federation

Most deployments start with a basic pool that federates external identities into Google Cloud without additional constraints.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const example = new gcp.iam.WorkloadIdentityPool("example", {workloadIdentityPoolId: "example-pool"});
import pulumi
import pulumi_gcp as gcp

example = gcp.iam.WorkloadIdentityPool("example", workload_identity_pool_id="example-pool")
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 {
		_, err := iam.NewWorkloadIdentityPool(ctx, "example", &iam.WorkloadIdentityPoolArgs{
			WorkloadIdentityPoolId: pulumi.String("example-pool"),
		})
		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 example = new Gcp.Iam.WorkloadIdentityPool("example", new()
    {
        WorkloadIdentityPoolId = "example-pool",
    });

});
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 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 example = new WorkloadIdentityPool("example", WorkloadIdentityPoolArgs.builder()
            .workloadIdentityPoolId("example-pool")
            .build());

    }
}
resources:
  example:
    type: gcp:iam:WorkloadIdentityPool
    properties:
      workloadIdentityPoolId: example-pool

The workloadIdentityPoolId sets the pool’s identifier, which becomes part of the resource name. Without specifying mode, the pool operates in FEDERATION_ONLY mode by default. The pool itself doesn’t grant access; you must create WorkloadIdentityPoolProvider resources to define how external tokens map to Google Cloud identities.

Configure federation with display metadata and state control

Production pools often include display names and descriptions for organization, and may start disabled for testing.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";

const example = new gcp.iam.WorkloadIdentityPool("example", {
    workloadIdentityPoolId: "example-pool",
    displayName: "Name of the pool",
    description: "Identity pool operates in FEDERATION_ONLY mode",
    disabled: true,
    mode: "FEDERATION_ONLY",
});
import pulumi
import pulumi_gcp as gcp

example = gcp.iam.WorkloadIdentityPool("example",
    workload_identity_pool_id="example-pool",
    display_name="Name of the pool",
    description="Identity pool operates in FEDERATION_ONLY mode",
    disabled=True,
    mode="FEDERATION_ONLY")
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 {
		_, err := iam.NewWorkloadIdentityPool(ctx, "example", &iam.WorkloadIdentityPoolArgs{
			WorkloadIdentityPoolId: pulumi.String("example-pool"),
			DisplayName:            pulumi.String("Name of the pool"),
			Description:            pulumi.String("Identity pool operates in FEDERATION_ONLY mode"),
			Disabled:               pulumi.Bool(true),
			Mode:                   pulumi.String("FEDERATION_ONLY"),
		})
		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 example = new Gcp.Iam.WorkloadIdentityPool("example", new()
    {
        WorkloadIdentityPoolId = "example-pool",
        DisplayName = "Name of the pool",
        Description = "Identity pool operates in FEDERATION_ONLY mode",
        Disabled = true,
        Mode = "FEDERATION_ONLY",
    });

});
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 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 example = new WorkloadIdentityPool("example", WorkloadIdentityPoolArgs.builder()
            .workloadIdentityPoolId("example-pool")
            .displayName("Name of the pool")
            .description("Identity pool operates in FEDERATION_ONLY mode")
            .disabled(true)
            .mode("FEDERATION_ONLY")
            .build());

    }
}
resources:
  example:
    type: gcp:iam:WorkloadIdentityPool
    properties:
      workloadIdentityPoolId: example-pool
      displayName: Name of the pool
      description: Identity pool operates in FEDERATION_ONLY mode
      disabled: true
      mode: FEDERATION_ONLY

The displayName and description properties add organizational metadata. The disabled property controls whether the pool can exchange tokens; set it to true during setup, then flip to false when ready. The mode property explicitly sets FEDERATION_ONLY, though this is the default. Note that mode cannot be changed after creation; you must create a new pool to switch modes.

Issue mTLS certificates for Google Cloud workloads

TRUST_DOMAIN mode pools assign identities to Google Cloud workloads and can issue mutual TLS certificates for service-to-service authentication.

import * as pulumi from "@pulumi/pulumi";
import * as gcp from "@pulumi/gcp";
import * as std from "@pulumi/std";

const example = new gcp.iam.WorkloadIdentityPool("example", {
    workloadIdentityPoolId: "example-pool",
    displayName: "Name of the pool",
    description: "Identity pool operates in TRUST_DOMAIN mode",
    disabled: true,
    mode: "TRUST_DOMAIN",
    inlineCertificateIssuanceConfig: {
        caPools: {
            "us-central1": "projects/project-bar/locations/us-central1/caPools/ca-pool-bar",
            "asia-east2": "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo",
        },
        lifetime: "86400s",
        rotationWindowPercentage: 50,
        keyAlgorithm: "ECDSA_P256",
    },
    inlineTrustConfig: {
        additionalTrustBundles: [
            {
                trustDomain: "example.com",
                trustAnchors: [
                    {
                        pemCertificate: std.file({
                            input: "test-fixtures/trust_anchor_1.pem",
                        }).then(invoke => invoke.result),
                    },
                    {
                        pemCertificate: std.file({
                            input: "test-fixtures/trust_anchor_2.pem",
                        }).then(invoke => invoke.result),
                    },
                ],
            },
            {
                trustDomain: "example.net",
                trustAnchors: [
                    {
                        pemCertificate: std.file({
                            input: "test-fixtures/trust_anchor_3.pem",
                        }).then(invoke => invoke.result),
                    },
                    {
                        pemCertificate: std.file({
                            input: "test-fixtures/trust_anchor_4.pem",
                        }).then(invoke => invoke.result),
                    },
                ],
            },
        ],
    },
});
import pulumi
import pulumi_gcp as gcp
import pulumi_std as std

example = gcp.iam.WorkloadIdentityPool("example",
    workload_identity_pool_id="example-pool",
    display_name="Name of the pool",
    description="Identity pool operates in TRUST_DOMAIN mode",
    disabled=True,
    mode="TRUST_DOMAIN",
    inline_certificate_issuance_config={
        "ca_pools": {
            "us-central1": "projects/project-bar/locations/us-central1/caPools/ca-pool-bar",
            "asia-east2": "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo",
        },
        "lifetime": "86400s",
        "rotation_window_percentage": 50,
        "key_algorithm": "ECDSA_P256",
    },
    inline_trust_config={
        "additional_trust_bundles": [
            {
                "trust_domain": "example.com",
                "trust_anchors": [
                    {
                        "pem_certificate": std.file(input="test-fixtures/trust_anchor_1.pem").result,
                    },
                    {
                        "pem_certificate": std.file(input="test-fixtures/trust_anchor_2.pem").result,
                    },
                ],
            },
            {
                "trust_domain": "example.net",
                "trust_anchors": [
                    {
                        "pem_certificate": std.file(input="test-fixtures/trust_anchor_3.pem").result,
                    },
                    {
                        "pem_certificate": std.file(input="test-fixtures/trust_anchor_4.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 {
		invokeFile, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/trust_anchor_1.pem",
		}, nil)
		if err != nil {
			return err
		}
		invokeFile1, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/trust_anchor_2.pem",
		}, nil)
		if err != nil {
			return err
		}
		invokeFile2, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/trust_anchor_3.pem",
		}, nil)
		if err != nil {
			return err
		}
		invokeFile3, err := std.File(ctx, &std.FileArgs{
			Input: "test-fixtures/trust_anchor_4.pem",
		}, nil)
		if err != nil {
			return err
		}
		_, err = iam.NewWorkloadIdentityPool(ctx, "example", &iam.WorkloadIdentityPoolArgs{
			WorkloadIdentityPoolId: pulumi.String("example-pool"),
			DisplayName:            pulumi.String("Name of the pool"),
			Description:            pulumi.String("Identity pool operates in TRUST_DOMAIN mode"),
			Disabled:               pulumi.Bool(true),
			Mode:                   pulumi.String("TRUST_DOMAIN"),
			InlineCertificateIssuanceConfig: &iam.WorkloadIdentityPoolInlineCertificateIssuanceConfigArgs{
				CaPools: pulumi.StringMap{
					"us-central1": pulumi.String("projects/project-bar/locations/us-central1/caPools/ca-pool-bar"),
					"asia-east2":  pulumi.String("projects/project-foo/locations/asia-east2/caPools/ca-pool-foo"),
				},
				Lifetime:                 pulumi.String("86400s"),
				RotationWindowPercentage: pulumi.Int(50),
				KeyAlgorithm:             pulumi.String("ECDSA_P256"),
			},
			InlineTrustConfig: &iam.WorkloadIdentityPoolInlineTrustConfigArgs{
				AdditionalTrustBundles: iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArray{
					&iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArgs{
						TrustDomain: pulumi.String("example.com"),
						TrustAnchors: iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArray{
							&iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs{
								PemCertificate: pulumi.String(invokeFile.Result),
							},
							&iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs{
								PemCertificate: pulumi.String(invokeFile1.Result),
							},
						},
					},
					&iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArgs{
						TrustDomain: pulumi.String("example.net"),
						TrustAnchors: iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArray{
							&iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs{
								PemCertificate: pulumi.String(invokeFile2.Result),
							},
							&iam.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs{
								PemCertificate: pulumi.String(invokeFile3.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 example = new Gcp.Iam.WorkloadIdentityPool("example", new()
    {
        WorkloadIdentityPoolId = "example-pool",
        DisplayName = "Name of the pool",
        Description = "Identity pool operates in TRUST_DOMAIN mode",
        Disabled = true,
        Mode = "TRUST_DOMAIN",
        InlineCertificateIssuanceConfig = new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineCertificateIssuanceConfigArgs
        {
            CaPools = 
            {
                { "us-central1", "projects/project-bar/locations/us-central1/caPools/ca-pool-bar" },
                { "asia-east2", "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo" },
            },
            Lifetime = "86400s",
            RotationWindowPercentage = 50,
            KeyAlgorithm = "ECDSA_P256",
        },
        InlineTrustConfig = new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigArgs
        {
            AdditionalTrustBundles = new[]
            {
                new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArgs
                {
                    TrustDomain = "example.com",
                    TrustAnchors = new[]
                    {
                        new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs
                        {
                            PemCertificate = Std.File.Invoke(new()
                            {
                                Input = "test-fixtures/trust_anchor_1.pem",
                            }).Apply(invoke => invoke.Result),
                        },
                        new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs
                        {
                            PemCertificate = Std.File.Invoke(new()
                            {
                                Input = "test-fixtures/trust_anchor_2.pem",
                            }).Apply(invoke => invoke.Result),
                        },
                    },
                },
                new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArgs
                {
                    TrustDomain = "example.net",
                    TrustAnchors = new[]
                    {
                        new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs
                        {
                            PemCertificate = Std.File.Invoke(new()
                            {
                                Input = "test-fixtures/trust_anchor_3.pem",
                            }).Apply(invoke => invoke.Result),
                        },
                        new Gcp.Iam.Inputs.WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs
                        {
                            PemCertificate = Std.File.Invoke(new()
                            {
                                Input = "test-fixtures/trust_anchor_4.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.inputs.WorkloadIdentityPoolInlineCertificateIssuanceConfigArgs;
import com.pulumi.gcp.iam.inputs.WorkloadIdentityPoolInlineTrustConfigArgs;
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 example = new WorkloadIdentityPool("example", WorkloadIdentityPoolArgs.builder()
            .workloadIdentityPoolId("example-pool")
            .displayName("Name of the pool")
            .description("Identity pool operates in TRUST_DOMAIN mode")
            .disabled(true)
            .mode("TRUST_DOMAIN")
            .inlineCertificateIssuanceConfig(WorkloadIdentityPoolInlineCertificateIssuanceConfigArgs.builder()
                .caPools(Map.ofEntries(
                    Map.entry("us-central1", "projects/project-bar/locations/us-central1/caPools/ca-pool-bar"),
                    Map.entry("asia-east2", "projects/project-foo/locations/asia-east2/caPools/ca-pool-foo")
                ))
                .lifetime("86400s")
                .rotationWindowPercentage(50)
                .keyAlgorithm("ECDSA_P256")
                .build())
            .inlineTrustConfig(WorkloadIdentityPoolInlineTrustConfigArgs.builder()
                .additionalTrustBundles(                
                    WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArgs.builder()
                        .trustDomain("example.com")
                        .trustAnchors(                        
                            WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs.builder()
                                .pemCertificate(StdFunctions.file(FileArgs.builder()
                                    .input("test-fixtures/trust_anchor_1.pem")
                                    .build()).result())
                                .build(),
                            WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs.builder()
                                .pemCertificate(StdFunctions.file(FileArgs.builder()
                                    .input("test-fixtures/trust_anchor_2.pem")
                                    .build()).result())
                                .build())
                        .build(),
                    WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleArgs.builder()
                        .trustDomain("example.net")
                        .trustAnchors(                        
                            WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs.builder()
                                .pemCertificate(StdFunctions.file(FileArgs.builder()
                                    .input("test-fixtures/trust_anchor_3.pem")
                                    .build()).result())
                                .build(),
                            WorkloadIdentityPoolInlineTrustConfigAdditionalTrustBundleTrustAnchorArgs.builder()
                                .pemCertificate(StdFunctions.file(FileArgs.builder()
                                    .input("test-fixtures/trust_anchor_4.pem")
                                    .build()).result())
                                .build())
                        .build())
                .build())
            .build());

    }
}
resources:
  example:
    type: gcp:iam:WorkloadIdentityPool
    properties:
      workloadIdentityPoolId: example-pool
      displayName: Name of the pool
      description: Identity pool operates in TRUST_DOMAIN mode
      disabled: true
      mode: TRUST_DOMAIN
      inlineCertificateIssuanceConfig:
        caPools:
          us-central1: projects/project-bar/locations/us-central1/caPools/ca-pool-bar
          asia-east2: projects/project-foo/locations/asia-east2/caPools/ca-pool-foo
        lifetime: 86400s
        rotationWindowPercentage: 50
        keyAlgorithm: ECDSA_P256
      inlineTrustConfig:
        additionalTrustBundles:
          - trustDomain: example.com
            trustAnchors:
              - pemCertificate:
                  fn::invoke:
                    function: std:file
                    arguments:
                      input: test-fixtures/trust_anchor_1.pem
                    return: result
              - pemCertificate:
                  fn::invoke:
                    function: std:file
                    arguments:
                      input: test-fixtures/trust_anchor_2.pem
                    return: result
          - trustDomain: example.net
            trustAnchors:
              - pemCertificate:
                  fn::invoke:
                    function: std:file
                    arguments:
                      input: test-fixtures/trust_anchor_3.pem
                    return: result
              - pemCertificate:
                  fn::invoke:
                    function: std:file
                    arguments:
                      input: test-fixtures/trust_anchor_4.pem
                    return: result

In TRUST_DOMAIN mode, all identities must follow the format ns/<namespace>/sa/<workload_identifier>. The inlineCertificateIssuanceConfig property defines CA pools by region for certificate issuance, along with certificate lifetime and rotation settings. The inlineTrustConfig property establishes trust relationships with other domains by specifying trust anchors (PEM certificates). Each trust domain can have multiple trust anchors, allowing the pool to recognize certificates from those domains.

Beyond these examples

These snippets focus on specific pool-level features: federation and trust domain modes, mTLS certificate issuance, and trust anchor configuration. They’re intentionally minimal rather than full authentication systems.

The examples may reference pre-existing infrastructure such as CA pool resources in specified regions (for TRUST_DOMAIN mode) and PEM certificate files for trust anchors. They focus on configuring the pool rather than provisioning the complete identity federation workflow.

To keep things focused, common pool patterns are omitted, including:

  • WorkloadIdentityPoolProvider resources (required for federation)
  • IAM policy bindings to grant resource access
  • Certificate rotation and lifecycle management
  • Namespace and workload identifier conventions

These omissions are intentional: the goal is to illustrate how each pool feature is wired, not provide drop-in identity federation modules. See the Workload Identity Pool resource reference for all available configuration options.

Let's configure GCP Workload Identity Pools

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Pool Configuration & Modes
What's the difference between FEDERATION_ONLY and TRUST_DOMAIN modes?
FEDERATION_ONLY (the default) is for federating external workload identities like AWS or Azure into Google Cloud, with no format constraints and support for creating providers. TRUST_DOMAIN is for assigning identities to Google Cloud workloads, requires identities to follow the ns/<namespace>/sa/<workload_identifier> format, and does not allow creating gcp.iam.WorkloadIdentityPoolProvider resources.
Can I create providers in a TRUST_DOMAIN mode pool?
No, gcp.iam.WorkloadIdentityPoolProvider resources cannot be created within TRUST_DOMAIN mode pools. Providers are only supported in FEDERATION_ONLY mode.
Immutability & Lifecycle
Why does my mode change fail even though preview shows it will succeed?
The mode field is immutable after pool creation. While pulumi preview may show an update, pulumi up will fail with an API error like “Error 400: Attempted to update an immutable field.” You must create a new Workload Identity Pool resource with the desired mode instead.
What fields can't be changed after creating a pool?
The project, workloadIdentityPoolId, and mode fields are immutable after creation. Changing these requires creating a new pool.
Can I reuse a deleted pool's ID immediately?
No, soft-deleted pools cannot have their IDs reused until permanent deletion occurs (approximately 30 days). You can either use a different pool ID, wait for permanent deletion, or restore the soft-deleted pool using UndeleteWorkloadIdentityPool.
Identity & Access Control
What happens to existing tokens when I disable a pool?
When a pool is disabled, you cannot exchange new tokens or use existing tokens to access resources. If you re-enable the pool, existing tokens will grant access again.
Naming & Constraints
What are the naming rules for workloadIdentityPoolId?
The pool ID must be 4-32 characters long and may only contain lowercase letters, numbers, and hyphens ([a-z0-9-]). The prefix gcp- is reserved for Google and cannot be used.
What are the character limits for pool descriptions and display names?
The description field cannot exceed 256 characters, and the displayName field cannot exceed 32 characters.
What format must identities follow in TRUST_DOMAIN mode?
All identities in a TRUST_DOMAIN mode pool must conform to the format ns/<namespace>/sa/<workload_identifier>, consisting of a single namespace and individual workload identifier.

Using a different cloud?

Explore security guides for other cloud providers: