From 674ce71ab913364cae7077beeea699d4d7a56c20 Mon Sep 17 00:00:00 2001 From: Roberto Tyley Date: Thu, 25 Apr 2024 11:41:15 +0100 Subject: [PATCH] Verify artifact hashes before signing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In `gha-scala-library-release-workflow`, artifacts are created in one GitHub Job (`🎊 Create artifacts`), and then _signed_ in another (`🔒 Sign`) - the artifacts are transmitted between Jobs by using GitHub's cache infrastructure (https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows), as there are many megabytes of artifact data to transfer, more than the 1 MB `$GITHUB_OUTPUT` string (https://docs.github.com/en/actions/using-jobs/defining-outputs-for-jobs) supported by GitHub Jobs could necessarily handle. `$GITHUB_OUTPUT` has the advantage that it's scoped to a single workflow run, whereas the cache infrastructure is shared between all workflows in the repository - making it more vulnerable to tampering. In principle, an attack could exist where another GitHub workflow in the same repo could generate an identical cache key, replacing the genuine artifacts with malicious ones, which would then be signed by the `🔒 Sign` Job. Adding artifact hash verification --------------------------------- We've already been recording artifact SHA256 hashes in `🎊 Create artifacts`, and later storing them in the annotated git tag associated with the release: https://github.com/guardian/gha-scala-library-release-workflow/blob/cc53a31fdc6d856940def18ddab4d1ab4d36848e/.github/workflows/reusable-release.yml#L268-L273 ...but we haven't been _verifying_ those SHA256 hashes when coming into the `🔒 Sign` phase, when the generated artifacts are loaded out of cached storage. This commit adds that additional security check. --- .github/workflows/reusable-release.yml | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/.github/workflows/reusable-release.yml b/.github/workflows/reusable-release.yml index 96286e3..f3a7386 100644 --- a/.github/workflows/reusable-release.yml +++ b/.github/workflows/reusable-release.yml @@ -284,6 +284,7 @@ jobs: runs-on: ubuntu-latest env: KEY_FINGERPRINT: ${{ needs.init.outputs.key_fingerprint }} + ARTIFACT_SHA256SUMS: ${{ needs.create-artifacts.outputs.ARTIFACT_SHA256SUMS }} steps: - id: generate-github-app-token uses: actions/create-github-app-token@v1 @@ -302,6 +303,19 @@ jobs: path: ${{ env.LOCAL_ARTIFACTS_STAGING_PATH }} key: unsigned-${{ env.RUN_ATTEMPT_UID }} fail-on-cache-miss: true + - name: Verify artifact hashes before signing + run: | + sudo apt-get install hashdeep -q > /dev/null + ARTIFACT_SHA256SUMS_FILE=$( mktemp ) + printf "$ARTIFACT_SHA256SUMS" > $ARTIFACT_SHA256SUMS_FILE + + cd $LOCAL_ARTIFACTS_STAGING_PATH + echo "Checking artifact hashes..." + if [[ $(sha256deep -r -l -X "$ARTIFACT_SHA256SUMS_FILE" .) ]] + then + echo "::error title=Artifact hash verification failed::Artifacts for signing don't match the hash values recorded when they were generated." + exit 1 + fi - uses: actions/setup-java@v4 with: distribution: corretto @@ -315,10 +329,9 @@ jobs: env: RELEASE_TAG: ${{ needs.push-release-commit.outputs.release_tag }} RELEASE_COMMIT_ID: ${{ needs.push-release-commit.outputs.release_commit_id }} - ARTIFACT_SHA256SUMS: ${{ needs.create-artifacts.outputs.ARTIFACT_SHA256SUMS }} KEY_EMAIL: ${{ needs.init.outputs.key_email }} run: | - cd repo + cd $GITHUB_WORKSPACE/repo git config user.email "$KEY_EMAIL" git config user.name "$COMMITTER_NAME" git config tag.gpgSign true