From ca10f3cba0eedbef99327c332f2902eb6b876b64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Guilherme=20Vanz?= Date: Mon, 25 Nov 2024 14:50:05 -0300 Subject: [PATCH] chore(ci): allow slsactl verification. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Updates the release.yml file to allow users verify the attestation content of the policy server using slsactl command. slsactl does not support the verification of the artefacts when it's build using sub workflow files. This is fixed by copying the content of the container-build.yml file into the release.yml file. Signed-off-by: José Guilherme Vanz --- .github/workflows/attestation.yml | 102 ----------------- .github/workflows/container-build.yml | 70 +++++++++--- .github/workflows/container-image.yml | 82 ------------- .github/workflows/release.yml | 159 ++++++++++++++++++++++++-- 4 files changed, 205 insertions(+), 208 deletions(-) delete mode 100644 .github/workflows/attestation.yml delete mode 100644 .github/workflows/container-image.yml diff --git a/.github/workflows/attestation.yml b/.github/workflows/attestation.yml deleted file mode 100644 index 81819119..00000000 --- a/.github/workflows/attestation.yml +++ /dev/null @@ -1,102 +0,0 @@ -name: Sign attestation files - -on: - workflow_call: - inputs: - image-digest: - type: string - required: true - -jobs: - sbom: - name: Fetch, sign and verify SBOM and provenance files - strategy: - matrix: - arch: [amd64, arm64] - - permissions: - packages: write - id-token: write - - runs-on: ubuntu-latest - steps: - - name: Install cosign - uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - - - name: Install the crane command - uses: kubewarden/github-actions/crane-installer@d94509d260ee11a92b4f65bc0acd297feec24d7f # v3.3.5 - - - name: Login to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Verify container image signature - run: | - cosign verify \ - --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ - --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/container-image.yml@${{ github.ref }}" \ - ghcr.io/${{ github.repository_owner }}/policy-server@${{ inputs.image-digest }} - - - name: Find platform digest - shell: bash - run: | - set -e - DIGEST=$(crane digest \ - --platform "linux/${{ matrix.arch }}" \ - ghcr.io/${{ github.repository_owner }}/policy-server@${{ inputs.image-digest }}) - echo "PLATFORM_DIGEST=${DIGEST}" >> "$GITHUB_ENV" - - - name: Find attestation digest - run: | - set -e - DIGEST=$(crane manifest ghcr.io/${{github.repository_owner}}/policy-server@${{ inputs.image-digest }} \ - | jq '.manifests[] | select(.annotations["vnd.docker.reference.type"]=="attestation-manifest") | select(.annotations["vnd.docker.reference.digest"]=="${{ env.PLATFORM_DIGEST }}") | .digest' - ) - echo "ATTESTATION_MANIFEST_DIGEST=${DIGEST}" >> "$GITHUB_ENV" - - - name: Find provenance manifest digest - run: | - set -e - DIGEST=$(crane manifest ghcr.io/${{github.repository_owner}}/policy-server@${{ env.ATTESTATION_MANIFEST_DIGEST}} | \ - jq '.layers[] | select(.annotations["in-toto.io/predicate-type"] == "https://slsa.dev/provenance/v0.2") | .digest') - echo "PROVENANCE_DIGEST=${DIGEST}" >> "$GITHUB_ENV" - - - name: Find SBOM manifest layers digest - run: | - set -e - DIGEST=$(crane manifest ghcr.io/${{github.repository_owner}}/policy-server@${{ env.ATTESTATION_MANIFEST_DIGEST}} | \ - jq '.layers | map(select(.annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document")) | map(.digest) | join(" ")') - echo "SBOM_DIGEST=${DIGEST}" >> "$GITHUB_ENV" - - - name: Download provenance and SBOM files - run: | - set -e - crane blob ghcr.io/${{github.repository_owner}}/policy-server@${{ env.PROVENANCE_DIGEST}} > policy-server-attestation-${{ matrix.arch }}-provenance.json - sha256sum policy-server-attestation-${{ matrix.arch }}-provenance.json >> policy-server-attestation-${{ matrix.arch }}-checksum.txt - - - for sbom_digest in "${{ env.SBOM_DIGEST }}"; do - crane blob ghcr.io/${{github.repository_owner}}/policy-server@$sbom_digest > policy-server-attestation-${{ matrix.arch }}-sbom-${sbom_digest#"sha256:"}.json - sha256sum policy-server-attestation-${{ matrix.arch }}-sbom-${sbom_digest#"sha256:"}.json >> policy-server-attestation-${{ matrix.arch }}-checksum.txt - done - - - name: Sign checksum file - run: | - cosign sign-blob --yes \ - --bundle policy-server-attestation-${{ matrix.arch }}-checksum-cosign.bundle \ - policy-server-attestation-${{ matrix.arch }}-checksum.txt - - cosign verify-blob \ - --bundle policy-server-attestation-${{ matrix.arch }}-checksum-cosign.bundle \ - --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ - --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/attestation.yml@${{ github.ref }}" \ - policy-server-attestation-${{ matrix.arch }}-checksum.txt - - - name: Upload SBOMs as artifacts - uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 - with: - name: attestation-${{ matrix.arch }} - path: policy-server-attestation-${{ matrix.arch }}* diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index 86293477..2dcfdf63 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -1,12 +1,6 @@ -name: Build container image, sign it, and generate SBOMs +name: Build container image and sign it on: - workflow_call: - outputs: - digest: - description: "Container image digest" - value: ${{jobs.build.outputs.digest}} - push: branches: - "main" @@ -17,17 +11,59 @@ permissions: jobs: build: - uses: ./.github/workflows/container-image.yml + name: Build container image permissions: packages: write id-token: write + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - sbom: - needs: - - build - uses: ./.github/workflows/attestation.yml - permissions: - packages: write - id-token: write - with: - image-digest: ${{ needs.build.outputs.digest }} + - name: Install cosign + uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 + + - name: Login to GitHub Container Registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Retrieve tag name (main branch) + if: ${{ startsWith(github.ref, 'refs/heads/main') }} + run: | + echo TAG_NAME=latest >> $GITHUB_ENV + + - name: Retrieve tag name (feat branch) + if: ${{ startsWith(github.ref, 'refs/heads/feat') }} + run: | + echo "TAG_NAME=latest-$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV + + - name: Push and push container image + id: build-image + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64, linux/arm64 + push: true + sbom: false # SBOM for feature and main branches is not generated + provenance: false # Provenance for feature and main branches is not generated + tags: | + ghcr.io/${{github.repository_owner}}/policy-server:${{ env.TAG_NAME }} + + - name: Sign container image + run: | + cosign sign --yes ghcr.io/${{github.repository_owner}}/policy-server@${{ steps.build-image.outputs.digest }} + + cosign verify \ + --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ + --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/container-build.yml@${{ github.ref }}" \ + ghcr.io/${{github.repository_owner}}/policy-server@${{ steps.build-image.outputs.digest }} diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml deleted file mode 100644 index a476b344..00000000 --- a/.github/workflows/container-image.yml +++ /dev/null @@ -1,82 +0,0 @@ -name: Build container image - -on: - workflow_call: - outputs: - digest: - description: "Image digest" - value: ${{ jobs.build.outputs.digest }} - -jobs: - build: - name: Build container image - permissions: - packages: write - id-token: write - runs-on: ubuntu-latest - outputs: - repository: ${{ steps.setoutput.outputs.repository }} - tag: ${{ steps.setoutput.outputs.tag }} - artifact: ${{ steps.setoutput.outputs.artifact }} - digest: ${{ steps.setoutput.outputs.digest }} - steps: - - name: Checkout code - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - - - name: Install cosign - uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 - - - name: Set up QEMU - uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 - - - name: Login to GitHub Container Registry - uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - name: Retrieve tag name (main branch) - if: ${{ startsWith(github.ref, 'refs/heads/main') }} - run: | - echo TAG_NAME=latest >> $GITHUB_ENV - - - name: Retrieve tag name (feat branch) - if: ${{ startsWith(github.ref, 'refs/heads/feat') }} - run: | - echo "TAG_NAME=latest-$(echo ${GITHUB_REF#refs/heads/})" >> $GITHUB_ENV - - - name: Retrieve tag name (tag) - if: ${{ startsWith(github.ref, 'refs/tags/') }} - run: | - echo TAG_NAME=$(echo $GITHUB_REF | sed -e "s|refs/tags/||") >> $GITHUB_ENV - - - name: Push and push container image - id: build-image - uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 - with: - context: . - file: ./Dockerfile - platforms: linux/amd64, linux/arm64 - push: true - sbom: true - provenance: mode=max - tags: | - ghcr.io/${{github.repository_owner}}/policy-server:${{ env.TAG_NAME }} - - - name: Sign container image - run: | - cosign sign --yes ghcr.io/${{github.repository_owner}}/policy-server@${{ steps.build-image.outputs.digest }} - - cosign verify \ - --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ - --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/container-image.yml@${{ github.ref }}" \ - ghcr.io/${{github.repository_owner}}/policy-server@${{ steps.build-image.outputs.digest }} - - - id: setoutput - name: Set output parameters - run: | - echo "digest=${{ steps.build-image.outputs.digest }}" >> $GITHUB_OUTPUT diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6f8a1fcb..ff0593f1 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,25 +13,170 @@ jobs: permissions: read-all build: - name: Build container image, sign it, and generate SBOMs - uses: ./.github/workflows/container-build.yml + name: Build container image permissions: + packages: write id-token: write + runs-on: ubuntu-latest + outputs: + repository: ${{ steps.setoutput.outputs.repository }} + tag: ${{ steps.setoutput.outputs.tag }} + artifact: ${{ steps.setoutput.outputs.artifact }} + digest: ${{ steps.setoutput.outputs.digest }} + steps: + - name: Checkout code + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install cosign + uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 + + - name: Set up QEMU + uses: docker/setup-qemu-action@49b3bc8e6bdd4a60e6116a5414239cba5943d3cf # v3.2.0 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@c47758b77c9736f4b2ef4073d4d51994fabfe349 # v3.7.1 + + - name: Login to GitHub Container Registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Retrieve tag name (tag) + run: | + echo TAG_NAME=$(echo $GITHUB_REF | sed -e "s|refs/tags/||") >> $GITHUB_ENV + + - name: Push and push container image + id: build-image + uses: docker/build-push-action@4f58ea79222b3b9dc2c8bbdd6debcef730109a75 # v6.9.0 + with: + context: . + file: ./Dockerfile + platforms: linux/amd64, linux/arm64 + push: true + sbom: true + provenance: mode=max + tags: | + ghcr.io/${{github.repository_owner}}/policy-server:${{ env.TAG_NAME }} + + - name: Sign container image + run: | + cosign sign --yes ghcr.io/${{github.repository_owner}}/policy-server@${{ steps.build-image.outputs.digest }} + + cosign verify \ + --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ + --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/release.yml@${{ github.ref }}" \ + ghcr.io/${{github.repository_owner}}/policy-server@${{ steps.build-image.outputs.digest }} + + - id: setoutput + name: Set output parameters + run: | + echo "digest=${{ steps.build-image.outputs.digest }}" >> $GITHUB_OUTPUT + + sbom: + name: Fetch, sign and verify SBOM and provenance files + strategy: + matrix: + arch: [amd64, arm64] + permissions: packages: write - contents: read + id-token: write + needs: + - build + + runs-on: ubuntu-latest + steps: + - name: Install cosign + uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0 + + - name: Install the crane command + uses: kubewarden/github-actions/crane-installer@d94509d260ee11a92b4f65bc0acd297feec24d7f # v3.3.5 + + - name: Login to GitHub Container Registry + uses: docker/login-action@9780b0c442fbb1117ed29e0efdff1e18412f7567 # v3.3.0 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Verify container image signature + run: | + cosign verify \ + --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ + --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/release.yml@${{ github.ref }}" \ + ghcr.io/${{ github.repository_owner }}/policy-server@${{ needs.build.outputs.digest }} + + - name: Find platform digest + shell: bash + run: | + set -e + DIGEST=$(crane digest \ + --platform "linux/${{ matrix.arch }}" \ + ghcr.io/${{ github.repository_owner }}/policy-server@${{ needs.build.outputs.digest }}) + echo "PLATFORM_DIGEST=${DIGEST}" >> "$GITHUB_ENV" + + - name: Find attestation digest + run: | + set -e + DIGEST=$(crane manifest ghcr.io/${{github.repository_owner}}/policy-server@${{ needs.build.outputs.digest }} \ + | jq '.manifests[] | select(.annotations["vnd.docker.reference.type"]=="attestation-manifest") | select(.annotations["vnd.docker.reference.digest"]=="${{ env.PLATFORM_DIGEST }}") | .digest' + ) + echo "ATTESTATION_MANIFEST_DIGEST=${DIGEST}" >> "$GITHUB_ENV" + + - name: Find provenance manifest digest + run: | + set -e + DIGEST=$(crane manifest ghcr.io/${{github.repository_owner}}/policy-server@${{ env.ATTESTATION_MANIFEST_DIGEST}} | \ + jq '.layers[] | select(.annotations["in-toto.io/predicate-type"] == "https://slsa.dev/provenance/v0.2") | .digest') + echo "PROVENANCE_DIGEST=${DIGEST}" >> "$GITHUB_ENV" + + - name: Find SBOM manifest layers digest + run: | + set -e + DIGEST=$(crane manifest ghcr.io/${{github.repository_owner}}/policy-server@${{ env.ATTESTATION_MANIFEST_DIGEST}} | \ + jq '.layers | map(select(.annotations["in-toto.io/predicate-type"] == "https://spdx.dev/Document")) | map(.digest) | join(" ")') + echo "SBOM_DIGEST=${DIGEST}" >> "$GITHUB_ENV" + + - name: Download provenance and SBOM files + run: | + set -e + crane blob ghcr.io/${{github.repository_owner}}/policy-server@${{ env.PROVENANCE_DIGEST}} > policy-server-attestation-${{ matrix.arch }}-provenance.json + sha256sum policy-server-attestation-${{ matrix.arch }}-provenance.json >> policy-server-attestation-${{ matrix.arch }}-checksum.txt + + + for sbom_digest in "${{ env.SBOM_DIGEST }}"; do + crane blob ghcr.io/${{github.repository_owner}}/policy-server@$sbom_digest > policy-server-attestation-${{ matrix.arch }}-sbom-${sbom_digest#"sha256:"}.json + sha256sum policy-server-attestation-${{ matrix.arch }}-sbom-${sbom_digest#"sha256:"}.json >> policy-server-attestation-${{ matrix.arch }}-checksum.txt + done + + - name: Sign checksum file + run: | + cosign sign-blob --yes \ + --bundle policy-server-attestation-${{ matrix.arch }}-checksum-cosign.bundle \ + policy-server-attestation-${{ matrix.arch }}-checksum.txt + + cosign verify-blob \ + --bundle policy-server-attestation-${{ matrix.arch }}-checksum-cosign.bundle \ + --certificate-oidc-issuer=https://token.actions.githubusercontent.com \ + --certificate-identity="https://github.com/${{github.repository_owner}}/policy-server/.github/workflows/release.yml@${{ github.ref }}" \ + policy-server-attestation-${{ matrix.arch }}-checksum.txt + + - name: Upload SBOMs as artifacts + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 + with: + name: attestation-${{ matrix.arch }} + path: policy-server-attestation-${{ matrix.arch }}* release: name: Create release - needs: - ci - build - + - sbom permissions: contents: write - runs-on: ubuntu-latest - steps: - name: Retrieve tag name if: ${{ startsWith(github.ref, 'refs/tags/') }}