Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: Add example for using GCP Workload Identity #2000

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
120 changes: 120 additions & 0 deletions internal/builders/container/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ project simply generates provenance as a separate step in an existing workflow.
- [Benefits of Provenance](#benefits-of-provenance)
- [Generating Provenance](#generating-provenance)
- [Getting Started](#getting-started)
- [With GCP Artifact Registry](#with-gcp-artifact-registry)
- [Referencing the SLSA generator](#referencing-the-slsa-generator)
- [Private Repositories](#private-repositories)
- [Supported Triggers](#supported-triggers)
Expand Down Expand Up @@ -152,6 +153,125 @@ jobs:
registry-password: ${{ secrets.GITHUB_TOKEN }}
```

#### With GCP Artifact Registry

The following is an example of pushing an image to an [Artifact Registry](https://cloud.google.com/artifact-registry) in GCP and generating the provenance for that image. In order for you to run this example, you will need to have a [Workload Identity Federation](https://cloud.google.com/iam/docs/workload-identity-federation) that enables you to exchange a GitHub token for access within GCP. If you have not yet created one or have not created a provider within your existing federation for GitHub, please review the following resources:

- https://gist.github.com/palewire/12c4b2b974ef735d22da7493cf7f4d37
chasen-bettinger marked this conversation as resolved.
Show resolved Hide resolved
- https://cloud.google.com/blog/products/identity-security/enabling-keyless-authentication-from-github-actions
chasen-bettinger marked this conversation as resolved.
Show resolved Hide resolved

Once you have a Workload Identity Federation with a GitHub provider, you're ready to begin implementing the GitHub Action below.

```yaml
env:
IMAGE_NAME: ${{ github.repository }}
# FORMAT:
# {region}-docker.pkg.dev/{project-id}/{artifact-registry-name}
# EXAMPLE:
# northamerica-northeast1-docker.pkg.dev/blank-check-231234/your-repository
REPOSITORY_PATH: ${{ vars.REPOSITORY_PATH }}
# EXAMPLE:
# projects/123123412578/locations/global/workloadIdentityPools/my-pool/providers/my-provider
WORKLOAD_IDENTITY_PROVIDER: ${{ vars.WORKLOAD_IDENTITY_PROVIDER }}
# EXAMPLE:
# [email protected]
SERVICE_ACCOUNT: ${{ vars.SERVICE_ACCOUNT }}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please set the default pemissions, e.g.

permissions: read-all

or

permissions:
   contents: read

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the what or why behind this comment. Could you expand please?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that if this is meant to be a full example it should include a set of default permissions.
https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions

The defaults are usually permissive and we'd like to encourage folks to explicitly set them to be less permissive.
https://docs.github.com/en/actions/security-guides/automatic-token-authentication#permissions-for-the-github_token

on: [push]

jobs:
# This step builds our image, pushes it, and outputs the repo hash digest.
build:
permissions:
contents: read
packages: write
id-token: write
outputs:
image: ${{ steps.image.outputs.image }}
digest: ${{ steps.build.outputs.digest }}
workload_identity_provider: ${{ steps.idprov.outputs.widp }}
service_account: ${{ steps.sa.outputs.sa }}
runs-on: ubuntu-latest
steps:
- name: Checkout the repository
uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b # v2.3.4

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@dc7b9719a96d48369863986a06765841d7ea23f6 # v2.0.0

- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/[email protected]'
with:
token_format: 'access_token'
workload_identity_provider: ${{ vars.WORKLOAD_IDENTITY_PROVIDER }}
service_account: ${{ vars.SERVICE_ACCOUNT }}

- name: Authenticate Docker
uses: docker/login-action@49ed152c8eca782a232dede0303416e8f356c37b # v2.0.0
with:
registry: northamerica-northeast1-docker.pkg.dev
username: oauth2accesstoken
password: ${{ steps.auth.outputs.access_token }}

- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@69f6fc9d46f2f8bf0d5491e4aabe0bb8c6a4678a # v4.0.1
with:
images: ${{ vars.REPOSITORY_PATH }}/${{ env.IMAGE_NAME }}

- name: Build and push Docker image
uses: docker/build-push-action@e551b19e49efd4e98792db7592c17c09b89db8d8 # v3.0.0
id: build
with:
push: true
tags: |
${{ steps.meta.outputs.tags }}
${{ vars.REPOSITORY_PATH }}/${{ env.IMAGE_NAME }}:latest
labels: ${{ steps.meta.outputs.labels }}

- name: Output image
id: image
run: |
# NOTE: Set the image as an output because the `env` context is not
# available to the inputs of a reusable workflow call.
image_name="${REPOSITORY_PATH}/${IMAGE_NAME}"
echo image=$image_name >> "$GITHUB_OUTPUT"

- name: Output workload_identity_provider
id: idprov
run: |
workload_identity_provider=${WORKLOAD_IDENTITY_PROVIDER}
echo widp=$workload_identity_provider >> "$GITHUB_OUTPUT"

- name: Output service_account
id: sa
run: |
service_account=${SERVICE_ACCOUNT}
echo sa=$service_account >> "$GITHUB_OUTPUT"
chasen-bettinger marked this conversation as resolved.
Show resolved Hide resolved

# This step calls the container workflow to generate provenance and push it to
# the container registry.
provenance:
needs: [build]
permissions:
actions: read # for detecting the Github Actions environment.
id-token: write # for creating OIDC tokens for signing.
packages: write # for uploading attestations.
uses: slsa-framework/slsa-github-generator/.github/workflows/[email protected]
with:
image: ${{ needs.build.outputs.image }}
digest: ${{ needs.build.outputs.digest }}
gcp-workload-identity-provider: ${{ needs.build.outputs.workload_identity_provider }}
gcp-service-account: ${{ needs.build.outputs.service_account }}
chasen-bettinger marked this conversation as resolved.
Show resolved Hide resolved
registry-username: ${{ github.actor }}
secrets:
registry-password: ${{ secrets.GITHUB_TOKEN }}

```

NOTE: There are existing challenges with using secrets in reusable workflows. Due to these problems, you will likely need to use unencrypted environment variables. To learn more: https://github.com/orgs/community/discussions/17554 and https://colinsalmcorner.com/consuming-environment-secrets-in-reusable-workflows/.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I'm misunderstanding something but IIUC, Since the user isn't writing a reusable workflow, but rather calling one, this shouldn't really be an issue. Are you referring to something specific here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was my attempt at articulating that the caller cannot pass values within the secrets. object into reusable workflows. They'll have to use whatever is stored in vars..

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this is specific to our reusable workflows or to workload identity so maybe we can just leave this out as I think it might confuse the reader.

Or maybe you can be more specific? Like saying something like "WORKLOAD_IDENTITY_PROVIDER and SERVICE_ACCOUNT should be stored in vars rather than secrets as you cannot pass secrets to reusable workflow inputs".

wdut?


### Referencing the SLSA generator

At present, the generator **MUST** be referenced
Expand Down