Skip to main content
  1. Docs
  2. Administration
  3. Access & Identity
  4. OIDC Issuers
  5. Google Kubernetes Engine

Configuring OpenID Connect for Google Kubernetes Engine

    This document outlines the steps required to configure Pulumi Cloud to accept Google Kubernetes Engine id_tokens and exchange them for organization access tokens. With this configuration, Kubernetes pods authenticate to Pulumi Cloud using OIDC tokens issued by GKE.

    See “Bound Tokens” for more background.

    Common use cases

    This integration is most often used to authenticate workloads that run Pulumi operations from inside a GKE cluster, without storing long-lived Pulumi access tokens. Two common scenarios:

    • Pulumi Kubernetes Operator — Run Pulumi stacks as Kubernetes custom resources. The operator’s workspace pods authenticate to Pulumi Cloud using the cluster’s OIDC tokens instead of a static PULUMI_ACCESS_TOKEN.
    • Customer-managed deployment runners — Run Pulumi Deployments inside your own GKE cluster. The workflow runner fetches a Pulumi Pool token dynamically using its OIDC identity.
    This guide walks through the Pulumi Cloud UI. You can also configure OIDC Issuers via the REST API or the OidcIssuer resource in the Pulumi Service provider.
    This guide demonstrates using organization tokens. Depending on your Pulumi edition, you can also use personal or team tokens by adjusting the token type in the authorization policies and the pulumi login parameters.

    Prerequisites

    • You must be an admin of your Pulumi organization.
    • You must have a GKE cluster.
    This guide provides step-by-step instructions based on the official provider documentation, which is subject to change. For the most current information, refer to the official Bound Service Account Tokens documentation.

    Register the OIDC Issuer

    1. Navigate to Settings → Access Management → OIDC Issuers and select Register issuer.
    2. Name the issuer and set the issuer URL to https://container.googleapis.com/v1/projects/PROJECT_NAME/locations/LOCATION/clusters/CLUSTER_NAME/.
    3. Submit the form.

    Configure the authorization policies

    1. Select the issuer name.
    2. Set Decision to Allow.
    3. Set Token type to Organization.
    4. Add a new rule and configure it to verify the namespace and the service name.
    5. Select Save policies.

    Sample

    // Pulumi program to run a bash script in a Kubernetes pod,
    // mount a service account token with an appropriate audience,
    // exchange the token for an ordinary Pulumi access token,
    // then run `pulumi whoami`.
    
    import * as kubernetes from "@pulumi/kubernetes";
    
    const loginParams = {
        "org_name": "MY_ORG_NAME",
    }
    
    const script = new kubernetes.core.v1.ConfigMap("script", {
        data: {
            "entrypoint.sh": `#!/bin/bash
    OIDC_GKE_TOKEN=$(</var/run/secrets/pulumi/token)
    echo "OIDC Token:"
    echo $OIDC_GKE_TOKEN
    pulumi login --oidc-token $OIDC_GKE_TOKEN --oidc-org ${loginParams.org_name}
    pulumi whoami
    `
        }
    });
    
    const job = new kubernetes.batch.v1.Job("runner", {
        metadata: {
        },
        spec: {
            template: {
                spec: {
                    containers: [{
                        name: "runner",
                        image: "pulumi/pulumi:latest",
                        command: ["/bin/entrypoint.sh"],
                        volumeMounts: [
                            {
                                name: "pulumi-serviceaccounttoken",
                                mountPath: "/var/run/secrets/pulumi",
                            },
                            {
                                name: "script",
                                mountPath: "/bin/entrypoint.sh",
                                readOnly: true,
                                subPath: "entrypoint.sh",
                            },
                        ],
                    }],
                    restartPolicy: "Never",
                    volumes: [
                        {
                            name: "pulumi-serviceaccounttoken",
                            projected: {
                                sources: [
                                    {
                                        serviceAccountToken: {
                                            audience: "urn:pulumi:org:MY_ORG_NAME",
                                            expirationSeconds: 3600,
                                            path: "token",
                                        },
                                    },
                                ],
                            },
                        },
                        {
                            name: "script",
                            configMap: {
                                defaultMode: 0o700,
                                name: script.metadata.name,
                            },
                        },
                    ],
                },
            },
            backoffLimit: 0,
        },
    });
    
    export const jobName = job.metadata.name;