From 23a2d52a99635f57dbf9c8ecd225a92c86d8c175 Mon Sep 17 00:00:00 2001 From: saisatishkarra Date: Mon, 20 Nov 2023 21:50:53 -0600 Subject: [PATCH] feat: Set cosign-repository input and env (#2962) Solves: #2956 --------- Signed-off-by: saisatishkarra Signed-off-by: laurentsimon <64505099+laurentsimon@users.noreply.github.com> Co-authored-by: laurentsimon <64505099+laurentsimon@users.noreply.github.com> Co-authored-by: Ian Lewis --- .../workflows/generator_container_slsa3.yml | 71 ++++++++++++++++++- internal/builders/container/README.md | 10 ++- 2 files changed, 77 insertions(+), 4 deletions(-) diff --git a/.github/workflows/generator_container_slsa3.yml b/.github/workflows/generator_container_slsa3.yml index 7c36b2339f..3096325d88 100644 --- a/.github/workflows/generator_container_slsa3.yml +++ b/.github/workflows/generator_container_slsa3.yml @@ -28,12 +28,20 @@ defaults: on: workflow_call: secrets: + # Note: This should only be used for high entropy values such as AWS Access Key. + # See https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/container#workflow-inputs for more information. registry-username: description: "Username to log into the container registry." registry-password: description: "Password to log in the container registry." image: description: "The OCI image name. This must not include a tag or digest." + # Note: This should only be used for high entropy values such as AWS Access Key. + # See https://github.com/slsa-framework/slsa-github-generator/tree/main/internal/builders/container#workflow-inputs for more information. + provenance-registry-username: + description: "Username when publishing to provenance registry (option 'provenance-registry') instead of image registry." + provenance-registry-password: + description: "Password when publishing to provenance registry instead of image registry." inputs: image: description: "The OCI image name. This must not include a tag or digest." @@ -70,6 +78,14 @@ on: required: false type: string default: "" + provenance-registry-username: + description: "Username when publishing to provenance registry (option 'provenance-registry') instead of image registry." + required: false + type: string + provenance-registry: + description: "If set, provenance is pushed to this registry instead of image registry." + required: false + type: string outputs: # Note: we use this output because there is no buildt-in `outcome` and `result` is always `success` # if `continue-on-error` is set to `true`. @@ -153,6 +169,8 @@ jobs: cosign-release: v2.0.0 continue-on-error: true + # TODO(#2974): consolidate this code into a script + # The script below is a duplicate of the code used for signing into the provenance registry - name: Login id: login continue-on-error: true @@ -196,6 +214,51 @@ jobs: echo "login to ${untrusted_registry}" cosign login "${untrusted_registry}" -u "${username}" -p "${password}" + # TODO(#2974): consolidate this code into a script + # The script below is a duplicate of the code used for signing into the main registry + - name: Provenance registry login + id: provenance-registry-login + continue-on-error: true + env: + UNTRUSTED_PROVENANCE_REGISTRY: "${{ inputs.provenance-registry }}" + UNTRUSTED_INPUT_PROVENANCE_USERNAME: "${{ inputs.provenance-registry-username }}" + UNTRUSTED_SECRET_PROVENANCE_USERNAME: "${{ secrets.provenance-registry-username }}" + UNTRUSTED_PROVENANCE_PASSWORD: "${{ secrets.provenance-registry-password }}" + GCP_ACCESS_TOKEN: "${{ steps.auth.outputs.access_token }}" + if: ${{ env.UNTRUSTED_PROVENANCE_REGISTRY != '' }} + run: | + set -euo pipefail + + # NOTE: Some registries are of the form / + # Here we get the first part and check if it has a '.' or ':' + # character in it to see if it's a domain name. + # See: https://stackoverflow.com/questions/37861791/how-are-docker-image-names-parsed#37867949 + + untrusted_provenance_domain="docker.io" + maybe_provenance_domain=$(echo "${UNTRUSTED_PROVENANCE_REGISTRY}" | cut -f1 -d "/" | { grep -E "\.|:" || true; }) + if [ "${maybe_provenance_domain}" != "" ]; then + untrusted_provenance_domain="${maybe_provenance_domain}" + fi + + if [ "${GCP_ACCESS_TOKEN}" != "" ]; then + username="oauth2accesstoken" + password="${GCP_ACCESS_TOKEN}" + else + username="${UNTRUSTED_SECRET_PROVENANCE_USERNAME:-${UNTRUSTED_INPUT_PROVENANCE_USERNAME}}" + if [ "${username}" == "" ]; then + echo "provenance-registry-username is required." >&2 + exit 1 + fi + password="${UNTRUSTED_PROVENANCE_PASSWORD}" + if [ "${password}" == "" ]; then + echo "provenance-registry-password is required." >&2 + exit 1 + fi + fi + + echo "login to provenance registry: ${untrusted_provenance_domain}" + cosign login "${untrusted_provenance_domain}" -u "${username}" -p "${password}" + - name: Create and sign provenance id: sign-prov continue-on-error: true @@ -204,6 +267,7 @@ jobs: UNTRUSTED_SECRET_IMAGE: "${{ secrets.image }}" UNTRUSTED_DIGEST: "${{ inputs.digest }}" GITHUB_CONTEXT: "${{ toJSON(github) }}" + UNTRUSTED_PROVENANCE_REGISTRY: "${{ inputs.provenance-registry }}" run: | set -euo pipefail @@ -211,7 +275,12 @@ jobs: predicate_name="predicate.json" "$GITHUB_WORKSPACE/$BUILDER_BINARY" generate --predicate="$predicate_name" - COSIGN_EXPERIMENTAL=1 cosign attest --predicate="$predicate_name" \ + if [[ -n "${UNTRUSTED_PROVENANCE_REGISTRY}" ]]; then + export COSIGN_REPOSITORY="${UNTRUSTED_PROVENANCE_REGISTRY}" + fi + + COSIGN_EXPERIMENTAL=1 \ + cosign attest --predicate="$predicate_name" \ --type slsaprovenance \ --yes \ "${UNTRUSTED_SECRET_IMAGE:-${UNTRUSTED_IMAGE}}@${UNTRUSTED_DIGEST}" diff --git a/internal/builders/container/README.md b/internal/builders/container/README.md index b12a39397a..61d47b4801 100644 --- a/internal/builders/container/README.md +++ b/internal/builders/container/README.md @@ -214,14 +214,18 @@ Inputs: | `continue-on-error` | Set to true to ignore errors. This option is useful if you won't want a failure to fail your entire workflow.
Default: `false` | | `gcp-workload-identity-provider` | The full identifier of the Workload Identity Provider, including the project number, pool name, and provider name. If provided, this must be the full identifier which includes all parts:
`projects/123456789/locations/global/workloadIdentityPools/my-pool/providers/my-provider` | | `gcp-service-account` | Email address or unique identifier of the Google Cloud service account for which to generate credentials. For example:
`my-service-account@my-project.iam.gserviceaccount.com` | +| `provenance-registry-username` | Username when publishing to provenance registry (option 'provenance-registry') instead of image registry. Either `provenance-registry-username` input or `provenance-registry-username` secret is required. | +| `provenance-registry` | If set, provenance is pushed to this registry instead of image registry. (e.g. `gcr.io/my-new-repo`) | Secrets: | Name | Description | |---------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `image` | The OCI image name. This must not include a tag or digest. Either `image` input or `image` secret is **required**. Secret `image` value takes precedence on `image` input value. Should be used in scenarios when the image name contains secret values, and therefore can't be provided directly. Use case - an undisclosed private registry use. | -| `registry-username` | Username to log in the container registry. Either `registry-username` input or `registry-username` secret is required. This should only be used for high entropy values such as AWS Access Key as described [here](https://github.com/docker/login-action#aws-elastic-container-registry-ecr). Normal username values could match other input values and cause them to be ignored by GitHub Actions and causing your build to fail. In those cases, use the `registry-username` input instead. | -| `registry-password` | **(Required)** Password to log in the container registry. | +| `image` | The OCI image name. This must not include a tag or digest. Either `image` input or `image` secret is **required**. Secret `image` value takes precedence on `image` input value. Should be used in scenarios when the image name contains secret values, and therefore can't be provided directly. Use case - an undisclosed private registry use. | +| `registry-username` | Username to log in the container registry. Either `registry-username` input or `registry-username` secret is required. This should only be used for high entropy values such as AWS Access Key as described [here](https://github.com/docker/login-action#aws-elastic-container-registry-ecr). Normal username values could match other input values and cause them to be ignored by GitHub Actions and causing your build to fail. In those cases, use the `registry-username` input instead. | +| `registry-password` | **(Required)** Password to log in the container registry. | +| `provenance-registry-username` | Username when publishing to provenance registry (option 'provenance-registry') instead of image registry. Either `provenance-registry-username` input or `provenance-registry-username` secret is required. This should only be used for high entropy values such as AWS Access Key as described [here](https://github.com/docker/login-action#aws-elastic-container-registry-ecr). Normal username values could match other input values and cause them to be ignored by GitHub Actions and causing your build to fail. In those cases, use the registry-username input instead. | +| `provenance-registry-password` | Password when publishing to provenance registry instead of image registry. | ### Workflow Outputs