A Buildkite plugin that exchanges a Buildkite OIDC token for a Pulumi access token using OAuth 2.0 Token Exchange.
The resulting token is exported as PULUMI_ACCESS_TOKEN, allowing subsequent pipeline steps to authenticate with Pulumi Cloud without storing static credentials.
- Buildkite agent v3.48+ (OIDC token support)
curl>= 8.0.0jq>= 1.5 (for-eexit status flag)bash>= 4.0- A Pulumi Cloud organization with OIDC configured (see setup below). Available token types depend on your Pulumi edition:
- Individual: personal tokens only
- Team: personal and organization tokens
- Enterprise / Business Critical: personal, organization, and team tokens
Before using this plugin, you need to register Buildkite as an OIDC issuer in Pulumi Cloud and create an authorization policy.
- Navigate to Pulumi Cloud > Access Management > Settings > OIDC Issuers
- Click Register a new issuer
- Set the issuer URL to
https://agent.buildkite.com - Configure the max token expiration as needed
See the Pulumi OIDC client documentation for details.
By default, all token exchange requests are denied. You must create an authorization policy that matches the Buildkite OIDC token claims.
Buildkite OIDC tokens use the following subject claim format:
organization:{ORG_SLUG}:pipeline:{PIPELINE_SLUG}:ref:{REF}:commit:{COMMIT}:step:{STEP_KEY}
Example policy allowing all pipelines in a Buildkite organization:
- Sub claim:
organization:my-buildkite-org:pipeline:*:ref:*:commit:*:step:* - Token type: Organization access token
- Scope: (leave empty for default)
The Pulumi organization name. Used to construct the audience (urn:pulumi:org:<org_name>) for both the Buildkite OIDC token request and the Pulumi token exchange.
The lifetime (in seconds) for the Buildkite OIDC token before it expires. Must be a non-negative integer. When set to 0 (the default), the API uses its default lifetime.
Default: 0
The type of Pulumi access token to request. Must be one of:
| Value | Description |
|---|---|
urn:pulumi:token-type:access_token:organization |
Organization-scoped token (default) |
urn:pulumi:token-type:access_token:team |
Team-scoped token (requires scope) |
urn:pulumi:token-type:access_token:personal |
Personal token (requires scope) |
Default: urn:pulumi:token-type:access_token:organization
Scope for the requested token. The value depends on the requested_token_type:
| Token Type | Scope Format | Example |
|---|---|---|
| Organization | admin (optional, for admin privileges) |
admin |
| Team | team:<TEAM_NAME> |
team:platform-team |
| Personal | user:<USER_LOGIN> |
user:jane |
The authorization policy must explicitly grant the requested scope.
The Pulumi Cloud API base URL. Override this for self-hosted Pulumi Cloud deployments.
Default: https://api.pulumi.com
When true, prints the full curl command and API response for troubleshooting. Warning: this exposes both the Buildkite OIDC token and the Pulumi access token in the build log. Only use for debugging.
Default: false
On success, the plugin exports:
PULUMI_ACCESS_TOKEN- A short-lived Pulumi access token that authenticates subsequentpulumiCLI commands.
steps:
- label: ":pulumi: Deploy"
command: "pulumi up --yes --stack my-org/my-stack/production"
plugins:
- instant-labs/pulumi-oidc#v0.1.0:
org_name: "my-org"steps:
- label: ":pulumi: Deploy"
command: "pulumi up --yes --stack my-org/my-stack/production"
plugins:
- instant-labs/pulumi-oidc#v0.1.0:
org_name: "my-org"
requested_token_type: "urn:pulumi:token-type:access_token:team"
scope: "team:platform-team"steps:
- label: ":pulumi: Deploy"
command: "pulumi up --yes --stack my-org/my-stack/production"
plugins:
- instant-labs/pulumi-oidc#v0.1.0:
org_name: "my-org"
requested_token_type: "urn:pulumi:token-type:access_token:personal"
scope: "user:jane"
lifetime: 3600After obtaining a Pulumi access token via this plugin, you can use Pulumi ESC to dynamically fetch cloud provider credentials:
steps:
- label: ":pulumi: Deploy with ESC"
commands:
- eval $(pulumi env open my-org/my-project/aws-prod --format shell)
- pulumi up --yes --stack my-org/my-stack/production
plugins:
- instant-labs/pulumi-oidc#v0.1.0:
org_name: "my-org"This uses your Pulumi access token to open an ESC environment that provides temporary AWS/Azure/GCP credentials via OIDC federation. See Configuring OIDC in ESC for environment setup.
Run tests:
make testRun linter:
make lintMIT License. See LICENSE.