|
| 1 | +#!/bin/bash |
| 2 | +set -uo pipefail # prevent accessing unset env vars, prevent masking pipeline errors to the next command |
| 3 | + |
| 4 | +#docs |
| 5 | +#title :verify_provenance.sh |
| 6 | +#description :This script will download and verify a signed Powertools for AWS Lambda (Python) release build with SLSA Verifier |
| 7 | +#author :@heitorlessa |
| 8 | +#date :July 1st 2023 |
| 9 | +#version :0.1 |
| 10 | +#usage :bash verify_provenance.sh {release version} |
| 11 | +#notes :Meant to use in GitHub Actions or locally (MacOS, Linux, WSL). |
| 12 | +#os_version :Ubuntu 22.04.2 LTS |
| 13 | +#============================================================================== |
| 14 | + |
| 15 | +# Check if RELEASE_VERSION is provided as a command line argument |
| 16 | +if [[ $# -eq 1 ]]; then |
| 17 | + export readonly RELEASE_VERSION="$1" |
| 18 | +else |
| 19 | + echo "ERROR: Please provider Powertools release version as a command line argument." |
| 20 | + echo "Example: bash verify_provenance.sh 2.20.0" |
| 21 | + exit 1 |
| 22 | +fi |
| 23 | + |
| 24 | +export readonly ARCHITECTURE=$(uname -m | sed 's/x86_64/amd64/g') # arm64, x86_64 ->amd64 |
| 25 | +export readonly OS_NAME=$(uname -s | tr '[:upper:]' '[:lower:]') # darwin, linux |
| 26 | +export readonly SLSA_VERIFIER_VERSION="2.3.0" |
| 27 | +export readonly SLSA_VERIFIER_CHECKSUM_FILE="SHA256SUM.md" |
| 28 | +export readonly SLSA_VERIFIER_BINARY="./slsa-verifier-${OS_NAME}-${ARCHITECTURE}" |
| 29 | + |
| 30 | +export readonly RELEASE_BINARY="aws_lambda_powertools-${RELEASE_VERSION}-py3-none-any.whl" |
| 31 | +export readonly ORG="aws-powertools" |
| 32 | +export readonly REPO="powertools-lambda-python" |
| 33 | +export readonly PROVENANCE_FILE="multiple.intoto.jsonl" |
| 34 | + |
| 35 | +export readonly FILES=("${SLSA_VERIFIER_BINARY}" "${SLSA_VERIFIER_CHECKSUM_FILE}" "${PROVENANCE_FILE}" "${RELEASE_BINARY}") |
| 36 | + |
| 37 | +function debug() { |
| 38 | + TIMESTAMP=$(date -u "+%FT%TZ") # 2023-05-10T07:53:59Z |
| 39 | + echo ""${TIMESTAMP}" DEBUG - $1" |
| 40 | +} |
| 41 | + |
| 42 | +function download_slsa_verifier() { |
| 43 | + debug "[*] Downloading SLSA Verifier for - Binary: slsa-verifier-${OS_NAME}-${ARCHITECTURE}" |
| 44 | + curl --location --silent -O "https://github.com/slsa-framework/slsa-verifier/releases/download/v${SLSA_VERIFIER_VERSION}/slsa-verifier-${OS_NAME}-${ARCHITECTURE}" |
| 45 | + |
| 46 | + debug "[*] Downloading SLSA Verifier checksums" |
| 47 | + curl --location --silent -O "https://raw.githubusercontent.com/slsa-framework/slsa-verifier/f59b55ef2190581d40fc1a5f3b7a51cab2f4a652/${SLSA_VERIFIER_CHECKSUM_FILE}" |
| 48 | + |
| 49 | + debug "[*] Verifying SLSA Verifier binary integrity" |
| 50 | + CURRENT_HASH=$(sha256sum "${SLSA_VERIFIER_BINARY}" | awk '{print $1}') |
| 51 | + if [[ $(grep "${CURRENT_HASH}" "${SLSA_VERIFIER_CHECKSUM_FILE}") ]]; then |
| 52 | + debug "[*] SLSA Verifier binary integrity confirmed" |
| 53 | + chmod +x "${SLSA_VERIFIER_BINARY}" |
| 54 | + else |
| 55 | + debug "[!] Failed integrity check for SLSA Verifier binary: ${SLSA_VERIFIER_BINARY}" |
| 56 | + exit 1 |
| 57 | + fi |
| 58 | +} |
| 59 | + |
| 60 | +function download_provenance() { |
| 61 | + debug "[*] Downloading attestation for - Release: https://github.com/${ORG}/${REPO}/releases/v${RELEASE_VERSION}" |
| 62 | + |
| 63 | + curl --location --silent -O "https://github.com/${ORG}/${REPO}/releases/download/v${RELEASE_VERSION}/${PROVENANCE_FILE}" |
| 64 | +} |
| 65 | + |
| 66 | +function download_release_artifact() { |
| 67 | + debug "[*] Downloading ${RELEASE_VERSION} release from PyPi" |
| 68 | + python -m pip download \ |
| 69 | + --only-binary=:all: \ |
| 70 | + --no-deps \ |
| 71 | + --quiet \ |
| 72 | + aws-lambda-powertools=="${RELEASE_VERSION}" |
| 73 | +} |
| 74 | + |
| 75 | +function verify_provenance() { |
| 76 | + debug "[*] Verifying attestation with slsa-verifier" |
| 77 | + "${SLSA_VERIFIER_BINARY}" verify-artifact \ |
| 78 | + --provenance-path "${PROVENANCE_FILE}" \ |
| 79 | + --source-uri github.com/${ORG}/${REPO} \ |
| 80 | + ${RELEASE_BINARY} |
| 81 | +} |
| 82 | + |
| 83 | +function cleanup() { |
| 84 | + debug "[*] Cleaning up previously downloaded files" |
| 85 | + rm "${SLSA_VERIFIER_BINARY}" |
| 86 | + rm "${SLSA_VERIFIER_CHECKSUM_FILE}" |
| 87 | + rm "${PROVENANCE_FILE}" |
| 88 | + rm "${RELEASE_BINARY}" |
| 89 | + echo "${FILES[@]}" | xargs -n1 echo "Removed file: " |
| 90 | +} |
| 91 | + |
| 92 | +function main() { |
| 93 | + download_slsa_verifier |
| 94 | + download_provenance |
| 95 | + download_release_artifact |
| 96 | + verify_provenance |
| 97 | + cleanup |
| 98 | +} |
| 99 | + |
| 100 | +main |
| 101 | + |
| 102 | +# Lessons learned |
| 103 | +# |
| 104 | +# 1. If source doesn't match provenance |
| 105 | +# |
| 106 | +# FAILED: SLSA verification failed: source used to generate the binary does not match provenance: expected source 'awslabs/aws-lambda-powertools-python', got 'heitorlessa/aws-lambda-powertools-test' |
| 107 | +# |
| 108 | +# 2. Avoid building deps during download in Test registry endpoints |
| 109 | +# |
| 110 | +# FAILED: Could not find a version that satisfies the requirement poetry-core>=1.3.2 (from versions: 1.2.0) |
| 111 | +# |
0 commit comments