From df154053e6e64ef61884b1b8b161992e6d2787c0 Mon Sep 17 00:00:00 2001 From: Edoardo Rosa <6991986+notdodo@users.noreply.github.com> Date: Mon, 16 Feb 2026 14:10:36 +0100 Subject: [PATCH] [#patch] fix: image sign identity --- .github/workflows/docker-build-and-push.yml | 42 ++++++- README.md | 122 +++++++++++++++++++- 2 files changed, 159 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docker-build-and-push.yml b/.github/workflows/docker-build-and-push.yml index 7a66ba8..dff3b70 100644 --- a/.github/workflows/docker-build-and-push.yml +++ b/.github/workflows/docker-build-and-push.yml @@ -37,6 +37,9 @@ on: scan-image: type: boolean default: true + sign-image: + type: boolean + default: true tags: type: string default: | @@ -56,6 +59,19 @@ on: working-directory: type: string default: '.' + outputs: + image_name: + description: "Full image name (/)." + value: ${{ jobs.build-and-push-image.outputs.image_name }} + image_digest: + description: "Pushed image digest (sha256:...), empty when push=false." + value: ${{ jobs.build-and-push-image.outputs.image_digest }} + image_ref: + description: "Immutable image reference (/@), empty when push=false." + value: ${{ jobs.build-and-push-image.outputs.image_ref }} + local_image_ref: + description: "Local image reference used when push=false." + value: ${{ jobs.build-and-push-image.outputs.local_image_ref }} secrets: registry-username: required: false @@ -64,6 +80,11 @@ on: jobs: build-and-push-image: + outputs: + image_name: ${{ steps.workflow-outputs.outputs.image_name }} + image_digest: ${{ steps.workflow-outputs.outputs.image_digest }} + image_ref: ${{ steps.workflow-outputs.outputs.image_ref }} + local_image_ref: ${{ steps.workflow-outputs.outputs.local_image_ref }} permissions: artifact-metadata: write attestations: write @@ -144,6 +165,18 @@ jobs: load: true push: false tags: localimage:${{ github.sha }} + - name: Set workflow outputs + id: workflow-outputs + env: + IMAGE_NAME: ${{ format('{0}/{1}', inputs.registry, inputs.image) }} + IMAGE_DIGEST: ${{ inputs.push && steps.build.outputs.digest || '' }} + IMAGE_REF: ${{ inputs.push && format('{0}/{1}@{2}', inputs.registry, inputs.image, steps.build.outputs.digest) || '' }} + LOCAL_IMAGE_REF: ${{ !inputs.push && format('localimage:{0}', github.sha) || '' }} + run: | + echo "image_name=${IMAGE_NAME}" >> "${GITHUB_OUTPUT}" + echo "image_digest=${IMAGE_DIGEST}" >> "${GITHUB_OUTPUT}" + echo "image_ref=${IMAGE_REF}" >> "${GITHUB_OUTPUT}" + echo "local_image_ref=${LOCAL_IMAGE_REF}" >> "${GITHUB_OUTPUT}" - name: Generate artifact attestation if: inputs.push uses: actions/attest-build-provenance@96278af6caaf10aea03fd8d33a09a777ca52d62f # v3.2.0 @@ -180,17 +213,18 @@ jobs: sbom-path: ${{ inputs.working-directory }}/sbom.spdx.json - name: Install cosign uses: sigstore/cosign-installer@faadad0cce49287aee09b3a48701e75088a2c6ad # v4.0.0 - if: inputs.push + if: inputs.push && inputs.sign-image - name: Sign image - if: inputs.push + if: inputs.push && inputs.sign-image env: COSIGN_YES: 'true' IMAGE_REF: ${{ format('{0}/{1}@{2}', inputs.registry, inputs.image, steps.build.outputs.digest) }} - CERT_IDENTITY: ${{ format('https://github.com/{0}', github.workflow_ref) }} CERT_OIDC_ISSUER: https://token.actions.githubusercontent.com run: | cosign sign "${IMAGE_REF}" - cosign verify --certificate-identity "${CERT_IDENTITY}" --certificate-oidc-issuer "${CERT_OIDC_ISSUER}" "${IMAGE_REF}" + cosign verify \ + --certificate-identity-regexp '^https://github.com/notdodo/github-actions/.github/workflows/docker-build-and-push.yml@refs/tags/docker-build-and-push-v[0-9]+$' \ + --certificate-oidc-issuer "${CERT_OIDC_ISSUER}" "${IMAGE_REF}" - uses: reviewdog/action-setup@d8a7baabd7f3e8544ee4dbde3ee41d0011c3a93f # v1.5.0 if: inputs.scan-image - name: Run reviewdog diff --git a/README.md b/README.md index b65dfe8..c6cc4fc 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,13 @@ Collection of reusable workflows and custom actions designed to streamline autom ## Available Workflows - `notdodo/github-actions/.github/workflows/clean-branch-cache.yml`: Use to cleanup the cache for a merge branch -- `notdodo/github-actions/.github/workflows/docker-build-and-push.yml`: Builds a Dockerfile and upload the image to a registry and also performs a scan using [Trivy](https://trivy.dev/latest/) +- `notdodo/github-actions/.github/workflows/docker-build-and-push.yml`: Builds a Dockerfile, optionally signs it with cosign, uploads the image to a registry, and performs a scan using [Trivy](https://trivy.dev/latest/) - `notdodo/github-actions/.github/workflows/gitleaks.yml`: Uses [Gitleaks](https://gitleaks.io/index.html) to scan the code for secrets - `notdodo/github-actions/.github/workflows/go-ci.yml`: Used for Golang CI linting and testing - `notdodo/github-actions/.github/workflows/go-security-scan.yml`: Used for Golang CI security scanning with Sarif support - `notdodo/github-actions/.github/workflows/infra-security-scan.yml`: Used for docker, Makefiles, Kubernetes security scanning with Sarif support +- `notdodo/github-actions/.github/workflows/pulumi-preview.yml`: Used to run Pulumi preview with PR comments and OIDC authentication +- `notdodo/github-actions/.github/workflows/pulumi-up.yml`: Used to run Pulumi up for stack deployments with OIDC authentication - `notdodo/github-actions/.github/workflows/python-ci.yml`: Used for Python CI linting and checking for [Poetry](https://python-poetry.org/) projects - `notdodo/github-actions/.github/workflows/rust-ci.yml`: Used for Rust CI linting, building and testing - `notdodo/github-actions/.github/workflows/sast.yml`: Used to run Semgrep on the repository with Sarif support @@ -80,6 +82,51 @@ jobs: # infra-scan-v0.0.0 ``` +### Pulumi Preview + +```yaml +name: Pulumi Preview +on: + pull_request: + branches: + - main + +jobs: + pulumi-preview: + permissions: + contents: read + pull-requests: write + id-token: write + uses: notdodo/github-actions/.github/workflows/pulumi-preview.yml@pulumi-preview-v0 + with: + stack-name: notdodo/my-project/dev + working-directory: infra + aws-role: arn:aws:iam::123456789012:role/github-actions-pulumi-preview + aws-region: eu-west-1 +``` + +### Pulumi Up + +```yaml +name: Pulumi Up +on: + push: + branches: + - main + +jobs: + pulumi-up: + permissions: + contents: read + id-token: write + uses: notdodo/github-actions/.github/workflows/pulumi-up.yml@pulumi-up-v0 + with: + stack-name: notdodo/my-project/prod + working-directory: infra + aws-role: arn:aws:iam::123456789012:role/github-actions-pulumi-up + aws-region: eu-west-1 +``` + ### Python CI ```yaml @@ -136,6 +183,79 @@ jobs: registry-password: ${{ secrets.GITHUB_TOKEN }} ``` +By default, this workflow signs pushed images with cosign (`sign-image: true`) using the reusable workflow identity (the certificate identity belongs to the reusable workflow reference). + +To skip signing in the reusable workflow: + +```yaml +jobs: + build-push-docker-image: + uses: notdodo/github-actions/.github/workflows/docker-build-and-push.yml@docker-build-and-push-v1 + with: + image: notdodo/my-app + push: true + registry: ghcr.io + sign-image: false + secrets: + registry-username: notdodo + registry-password: ${{ secrets.GITHUB_TOKEN }} +``` + +Example: sign in the caller workflow instead of the reusable workflow. + +When used as a reusable workflow, these job outputs are available to the caller: + +- `image_name`: `/` +- `image_digest`: pushed digest (`sha256:...`), empty when `push: false` +- `image_ref`: immutable image reference (`/@`), empty when `push: false` +- `local_image_ref`: local image reference (`localimage:`), only set when `push: false` + +```yaml +name: Docker Build, Then Sign in Caller +on: + push: + branches: [main] + +jobs: + build-image: + permissions: + attestations: write + contents: read + id-token: write + packages: write + security-events: write + uses: notdodo/github-actions/.github/workflows/docker-build-and-push.yml@docker-build-and-push-v1 + with: + image: notdodo/my-app + push: true + registry: ghcr.io + sign-image: false + secrets: + registry-username: notdodo + registry-password: ${{ secrets.GITHUB_TOKEN }} + + sign-image: + needs: [build-image] + runs-on: ubuntu-latest + permissions: + id-token: write + contents: read + steps: + - uses: sigstore/cosign-installer@v4.0.0 + - name: Sign and verify + env: + COSIGN_YES: "true" + IMAGE_REF: ${{ needs.build-image.outputs.image_ref }} + CERT_OIDC_ISSUER: https://token.actions.githubusercontent.com + CERT_IDENTITY: ${{ format('https://github.com/{0}', github.workflow_ref) }} + run: | + cosign sign "${IMAGE_REF}" + cosign verify \ + --certificate-identity "${CERT_IDENTITY}" \ + --certificate-oidc-issuer "${CERT_OIDC_ISSUER}" \ + "${IMAGE_REF}" +``` + ### Auto tagger ```yaml