From 4fbb07009417c81dd1300479ccc67595ae873fc0 Mon Sep 17 00:00:00 2001 From: Flavio Castelli Date: Mon, 24 Jul 2023 11:42:56 +0200 Subject: [PATCH 1/2] New SBOM generation process Use syft to produce bill or materials of the container image and the application itself. Ensure each architecture-specific build has its own SBOM, signed and attached to the specific image. Also, attach to the GH release the SBOM of each container image being built. Prior to this commit the SBOM was only generated for the x86_64 platform and was attached to the multi-architecture container image index manifest. Signed-off-by: Flavio Castelli --- .github/workflows/container-build.yml | 30 +++-------- .github/workflows/container-image.yml | 29 ---------- .github/workflows/e2e-tests.yml | 1 - .github/workflows/release.yml | 78 ++++++++++++++++----------- .github/workflows/sbom.yml | 77 ++++++++++++++++++++++++++ Dockerfile | 4 ++ 6 files changed, 134 insertions(+), 85 deletions(-) create mode 100644 .github/workflows/sbom.yml diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index 6231d834..c63d6884 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -6,6 +6,7 @@ on: digest: description: "Container image digest" value: ${{jobs.build.outputs.digest}} + push: branches: - "main" @@ -20,29 +21,12 @@ jobs: with: push-image: true - sign: - runs-on: ubuntu-latest + sbom: + name: SBOM + needs: build + uses: ./.github/workflows/sbom.yml permissions: packages: write id-token: write - needs: build - steps: - - name: Login to GitHub Container Registry - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.repository_owner }} - password: ${{ secrets.GITHUB_TOKEN }} - - - uses: sigstore/cosign-installer@v3 - - - name: Sign the images - run: | - cosign sign --yes \ - ${{needs.build.outputs.repository}}@${{needs.build.outputs.digest}} - - - name: Sign the SBOM - run: | - tag=$(echo '${{needs.build.outputs.digest}}' | sed 's/:/-/g') - cosign sign --yes \ - "${{needs.build.outputs.repository}}:$tag.sbom" + with: + image-digest: ${{ needs.build.outputs.digest }} diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index 619915a5..a4bfb37f 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -6,10 +6,6 @@ on: push-image: type: boolean required: true - generate-sbom: - type: boolean - required: false - default: true outputs: repository: description: "Repository used to build the container image" @@ -52,18 +48,6 @@ jobs: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - - name: Install Golang - uses: actions/setup-go@v4 - with: - go-version: '1.19' - - - name: Install the bom command - uses: kubewarden/github-actions/kubernetes-bom-installer@v2 - - - name: Install Cosign - if: ${{ inputs.generate-sbom == true }} - uses: sigstore/cosign-installer@v3 - name: Retrieve tag name (main branch) if: ${{ startsWith(github.ref, 'refs/heads/main') }} @@ -105,19 +89,6 @@ jobs: outputs: type=docker,dest=/tmp/kubewarden-controller-image-${{ env.TAG_NAME }}.tar tags: | ghcr.io/${{github.repository_owner}}/kubewarden-controller:${{ env.TAG_NAME }} - - - name: Create SBOM file - if: ${{ inputs.generate-sbom == true }} - shell: bash - run: | - bom generate -n https://kubewarden.io/kubewarden.spdx -o kubewarden-controller.spdx . - - - name: Attach SBOM file in the container image - if: ${{ inputs.generate-sbom == true }} - shell: bash - run: | - set -e - cosign attach sbom --sbom kubewarden-controller.spdx "ghcr.io/${{github.repository_owner}}/kubewarden-controller@${{ steps.build-image.outputs.digest }}" - name: Upload container image to use in other jobs if: ${{ inputs.push-image == false }} diff --git a/.github/workflows/e2e-tests.yml b/.github/workflows/e2e-tests.yml index 6ec8dff3..c0877841 100644 --- a/.github/workflows/e2e-tests.yml +++ b/.github/workflows/e2e-tests.yml @@ -16,7 +16,6 @@ jobs: packages: write with: push-image: false - generate-sbom: false run-e2e-tests: name: "Tests" needs: [build] diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ad9c5322..c875541e 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,33 +12,22 @@ jobs: uses: ./.github/workflows/ci.yml permissions: read-all - container-build: + build: + name: Build container uses: ./.github/workflows/container-build.yml permissions: id-token: write packages: write - release: - permissions: - id-token: write - contents: write - name: Create release + + crds: + name: Build CRDs runs-on: ubuntu-latest - needs: - - ci - - container-build steps: - name: Install Golang uses: actions/setup-go@v4 with: go-version: '1.19' - - name: Install the bom command - shell: bash - run: go install sigs.k8s.io/bom/cmd/bom@v0.2.2 - - - name: Install cosign - uses: sigstore/cosign-installer@v3 - - name: Checkout code uses: actions/checkout@v3 @@ -46,27 +35,32 @@ jobs: run: | make generate-crds tar -czf CRDS.tar.gz -C generated-crds $(ls generated-crds) + - + name: Upload CRDs as artifacts + uses: actions/upload-artifact@v3 + with: + name: CRDS + path: CRDS.tar.gz + + release: + name: Create release + + needs: + - ci + - crds + - build + + permissions: + contents: write + runs-on: ubuntu-latest + + steps: - name: Retrieve tag name if: ${{ startsWith(github.ref, 'refs/tags/') }} run: | echo TAG_NAME=$(echo ${{ github.ref_name }}) >> $GITHUB_ENV - - name: Create SBOM file - shell: bash - run: | - bom generate -n https://kubewarden.io/kubewarden.spdx \ - --image "ghcr.io/${{github.repository_owner}}/kubewarden-controller@${{ needs.container-build.outputs.digest }}" \ - . > kubewarden-controller-sbom.spdx - - - name: Sign BOM file - run: | - cosign sign-blob --yes --output-certificate kubewarden-controller-sbom.spdx.cert \ - --output-signature kubewarden-controller-sbom.spdx.sig \ - kubewarden-controller-sbom.spdx - env: - COSIGN_EXPERIMENTAL: 1 - - name: Get latest release tag id: get_last_release_tag uses: actions/github-script@v6 @@ -100,13 +94,33 @@ jobs: } core.setFailed(`Draft release not found`) + - name: Download SBOM artifact + uses: actions/download-artifact@v3 + with: + name: sbom + + - name: Download CRDs artifact + uses: actions/download-artifact@v3 + with: + name: CRDS + + - name: Display structure of downloaded files + run: ls -R + - name: Upload release assets id: upload_release_assets uses: actions/github-script@v6 with: script: | let fs = require('fs'); - let files = ['kubewarden-controller-sbom.spdx', 'kubewarden-controller-sbom.spdx.cert', 'kubewarden-controller-sbom.spdx.sig', "CRDS.tar.gz"] + let files = [ + 'kubewarden-controller-sbom-amd64.spdx', + 'kubewarden-controller-sbom-amd64.spdx.cert', + 'kubewarden-controller-sbom-amd64.spdx.sig', + 'kubewarden-controller-sbom-arm64.spdx', + 'kubewarden-controller-sbom-arm64.spdx.cert', + 'kubewarden-controller-sbom-arm64.spdx.sig', + "CRDS.tar.gz"] const {RELEASE_ID} = process.env for (const file of files) { diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml new file mode 100644 index 00000000..7e903484 --- /dev/null +++ b/.github/workflows/sbom.yml @@ -0,0 +1,77 @@ +name: Build container image + +on: + workflow_call: + inputs: + image-digest: + type: string + required: true + +jobs: + sbom: + name: Build SBOM, sign and attach them to OCI image + strategy: + matrix: + arch: [amd64, arm64] + + permissions: + packages: write + id-token: write + + runs-on: ubuntu-latest + steps: + - name: Install cosign + uses: sigstore/cosign-installer@v3 + + - name: Install the syft command + #TODO: change origin + uses: flavio/github-actions/syft-installer@main + + - name: Install the crane command + #TODO: change origin + uses: flavio/github-actions/crane-installer@main + + - name: Login to GitHub Container Registry + uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.repository_owner }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Find platform digest + shell: bash + run: | + set -e + DIGEST=$(crane digest \ + --platform "linux/${{ matrix.arch }}" \ + ghcr.io/${{ github.repository_owner }}/kubewarden-controller@${{ inputs.image-digest }}) + echo "PLATFORM_DIGEST=${DIGEST}" >> "$GITHUB_ENV" + + - name: Create SBOM file + shell: bash + run: | + syft \ + -o spdx-json \ + --file kubewarden-controller-sbom-${{ matrix.arch }}.spdx \ + ghcr.io/${{ github.repository_owner }}/kubewarden-controller@${{ env.PLATFORM_DIGEST }} + + - name: Sign BOM file + run: | + cosign sign-blob --yes \ + --output-certificate kubewarden-controller-sbom-${{ matrix.arch }}.spdx.cert \ + --output-signature kubewarden-controller-sbom-${{ matrix.arch }}.spdx.sig \ + kubewarden-controller-sbom-${{ matrix.arch }}.spdx + + - name: Attach SBOM file in the container image + shell: bash + run: | + cosign attach \ + sbom --sbom kubewarden-controller-sbom-${{ matrix.arch }}.spdx \ + ghcr.io/${{ github.repository_owner }}/kubewarden-controller@${{ env.PLATFORM_DIGEST }} + + - + name: Upload SBOMs as artifacts + uses: actions/upload-artifact@v3 + with: + name: sbom + path: kubewarden-controller-sbom-* diff --git a/Dockerfile b/Dockerfile index 89a16612..8844e70b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,10 @@ RUN CGO_ENABLED=0 GOOS=linux GO111MODULE=on go build -a -o manager . FROM gcr.io/distroless/static:nonroot WORKDIR / COPY --from=builder /workspace/manager . +# Copy the Go Modules manifests - these are used by BOM generators +# and by security scanner +COPY go.mod /go.mod +COPY go.sum /go.sum USER 65532:65532 ENTRYPOINT ["/manager"] From 76a343beafb9b05b71a3880fac63e1c75332c185 Mon Sep 17 00:00:00 2001 From: Flavio Castelli Date: Tue, 25 Jul 2023 15:57:54 +0200 Subject: [PATCH 2/2] Feedback from PR review Signed-off-by: Flavio Castelli --- .github/workflows/container-build.yml | 7 ++++--- .github/workflows/container-image.yml | 11 +++++++++++ .github/workflows/release.yml | 2 +- .github/workflows/sbom.yml | 17 ++++++++++++----- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/.github/workflows/container-build.yml b/.github/workflows/container-build.yml index c63d6884..73043de3 100644 --- a/.github/workflows/container-build.yml +++ b/.github/workflows/container-build.yml @@ -1,4 +1,4 @@ -name: Build container image every change. +name: Build container image and SBOMs on: workflow_call: @@ -14,15 +14,16 @@ on: jobs: build: - name: Build + name: Build container image uses: ./.github/workflows/container-image.yml permissions: packages: write + id-token: write with: push-image: true sbom: - name: SBOM + name: Generate SBOM and push them to OCI registry needs: build uses: ./.github/workflows/sbom.yml permissions: diff --git a/.github/workflows/container-image.yml b/.github/workflows/container-image.yml index a4bfb37f..61ee4da2 100644 --- a/.github/workflows/container-image.yml +++ b/.github/workflows/container-image.yml @@ -25,6 +25,7 @@ jobs: name: Build container image permissions: packages: write + id-token: write runs-on: ubuntu-latest outputs: repository: ${{ steps.setoutput.outputs.repository }} @@ -48,6 +49,10 @@ jobs: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} + - + name: Install cosign + if: ${{ inputs.push-image }} + uses: sigstore/cosign-installer@v3 - name: Retrieve tag name (main branch) if: ${{ startsWith(github.ref, 'refs/heads/main') }} @@ -75,6 +80,12 @@ jobs: push: true tags: | ghcr.io/${{github.repository_owner}}/kubewarden-controller:${{ env.TAG_NAME }} + - + name: Sign container image + if: ${{ inputs.push-image }} + run: | + cosign sign --yes \ + ghcr.io/${{github.repository_owner}}/kubewarden-controller@${{ steps.build-image.outputs.digest }} - # Only build amd64 because buildx does not allow multiple platforms when # exporting the image to a tarball. As we use this only for end-to-end tests diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c875541e..fe147130 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,7 +13,7 @@ jobs: permissions: read-all build: - name: Build container + name: Build container image and SBOMs uses: ./.github/workflows/container-build.yml permissions: id-token: write diff --git a/.github/workflows/sbom.yml b/.github/workflows/sbom.yml index 7e903484..38543b8e 100644 --- a/.github/workflows/sbom.yml +++ b/.github/workflows/sbom.yml @@ -24,12 +24,10 @@ jobs: uses: sigstore/cosign-installer@v3 - name: Install the syft command - #TODO: change origin - uses: flavio/github-actions/syft-installer@main + uses: kubewarden/github-actions/syft-installer@v3.1.5 - name: Install the crane command - #TODO: change origin - uses: flavio/github-actions/crane-installer@main + uses: kubewarden/github-actions/crane-installer@v3.1.5 - name: Login to GitHub Container Registry uses: docker/login-action@v2 @@ -55,7 +53,7 @@ jobs: --file kubewarden-controller-sbom-${{ matrix.arch }}.spdx \ ghcr.io/${{ github.repository_owner }}/kubewarden-controller@${{ env.PLATFORM_DIGEST }} - - name: Sign BOM file + - name: Sign SBOM file run: | cosign sign-blob --yes \ --output-certificate kubewarden-controller-sbom-${{ matrix.arch }}.spdx.cert \ @@ -69,6 +67,15 @@ jobs: sbom --sbom kubewarden-controller-sbom-${{ matrix.arch }}.spdx \ ghcr.io/${{ github.repository_owner }}/kubewarden-controller@${{ env.PLATFORM_DIGEST }} + - name: Sign SBOM file pushed to OCI registry + shell: bash + run: | + set -e + SBOM_TAG="$(echo ${{ env.PLATFORM_DIGEST }} | sed -e 's/:/-/g').sbom" + + cosign sign --yes \ + ghcr.io/${{github.repository_owner}}/kubewarden-controller:${SBOM_TAG} + - name: Upload SBOMs as artifacts uses: actions/upload-artifact@v3