OIDC in Buildkite Packages
Open ID Connect (OIDC) is an authentication protocol based on the OAuth 2.0 framework. With OIDC, one system or service issues an OIDC token containing signed metadata (or claims) about a user or object. This token can be consumed by another service (which may be offered by a third-party or by the same organization) to authenticate the user or object. An OIDC policy configured on this other service defines which OIDC tokens (based on their claims) are permitted to perform the actions. If the OIDC token's claims match those of the OIDC policy configured in the other service, the token is authenticated and the service issuing the token is permitted to perform its actions on the other service.
You can configure Buildkite Packages registries with OIDC policies that only permit Buildkite Agent interactions from specific Buildkite organizations, pipelines, jobs, and agents, associated with a pipeline's job. This is similar to how third-party products and services can be configured with OIDC policies to consume Buildkite OIDC tokens from Buildkite pipelines, for deployment, or access management and security purposes.
A Buildkite OIDC token is a signed JSON Web Token (JWT) provided by a Buildkite Agent, containing metadata claims about a pipeline and its job, including the pipeline and organization slugs, as well as job-specific data, such as the branch, the commit SHA, the job ID, and the agent ID. Such a token is associated with a Buildkite Agent interaction to perform one or more actions on a Buildkite Packages registry. If the token's claims do not match or comply with the registry's OIDC policy, the OIDC token and subsequent pipeline jobs' actions are rejected.
The Buildkite Agent's oidc
command allows you to request an OIDC token from Buildkite containing claims about the pipeline's current job. These tokens are then used by a Buildkite Packages registry to determine (through its OIDC policy) if the organization, pipeline and any other metadata associated with the pipeline and its job are permitted to publish/upload packages to this registry.
Buildkite Packages registries also support OIDC policies that can consume OIDC tokens configured on third-party products and services, such as GitHub Actions, to authenticate interactions from these services.
Define an OIDC policy for a registry
You can specify an OIDC policy for your Buildkite registry, which defines the criteria for which OIDC tokens, from the Buildkite Agent or another third-party system, will be accepted by your registry and authenticate a package publication/upload action from that system.
To define an OIDC policy for one or more Buildkite pipeline jobs in a registry:
Select Packages in the global navigation to access the Registries page.
Select the registry whose OIDC policy needs defining.
Select Settings > OIDC Policy to access the registry's OIDC Policy page.
-
In the Policy field, specify this using the following format:
- iss: https://agent.buildkite.com organization_slug: organization-slug pipeline_slug: pipeline-slug build_branch: main
where:
-
iss
(the issuer) must behttps://agent.buildkite.com
, representing the Buildkite Agent. -
organization-slug
can be obtained from the end of your Buildkite URL, after accessing Packages or Pipelines in the global navigation of your organization in Buildkite. -
pipeline-slug
can be obtained from the end of your Buildkite URL, after accessing Pipelines in the global navigation of your organization in Buildkite. -
main
or whichever branch of the repository you want to restrict package publication/uploads from pipeline builds.
-
Each of these OIDC policy fields acts as a filter and only authenticates and accepts OIDC tokens from Buildkite Agent pipelines and jobs whose criteria match these field values. Therefore, omitting a field makes the policy less strict.
You can also specify multiple rules in this Policy field to allow your registry to accept jobs from other pipelines, as well as OIDC tokens from other systems.
Example OIDC policy for a registry
The following example OIDC policy defined on a registry (with two rules):
- iss: https://agent.buildkite.com
organization_slug: my-organization
pipeline_slug: my-pipeline
build_branch: main
- iss: https://agent.buildkite.com
organization_slug: my-organization
pipeline_slug: my-second-pipeline
Will only authenticate and accept OIDC tokens (and therefore, allow package publishing/uploads to this registry) from Buildkite Agents:
Configured with the Buildkite organization
my-organization
.Running pipeline builds of the
my-pipeline
ormy-second-pipeline
pipelines within this organization.For
my-pipeline
, running builds from themain
branch of the repository.For
my-second-pipeline
, running builds from any branch of the repository.
Configure a Buildkite pipeline to authenticate to a registry
Configuring a Buildkite pipeline command
step to request an OIDC token from Buildkite to interact with your Buildkite registry configured with an OIDC policy, is a two-part process.
Part 1: Request an OIDC token from Buildkite
To do this, use the following buildkite-agent oidc
command:
buildkite-agent oidc request-token --audience "https://packages.buildkite.com/{org.slug}/{registry.slug}" --lifetime 300
where:
-
--audience
is the target system that consumes this OIDC token. For Buildkite Packages, this value must be based on the URLhttps://packages.buildkite.com/{org.slug}/{registry.slug}
.
-
{org.slug}
can be obtained from the end of your Buildkite URL, after accessing Packages or Pipelines in the global navigation of your organization in Buildkite.
{registry.slug}
is the slug of your registry, which is the kebab-case version of your registry name, and can be obtained after accessing Packages in the global navigation > your registry from the Registries page.--lifetime
is the time (in seconds) that the OIDC token is valid for. By default, this value must be less than300
.
Part 2: Authenticate the Buildkite registry with the OIDC token
To do this (using Docker as an example), authenticate the Buildkite registry with the OIDC token obtained in part 1 by piping the output through to the docker login
command:
docker login packages.buildkite.com/{org.slug}/{registry.slug} --username buildkite --password-stdin
where:
{org.slug}
and{registry.slug}
are the same as the values used in thebuildkite-agent oidc request-token
command.--username
always has the valuebuildkite
.
Therefore, the full command
step would look like:
buildkite-agent oidc request-token --audience "https://packages.buildkite.com/{org.slug}/{registry.slug}" --lifetime 300 | docker login packages.buildkite.com/{org.slug}/{registry.slug} --username buildkite --password-stdin
Assuming a Buildkite organization with slug my-organization
and a pipeline slug my-pipeline
, this full command would look like:
buildkite-agent oidc request-token --audience "https://packages.buildkite.com/my-organization/my-pipeline" --lifetime 300 | docker login packages.buildkite.com/my-organization/my-pipeline --username buildkite --password-stdin
Example pipeline
The following example Buildkite pipeline YAML snippet demonstrates how to push Docker images to a Buildkite registry using OIDC token authentication:
steps:
- key: "docker-build" # Build the Docker image
label: ":docker: Build"
command: docker build --tag packages.buildkite.com/my-organization/my-pipeline/my-image:latest .
- key: "docker-login" # Authenticate the Buildkite Agent to the Buildkite Packages registry using an OIDC token
label: ":docker: Login"
command: buildkite-agent oidc request-token --audience "https://packages.buildkite.com/my-organization/my-pipeline" --lifetime 300 | docker login packages.buildkite.com/my-organization/my-pipeline --username buildkite --password-stdin
depends_on: "docker-build"
- key: "docker-push" # Now authenticated, push the Docker image to the registry
label: ":docker: Push"
command: docker push packages.buildkite.com/my-organization/my-pipeline/my-pipeline/my-image:latest
depends_on: "docker-login"