diff --git a/.github/workflows/bake.yml b/.github/workflows/bake.yml index e9b3a0a..85e2e44 100644 --- a/.github/workflows/bake.yml +++ b/.github/workflows/bake.yml @@ -126,6 +126,20 @@ on: type: string description: "Bake target name for metadata (defaults to docker-metadata-action)" required: false + chainguard-identity: + type: string + description: "UIDP of a Chainguard identity to assume via GitHub OIDC for keyless cgr.dev authentication" + required: false + chainguard-apk-host: + type: string + description: "Hostname for APK-related Chainguard authentication (passed through to chainguard-dev/setup-chainctl)" + required: false + default: apk.cgr.dev + chainguard-libraries-host: + type: string + description: "Hostname for Chainguard Libraries authentication (passed through to chainguard-dev/setup-chainctl)" + required: false + default: libraries.cgr.dev secrets: registry-auths: description: "Raw authentication to registries, defined as YAML objects (for image output)" @@ -907,6 +921,14 @@ jobs: core.info(JSON.stringify(bakeOverrides, null, 2)); core.setOutput('overrides', bakeOverrides.join(os.EOL)); }); + - + name: Set up chainctl + if: ${{ inputs.chainguard-identity != '' && inputs.push && inputs.output == 'image' }} + uses: chainguard-dev/setup-chainctl@2cddd35a2f120d9973e58094dc6878c93cf58c28 # v0.5.1 + with: + identity: ${{ inputs.chainguard-identity }} + apk-host: ${{ inputs.chainguard-apk-host }} + libraries-host: ${{ inputs.chainguard-libraries-host }} - name: Login to registry if: ${{ inputs.push && inputs.output == 'image' }} @@ -1091,6 +1113,14 @@ jobs: labels: ${{ inputs.meta-labels }} annotations: ${{ inputs.meta-annotations }} bake-target: ${{ inputs.meta-bake-target }} + - + name: Set up chainctl + if: ${{ inputs.chainguard-identity != '' && inputs.push && inputs.output == 'image' }} + uses: chainguard-dev/setup-chainctl@2cddd35a2f120d9973e58094dc6878c93cf58c28 # v0.5.1 + with: + identity: ${{ inputs.chainguard-identity }} + apk-host: ${{ inputs.chainguard-apk-host }} + libraries-host: ${{ inputs.chainguard-libraries-host }} - name: Login to registry if: ${{ inputs.push && inputs.output == 'image' }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d1a46c2..5747054 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -129,6 +129,20 @@ on: type: string description: "Flavor defines a global behavior for meta-tags" required: false + chainguard-identity: + type: string + description: "UIDP of a Chainguard identity to assume via GitHub OIDC for keyless cgr.dev authentication" + required: false + chainguard-apk-host: + type: string + description: "Hostname for APK-related Chainguard authentication (passed through to chainguard-dev/setup-chainctl)" + required: false + default: apk.cgr.dev + chainguard-libraries-host: + type: string + description: "Hostname for Chainguard Libraries authentication (passed through to chainguard-dev/setup-chainctl)" + required: false + default: libraries.cgr.dev secrets: registry-auths: description: "Raw authentication to registries, defined as YAML objects (for image output)" @@ -766,6 +780,14 @@ jobs: // for a public repository, we set max provenance mode core.setOutput('provenance', Build.resolveProvenanceAttrs(`mode=max,version=v1`)); } + - + name: Set up chainctl + if: ${{ inputs.chainguard-identity != '' && inputs.push && inputs.output == 'image' }} + uses: chainguard-dev/setup-chainctl@2cddd35a2f120d9973e58094dc6878c93cf58c28 # v0.5.1 + with: + identity: ${{ inputs.chainguard-identity }} + apk-host: ${{ inputs.chainguard-apk-host }} + libraries-host: ${{ inputs.chainguard-libraries-host }} - name: Login to registry if: ${{ inputs.push && inputs.output == 'image' }} @@ -946,6 +968,14 @@ jobs: flavor: ${{ inputs.meta-flavor }} labels: ${{ inputs.meta-labels }} annotations: ${{ inputs.meta-annotations }} + - + name: Set up chainctl + if: ${{ inputs.chainguard-identity != '' && inputs.push && inputs.output == 'image' }} + uses: chainguard-dev/setup-chainctl@2cddd35a2f120d9973e58094dc6878c93cf58c28 # v0.5.1 + with: + identity: ${{ inputs.chainguard-identity }} + apk-host: ${{ inputs.chainguard-apk-host }} + libraries-host: ${{ inputs.chainguard-libraries-host }} - name: Login to registry if: ${{ inputs.push && inputs.output == 'image' }} diff --git a/README.md b/README.md index 3f7d031..d8eb140 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ ___ * [Notes](#notes) * [Runner mapping](#runner-mapping) * [Metadata templates](#metadata-templates) + * [Chainguard keyless authentication](#chainguard-keyless-authentication) ## Overview @@ -233,6 +234,9 @@ jobs: | `meta-images` | List | | [List of images](https://github.com/docker/metadata-action?tab=readme-ov-file#images-input) to use as base name for tags (required for image output) | | `meta-tags` | List | | [List of tags](https://github.com/docker/metadata-action?tab=readme-ov-file#tags-input) as key-value pair attributes | | `meta-flavor` | List | | [Flavor](https://github.com/docker/metadata-action?tab=readme-ov-file#flavor-input) defines a global behavior for `meta-tags` | +| `chainguard-identity` | String | | UIDP of a Chainguard identity to assume via GitHub OIDC for keyless `cgr.dev` authentication. See [Chainguard keyless authentication](#chainguard-keyless-authentication) | +| `chainguard-apk-host` | String | `apk.cgr.dev` | Hostname for APK-related Chainguard authentication. Passed through to `chainguard-dev/setup-chainctl` | +| `chainguard-libraries-host` | String | `libraries.cgr.dev` | Hostname for Chainguard Libraries authentication. Passed through to `chainguard-dev/setup-chainctl` | ### Secrets @@ -342,6 +346,9 @@ jobs: | `meta-labels` | List | | [List of custom labels](https://github.com/docker/metadata-action?tab=readme-ov-file#overwrite-labels-and-annotations) | | `meta-annotations` | List | | [List of custom annotations](https://github.com/docker/metadata-action?tab=readme-ov-file#overwrite-labels-and-annotations) | | `meta-flavor` | List | | [Flavor](https://github.com/docker/metadata-action?tab=readme-ov-file#flavor-input) defines a global behavior for `meta-tags` | +| `chainguard-identity` | String | | UIDP of a Chainguard identity to assume via GitHub OIDC for keyless `cgr.dev` authentication. See [Chainguard keyless authentication](#chainguard-keyless-authentication) | +| `chainguard-apk-host` | String | `apk.cgr.dev` | Hostname for APK-related Chainguard authentication. Passed through to `chainguard-dev/setup-chainctl` | +| `chainguard-libraries-host` | String | `libraries.cgr.dev` | Hostname for Chainguard Libraries authentication. Passed through to `chainguard-dev/setup-chainctl` | ### Secrets @@ -431,3 +438,35 @@ jobs: *.args.VERSION={{meta.version}} meta-images: name/app ``` + +### Chainguard keyless authentication + +Setting `chainguard-identity` authenticates to `cgr.dev` via GitHub +OIDC, avoiding a static credential. The workflow runs +[`chainguard-dev/setup-chainctl`](https://github.com/chainguard-dev/setup-chainctl) +inside the `build` and `finalize` jobs so the token is minted on the +build runner and never crosses the `workflow_call` boundary (see +[`docker/github-builder#146`](https://github.com/docker/github-builder/issues/146)). + +```yaml +jobs: + bake: + uses: docker/github-builder/.github/workflows/bake.yml@v1 + permissions: + contents: read + id-token: write + with: + output: image + push: true + meta-images: cgr.dev/your-org/your-image + chainguard-identity: 70e4ec6.../79304d... +``` + +`chainguard-identity` can be combined with `registry-auths` for +multi-registry pushes. + +> [!IMPORTANT] +> `chainguard-dev/setup-chainctl` also authenticates against +> `apk.cgr.dev` and `libraries.cgr.dev`. The assumed identity must be +> claim-matched for those audiences, or `chainguard-apk-host` / +> `chainguard-libraries-host` must be redirected.