name: Constellation measure description: | Create measurements of a Constellation cluster and print to stdout. Optionally sign and/or upload to S3, if corresponding inputs are provided. inputs: cloudProvider: description: "Either 'gcp' or 'azure'." required: true cosignPublicKey: description: 'Cosign public key' required: false default: '' cosignPrivateKey: description: 'Cosign private key' required: false default: '' cosignPassword: description: 'Password for Cosign private key' required: false default: '' awsAccessKeyID: description: 'AWS access key ID to upload measurements' required: false default: '' awsSecretAccessKey: description: 'AWS secret access key to upload measurements' required: false default: '' awsDefaultRegion: description: 'AWS region of S3 bucket to upload measurements' required: false default: '' awsBucketName: description: 'S3 bucket name to upload measurements to' required: false default: '' runs: using: 'composite' steps: # Check /docs/secure_software_distribution.md#sign-measurements # for why we ignore certain measurement values. - name: Fetch PCRs run: | case $CSP in azure) FIRST_NODE=$(jq -r ".azurecontrolplanes | keys | first" constellation-state.json) CONSTELL_IP=$(jq -r ".azurecontrolplanes.\"${FIRST_NODE}\".PublicIP" constellation-state.json) pcr-reader --constell-ip ${CONSTELL_IP} -format yaml > measurements.yaml yq e 'del(.[0,6,10,11,12,13,14,15,16,17,18,19,20,21,22,23])' -i measurements.yaml ;; gcp) FIRST_NODE=$(jq -r ".gcpcontrolplanes | keys | first" constellation-state.json) CONSTELL_IP=$(jq -r ".gcpcontrolplanes.\"${FIRST_NODE}\".PublicIP" constellation-state.json) pcr-reader --constell-ip ${CONSTELL_IP} -format yaml > measurements.yaml yq e 'del(.[11,12,13,14,15,16,17,18,19,20,21,22,23])' -i measurements.yaml ;; esac cat measurements.yaml shell: bash env: CSP: ${{ inputs.cloudProvider }} # TODO: Replace with https://github.com/sigstore/sigstore-installer/tree/initial # once it has the functionality - name: Install Cosign uses: sigstore/cosign-installer@main if: ${{ inputs.cosignPublicKey != '' && inputs.cosignPrivateKey != '' && inputs.cosignPassword != '' }} - name: Install Rekor run: | curl -LO https://github.com/sigstore/rekor/releases/download/v0.9.0/rekor-cli-linux-amd64 sudo install rekor-cli-linux-amd64 /usr/local/bin/rekor-cli shell: bash if: ${{ inputs.cosignPublicKey != '' && inputs.cosignPrivateKey != '' && inputs.cosignPassword != '' }} - name: Sign measurements run: | set -e set -o pipefail echo "$COSIGN_PUBLIC_KEY" > cosign.pub # Enabling experimental mode also publishes signature to Rekor COSIGN_EXPERIMENTAL=1 cosign sign-blob --key env://COSIGN_PRIVATE_KEY measurements.yaml > measurements.yaml.sig # Verify - As documentation & check # Local Signature (input: artifact, key, signature) cosign verify-blob --key cosign.pub --signature measurements.yaml.sig measurements.yaml # Transparency Log Signature (input: artifact, key) uuid=$(rekor-cli search --artifact measurements.yaml | tail -n 1) sig=$(rekor-cli get --uuid=$uuid --format=json | jq -r .Body.HashedRekordObj.signature.content) cosign verify-blob --key cosign.pub --signature <(echo $sig) measurements.yaml shell: bash env: COSIGN_PUBLIC_KEY: ${{ inputs.cosignPublicKey }} COSIGN_PRIVATE_KEY: ${{ inputs.cosignPrivateKey }} COSIGN_PASSWORD: ${{ inputs.cosignPassword }} if: ${{ inputs.cosignPublicKey != '' && inputs.cosignPrivateKey != '' && inputs.cosignPassword != '' }} - name: Install AWS CLI run: sudo apt-get update && sudo apt-get -y install awscli shell: bash if: ${{ inputs.awsAccessKeyID != '' && inputs.awsSecretAccessKey != '' && inputs.awsDefaultRegion != '' && inputs.awsBucketName != '' }} - name: Upload to S3 run: | IMAGE=$(yq e ".provider.${CSP}.image" constellation-conf.yaml) S3_PATH=s3://${PUBLIC_BUCKET_NAME}/${IMAGE} aws s3 cp measurements.yaml ${S3_PATH}/measurements.yaml if test -f measurements.yaml.sig; then aws s3 cp measurements.yaml.sig ${S3_PATH}/measurements.yaml.sig fi shell: bash env: AWS_ACCESS_KEY_ID: ${{ inputs.awsAccessKeyID }} AWS_SECRET_ACCESS_KEY: ${{ inputs.awsSecretAccessKey }} AWS_DEFAULT_REGION: ${{ inputs.awsDefaultRegion }} PUBLIC_BUCKET_NAME: ${{ inputs.awsBucketName }} CSP: ${{ inputs.cloudProvider }} if: ${{ inputs.awsAccessKeyID != '' && inputs.awsSecretAccessKey != '' && inputs.awsDefaultRegion != '' && inputs.awsBucketName != '' }}