Skip to content

Commit f7e4199

Browse files
committed
build/bake: support GCP WIF registry identities
Signed-off-by: CrazyMax <1951866+crazy-max@users.noreply.github.com>
1 parent 27181d3 commit f7e4199

4 files changed

Lines changed: 210 additions & 27 deletions

File tree

.github/workflows/bake.yml

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,29 @@ jobs:
998998
if: ${{ needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
999999
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
10001000
with:
1001-
registry-auth: ${{ needs.registry-identities.outputs.aws-ecr-registry-auth }}
1001+
registry-auth: |
1002+
- registry: ${{ needs.registry-identities.outputs.aws-ecr-registry }}
1003+
-
1004+
name: Authenticate to Google Cloud
1005+
id: gcp-wif-auth
1006+
if: ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
1007+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
1008+
with:
1009+
token_format: access_token
1010+
workload_identity_provider: ${{ needs.registry-identities.outputs.gcp-wif-workload-identity-provider }}
1011+
service_account: ${{ needs.registry-identities.outputs.gcp-wif-service-account }}
1012+
project_id: ${{ needs.registry-identities.outputs.gcp-wif-project-id }}
1013+
create_credentials_file: false
1014+
export_environment_variables: false
1015+
-
1016+
name: Login to Google Artifact Registry
1017+
if: ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
1018+
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
1019+
with:
1020+
registry-auth: |
1021+
- registry: ${{ needs.registry-identities.outputs.gcp-wif-registry }}
1022+
username: oauth2accesstoken
1023+
password: ${{ steps.gcp-wif-auth.outputs.access_token }}
10021024
-
10031025
name: Login to registry
10041026
if: ${{ inputs.push && inputs.output == 'image' && env.REGISTRY_AUTHS_PRESENT == 'true' }}
@@ -1218,7 +1240,29 @@ jobs:
12181240
if: ${{ inputs.push && inputs.output == 'image' && needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
12191241
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
12201242
with:
1221-
registry-auth: ${{ needs.registry-identities.outputs.aws-ecr-registry-auth }}
1243+
registry-auth: |
1244+
- registry: ${{ needs.registry-identities.outputs.aws-ecr-registry }}
1245+
-
1246+
name: Authenticate to Google Cloud
1247+
id: gcp-wif-auth
1248+
if: ${{ inputs.push && inputs.output == 'image' && needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
1249+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
1250+
with:
1251+
token_format: access_token
1252+
workload_identity_provider: ${{ needs.registry-identities.outputs.gcp-wif-workload-identity-provider }}
1253+
service_account: ${{ needs.registry-identities.outputs.gcp-wif-service-account }}
1254+
project_id: ${{ needs.registry-identities.outputs.gcp-wif-project-id }}
1255+
create_credentials_file: false
1256+
export_environment_variables: false
1257+
-
1258+
name: Login to Google Artifact Registry
1259+
if: ${{ inputs.push && inputs.output == 'image' && needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
1260+
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
1261+
with:
1262+
registry-auth: |
1263+
- registry: ${{ needs.registry-identities.outputs.gcp-wif-registry }}
1264+
username: oauth2accesstoken
1265+
password: ${{ steps.gcp-wif-auth.outputs.access_token }}
12221266
-
12231267
name: Login to registry
12241268
if: ${{ inputs.push && inputs.output == 'image' && env.REGISTRY_AUTHS_PRESENT == 'true' }}

.github/workflows/build.yml

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -864,7 +864,29 @@ jobs:
864864
if: ${{ needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
865865
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
866866
with:
867-
registry-auth: ${{ needs.registry-identities.outputs.aws-ecr-registry-auth }}
867+
registry-auth: |
868+
- registry: ${{ needs.registry-identities.outputs.aws-ecr-registry }}
869+
-
870+
name: Authenticate to Google Cloud
871+
id: gcp-wif-auth
872+
if: ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
873+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
874+
with:
875+
token_format: access_token
876+
workload_identity_provider: ${{ needs.registry-identities.outputs.gcp-wif-workload-identity-provider }}
877+
service_account: ${{ needs.registry-identities.outputs.gcp-wif-service-account }}
878+
project_id: ${{ needs.registry-identities.outputs.gcp-wif-project-id }}
879+
create_credentials_file: false
880+
export_environment_variables: false
881+
-
882+
name: Login to Google Artifact Registry
883+
if: ${{ needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
884+
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
885+
with:
886+
registry-auth: |
887+
- registry: ${{ needs.registry-identities.outputs.gcp-wif-registry }}
888+
username: oauth2accesstoken
889+
password: ${{ steps.gcp-wif-auth.outputs.access_token }}
868890
-
869891
name: Login to registry
870892
if: ${{ inputs.push && inputs.output == 'image' && env.REGISTRY_AUTHS_PRESENT == 'true' }}
@@ -1080,7 +1102,29 @@ jobs:
10801102
if: ${{ inputs.push && inputs.output == 'image' && needs.registry-identities.outputs.aws-ecr-enabled == 'true' }}
10811103
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
10821104
with:
1083-
registry-auth: ${{ needs.registry-identities.outputs.aws-ecr-registry-auth }}
1105+
registry-auth: |
1106+
- registry: ${{ needs.registry-identities.outputs.aws-ecr-registry }}
1107+
-
1108+
name: Authenticate to Google Cloud
1109+
id: gcp-wif-auth
1110+
if: ${{ inputs.push && inputs.output == 'image' && needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
1111+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
1112+
with:
1113+
token_format: access_token
1114+
workload_identity_provider: ${{ needs.registry-identities.outputs.gcp-wif-workload-identity-provider }}
1115+
service_account: ${{ needs.registry-identities.outputs.gcp-wif-service-account }}
1116+
project_id: ${{ needs.registry-identities.outputs.gcp-wif-project-id }}
1117+
create_credentials_file: false
1118+
export_environment_variables: false
1119+
-
1120+
name: Login to Google Artifact Registry
1121+
if: ${{ inputs.push && inputs.output == 'image' && needs.registry-identities.outputs.gcp-wif-enabled == 'true' }}
1122+
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
1123+
with:
1124+
registry-auth: |
1125+
- registry: ${{ needs.registry-identities.outputs.gcp-wif-registry }}
1126+
username: oauth2accesstoken
1127+
password: ${{ steps.gcp-wif-auth.outputs.access_token }}
10841128
-
10851129
name: Login to registry
10861130
if: ${{ inputs.push && inputs.output == 'image' && env.REGISTRY_AUTHS_PRESENT == 'true' }}

.github/workflows/setup-registry-identities.yml

Lines changed: 62 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: registry-identities
1+
name: setup-registry-identities
22

33
on:
44
workflow_call:
@@ -11,18 +11,33 @@ on:
1111
aws-ecr-enabled:
1212
description: "Whether an AWS ECR registry identity was configured"
1313
value: ${{ jobs.setup-registry-identities.outputs.aws-ecr-enabled }}
14+
aws-ecr-registry:
15+
description: "AWS ECR registry host to authenticate against"
16+
value: ${{ jobs.setup-registry-identities.outputs.aws-ecr-registry }}
1417
aws-ecr-role-to-assume:
1518
description: "AWS IAM role ARN to assume for ECR authentication"
1619
value: ${{ jobs.setup-registry-identities.outputs.aws-ecr-role-to-assume }}
1720
aws-ecr-region:
1821
description: "AWS region to use for ECR authentication"
1922
value: ${{ jobs.setup-registry-identities.outputs.aws-ecr-region }}
20-
aws-ecr-registry-auth:
21-
description: "Registry auth YAML for Docker login"
22-
value: ${{ jobs.setup-registry-identities.outputs.aws-ecr-registry-auth }}
23+
gcp-wif-enabled:
24+
description: "Whether a GCP Workload Identity Federation registry identity was configured"
25+
value: ${{ jobs.setup-registry-identities.outputs.gcp-wif-enabled }}
26+
gcp-wif-registry:
27+
description: "Google Artifact Registry host to authenticate against"
28+
value: ${{ jobs.setup-registry-identities.outputs.gcp-wif-registry }}
29+
gcp-wif-workload-identity-provider:
30+
description: "GCP Workload Identity Provider resource name"
31+
value: ${{ jobs.setup-registry-identities.outputs.gcp-wif-workload-identity-provider }}
32+
gcp-wif-service-account:
33+
description: "GCP service account to impersonate"
34+
value: ${{ jobs.setup-registry-identities.outputs.gcp-wif-service-account }}
35+
gcp-wif-project-id:
36+
description: "GCP project ID"
37+
value: ${{ jobs.setup-registry-identities.outputs.gcp-wif-project-id }}
2338

2439
env:
25-
RUNTIME_MODULE: "@docker/github-builder-runtime@0.92.0"
40+
RUNTIME_MODULE: "@docker/github-builder-runtime@0.93.0"
2641
RUNTIME_INSTALL_ARGS: |
2742
--loglevel=error
2843
--no-save
@@ -39,9 +54,14 @@ jobs:
3954
runs-on: ubuntu-24.04
4055
outputs:
4156
aws-ecr-enabled: ${{ steps.validate.outputs.aws-ecr-enabled }}
57+
aws-ecr-registry: ${{ steps.validate.outputs.aws-ecr-registry }}
4258
aws-ecr-role-to-assume: ${{ steps.validate.outputs.aws-ecr-role-to-assume }}
4359
aws-ecr-region: ${{ steps.validate.outputs.aws-ecr-region }}
44-
aws-ecr-registry-auth: ${{ steps.validate.outputs.aws-ecr-registry-auth }}
60+
gcp-wif-enabled: ${{ steps.validate.outputs.gcp-wif-enabled }}
61+
gcp-wif-registry: ${{ steps.validate.outputs.gcp-wif-registry }}
62+
gcp-wif-workload-identity-provider: ${{ steps.validate.outputs.gcp-wif-workload-identity-provider }}
63+
gcp-wif-service-account: ${{ steps.validate.outputs.gcp-wif-service-account }}
64+
gcp-wif-project-id: ${{ steps.validate.outputs.gcp-wif-project-id }}
4565
steps:
4666
-
4767
name: Install dependencies
@@ -83,9 +103,14 @@ jobs:
83103
script: |
84104
const setEmptyOutputs = () => {
85105
core.setOutput('aws-ecr-enabled', 'false');
106+
core.setOutput('aws-ecr-registry', '');
86107
core.setOutput('aws-ecr-role-to-assume', '');
87108
core.setOutput('aws-ecr-region', '');
88-
core.setOutput('aws-ecr-registry-auth', '');
109+
core.setOutput('gcp-wif-enabled', 'false');
110+
core.setOutput('gcp-wif-registry', '');
111+
core.setOutput('gcp-wif-workload-identity-provider', '');
112+
core.setOutput('gcp-wif-service-account', '');
113+
core.setOutput('gcp-wif-project-id', '');
89114
};
90115
91116
const registryIdentities = core.getInput('registry-identities', {trimWhitespace: false});
@@ -135,13 +160,14 @@ jobs:
135160
}
136161
137162
let awsEcr;
163+
let gcpWif;
138164
entries.forEach((entry, index) => {
139165
const path = `registry-identities[${index}]`;
140166
ensureObject(entry, path);
141167
const type = requireString(entry, 'type', path);
142168
switch (type) {
143169
case 'aws-ecr': {
144-
const allowedKeys = new Set(['type', 'aws-region', 'role-to-assume', 'registry']);
170+
const allowedKeys = new Set(['type', 'registry', 'role-to-assume', 'region']);
145171
for (const key of Object.keys(entry)) {
146172
if (!allowedKeys.has(key)) {
147173
fail(`${path}.${key} is not supported for aws-ecr`);
@@ -150,15 +176,28 @@ jobs:
150176
if (awsEcr) {
151177
fail('only one aws-ecr registry identity is supported');
152178
}
153-
const awsRegion = requireString(entry, 'aws-region', path);
154-
const roleToAssume = requireString(entry, 'role-to-assume', path);
155-
const registry = requireString(entry, 'registry', path);
156179
awsEcr = {
157-
awsRegion,
158-
roleToAssume,
159-
registryAuth: yaml.dump([{
160-
registry
161-
}], {lineWidth: -1})
180+
registry: requireString(entry, 'registry', path),
181+
roleToAssume: requireString(entry, 'role-to-assume', path),
182+
region: requireString(entry, 'region', path)
183+
};
184+
break;
185+
}
186+
case 'gcp-wif': {
187+
const allowedKeys = new Set(['type', 'registry', 'workload_identity_provider', 'service_account', 'project_id']);
188+
for (const key of Object.keys(entry)) {
189+
if (!allowedKeys.has(key)) {
190+
fail(`${path}.${key} is not supported for gcp-wif`);
191+
}
192+
}
193+
if (gcpWif) {
194+
fail('only one gcp-wif registry identity is supported');
195+
}
196+
gcpWif = {
197+
registry: requireString(entry, 'registry', path),
198+
workloadIdentityProvider: requireString(entry, 'workload_identity_provider', path),
199+
serviceAccount: requireString(entry, 'service_account', path),
200+
projectId: requireString(entry, 'project_id', path)
162201
};
163202
break;
164203
}
@@ -168,6 +207,11 @@ jobs:
168207
});
169208
170209
core.setOutput('aws-ecr-enabled', awsEcr ? 'true' : 'false');
210+
core.setOutput('aws-ecr-registry', awsEcr?.registry || '');
171211
core.setOutput('aws-ecr-role-to-assume', awsEcr?.roleToAssume || '');
172-
core.setOutput('aws-ecr-region', awsEcr?.awsRegion || '');
173-
core.setOutput('aws-ecr-registry-auth', awsEcr?.registryAuth || '');
212+
core.setOutput('aws-ecr-region', awsEcr?.region || '');
213+
core.setOutput('gcp-wif-enabled', gcpWif ? 'true' : 'false');
214+
core.setOutput('gcp-wif-registry', gcpWif?.registry || '');
215+
core.setOutput('gcp-wif-workload-identity-provider', gcpWif?.workloadIdentityProvider || '');
216+
core.setOutput('gcp-wif-service-account', gcpWif?.serviceAccount || '');
217+
core.setOutput('gcp-wif-project-id', gcpWif?.projectId || '');

README.md

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ ___
1919
* [Notes](#notes)
2020
* [Signed GitHub Actions cache](#signed-github-actions-cache)
2121
* [Registry identities](#registry-identities)
22+
* [AWS ECR](#aws-ecr)
23+
* [Google Artifact Registry](#google-artifact-registry)
2224
* [Runner mapping](#runner-mapping)
2325
* [Metadata templates](#metadata-templates)
2426

@@ -412,9 +414,11 @@ secret. Provider-specific authentication steps are pinned in these reusable
412414
workflows; callers can only select supported provider types and pass identity
413415
configuration.
414416

415-
Amazon ECR private registry authentication is configured with `type: aws-ecr`.
416-
Callers must grant `id-token: write` so the AWS credential step can assume the
417-
role through GitHub OIDC:
417+
#### AWS ECR
418+
419+
Amazon ECR registry authentication is configured with `type: aws-ecr`. Callers
420+
must grant `id-token: write` so the AWS credential step can assume the role
421+
through GitHub OIDC:
418422

419423
```yaml
420424
jobs:
@@ -430,15 +434,62 @@ jobs:
430434
123456789100.dkr.ecr.us-east-1.amazonaws.com/sandbox/test-github-builder
431435
registry-identities: |
432436
- type: aws-ecr
433-
aws-region: us-east-1
434-
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
435437
registry: 123456789100.dkr.ecr.us-east-1.amazonaws.com
438+
role-to-assume: arn:aws:iam::123456789100:role/my-github-actions-role
439+
region: us-east-1
436440
```
437441

442+
| Name | Type | Description |
443+
|------------------|--------|---------------------------------------------------------------------------------------------------------------------------------|
444+
| `type` | String | Registry identity provider type. Must be `aws-ecr`. |
445+
| `registry` | String | Registry server passed to `docker/login-action`, such as `public.ecr.aws` for public ECR or a private ECR host for private ECR. |
446+
| `role-to-assume` | String | IAM role ARN assumed through GitHub OIDC. |
447+
| `region` | String | AWS region passed to `aws-actions/configure-aws-credentials` when assuming the role. Use `us-east-1` for ECR Public. |
448+
438449
The `registry` value is required for AWS ECR. Use the registry server that
439450
`docker/login-action` should log in to, such as `public.ecr.aws` for public ECR
440451
or `123456789100.dkr.ecr.us-east-1.amazonaws.com` for private ECR.
441452

453+
#### Google Artifact Registry
454+
455+
Google Artifact Registry authentication is configured with `type: gcp-wif`.
456+
Callers must grant `id-token: write` so `google-github-actions/auth` can
457+
exchange the GitHub OIDC token through GCP Workload Identity Federation:
458+
459+
```yaml
460+
jobs:
461+
build:
462+
uses: docker/github-builder/.github/workflows/build.yml@v1
463+
permissions:
464+
contents: read # to fetch the repository content
465+
id-token: write # for signing attestations, cache entries with GitHub OIDC and log in to Google Artifact Registry
466+
with:
467+
output: image
468+
push: ${{ github.event_name != 'pull_request' }}
469+
meta-images: |
470+
us-docker.pkg.dev/my-project/sandbox/test-github-builder
471+
registry-identities: |
472+
- type: gcp-wif
473+
registry: us-docker.pkg.dev
474+
workload_identity_provider: projects/123456789/locations/global/workloadIdentityPools/github/providers/provider
475+
service_account: builder@my-project.iam.gserviceaccount.com
476+
project_id: my-project
477+
```
478+
479+
| Name | Type | Description |
480+
|------------------------------|--------|------------------------------------------------------------------------------------------------------------------------------------------------|
481+
| `type` | String | Registry identity provider type. Must be `gcp-wif`. |
482+
| `registry` | String | Google Artifact Registry host passed to `docker/login-action`, such as `us-docker.pkg.dev`. Do not use the full repository path. |
483+
| `workload_identity_provider` | String | Workload Identity Provider resource name passed to `google-github-actions/auth`. |
484+
| `service_account` | String | Service account email passed to `google-github-actions/auth` for Workload Identity Federation. |
485+
| `project_id` | String | Google Cloud project ID passed to `google-github-actions/auth`. |
486+
487+
The `registry` value is required for GCP WIF. Use the Artifact Registry host
488+
that `docker/login-action` should log in to, such as `us-docker.pkg.dev`, not
489+
the full repository path. The workflow requests an access token from
490+
`google-github-actions/auth` and passes it directly to `docker/login-action`
491+
with the `oauth2accesstoken` username inside the same job.
492+
442493
### Runner mapping
443494

444495
The `runner` input accepts either a single GitHub-hosted Linux runner label or a

0 commit comments

Comments
 (0)