From ece82f3b119b64b71b47b372297367ca2ca51004 Mon Sep 17 00:00:00 2001 From: Otto Bittner Date: Tue, 14 Nov 2023 13:25:52 +0100 Subject: [PATCH] ci: call TCB upload step for AWS --- .../actions/constellation_destroy/action.yml | 30 ++++++++++ .../e2e_attestationconfigapi/action.yml | 5 +- .github/actions/e2e_verify/action.yml | 15 +++-- .../workflows/e2e-attestationconfigapi.yml | 6 ++ .github/workflows/e2e-test-daily.yml | 3 + .github/workflows/e2e-test-release.yml | 3 + .github/workflows/e2e-test-weekly.yml | 3 + .github/workflows/e2e-test.yml | 5 +- .github/workflows/e2e-upgrade.yml | 3 + .../attestationconfigapi/cli/e2e/test.sh.in | 59 ++++++++++++------- 10 files changed, 104 insertions(+), 28 deletions(-) diff --git a/.github/actions/constellation_destroy/action.yml b/.github/actions/constellation_destroy/action.yml index ac4892fc83..1cd89d0f6d 100644 --- a/.github/actions/constellation_destroy/action.yml +++ b/.github/actions/constellation_destroy/action.yml @@ -8,6 +8,15 @@ inputs: selfManagedInfra: description: "Use self-managed infrastructure instead of infrastructure created by the Constellation CLI." required: true + gcpClusterDeleteServiceAccount: + description: "Service account with permissions to delete a Constellation cluster on GCP." + required: true + azureClusterDeleteCredentials: + description: "Azure credentials authorized to delete a Constellation cluster." + required: true + cloudProvider: + description: "Either 'aws', 'azure' or 'gcp'." + required: true runs: using: "composite" @@ -41,6 +50,27 @@ runs: fi echo "::endgroup::" + - name: Login to GCP (Cluster service account) + if: inputs.cloudProvider == 'gcp' + uses: ./.github/actions/login_gcp + with: + service_account: ${{ inputs.gcpClusterDeleteServiceAccount }} + + - name: Login to AWS (Cluster role) + if: inputs.cloudProvider == 'aws' + uses: aws-actions/configure-aws-credentials@010d0da01d0b5a38af31e9c3470dbfdabdecca3a # v4.0.1 + with: + role-to-assume: arn:aws:iam::795746500882:role/GithubActionsE2ECluster + aws-region: eu-central-1 + # extend token expiry to 6 hours to ensure constellation can terminate + role-duration-seconds: 21600 + + - name: Login to Azure (Cluster service principal) + if: inputs.cloudProvider == 'azure' + uses: ./.github/actions/login_azure + with: + azure_credentials: ${{ inputs.azureClusterDeleteCredentials }} + - name: Constellation terminate if: inputs.selfManagedInfra != 'true' shell: bash diff --git a/.github/actions/e2e_attestationconfigapi/action.yml b/.github/actions/e2e_attestationconfigapi/action.yml index 955adf4bfb..add2894768 100644 --- a/.github/actions/e2e_attestationconfigapi/action.yml +++ b/.github/actions/e2e_attestationconfigapi/action.yml @@ -2,6 +2,9 @@ name: E2E Attestationconfig API Test description: "Test the attestationconfig CLI is functional." inputs: + csp: + description: "Cloud provider to run tests against" + default: "azure" buildBuddyApiKey: description: "BuildBuddy API key for caching Bazel artifacts" required: true @@ -33,4 +36,4 @@ runs: COSIGN_PRIVATE_KEY: ${{ inputs.cosignPrivateKey }} COSIGN_PASSWORD: ${{ inputs.cosignPassword }} run: | - bazel run //internal/api/attestationconfigapi/cli:cli_e2e_test + bazel run //internal/api/attestationconfigapi/cli:cli_e2e_test -- ${{ inputs.csp }} diff --git a/.github/actions/e2e_verify/action.yml b/.github/actions/e2e_verify/action.yml index c18938becb..b9b17a10de 100644 --- a/.github/actions/e2e_verify/action.yml +++ b/.github/actions/e2e_verify/action.yml @@ -66,8 +66,8 @@ runs: forwarderPID=$! sleep 5 - if [[ ${{ inputs.cloudProvider }} == "azure" ]]; then - echo "Extracting Azure TCB versions for API update" + if [[ ${{ inputs.cloudProvider }} == "azure" || ${{ inputs.cloudProvider }} == "aws" ]]; then + echo "Extracting TCB versions for API update" constellation verify --cluster-id "${clusterID}" --node-endpoint localhost:9090 -o json > "snp-report-${node}.json" else constellation verify --cluster-id "${clusterID}" --node-endpoint localhost:9090 @@ -84,14 +84,19 @@ runs: aws-region: eu-central-1 - name: Upload extracted TCBs - if: github.ref_name == 'main' && inputs.cloudProvider == 'azure' + if: github.ref_name == 'main' && (inputs.cloudProvider == 'azure' || inputs.cloudProvider == 'aws') shell: bash env: COSIGN_PASSWORD: ${{ inputs.cosignPassword }} COSIGN_PRIVATE_KEY: ${{ inputs.cosignPrivateKey }} run: | - for file in $(ls snp-report-*.json); do + reports=(snp-report-*.json) + if [ -z ${#reports[@]} ]; then + exit 1 + fi + + for file in "${reports[@]}"; do path=$(realpath "${file}") cat "${path}" - bazel run //internal/api/attestationconfigapi/cli -- upload azure snp-report "${path}" + bazel run //internal/api/attestationconfigapi/cli -- upload ${{ inputs.cloudProvider }} snp-report "${path}" done diff --git a/.github/workflows/e2e-attestationconfigapi.yml b/.github/workflows/e2e-attestationconfigapi.yml index ee2582bebf..7fcca9028b 100644 --- a/.github/workflows/e2e-attestationconfigapi.yml +++ b/.github/workflows/e2e-attestationconfigapi.yml @@ -16,6 +16,11 @@ on: jobs: e2e-api: + strategy: + fail-fast: false + max-parallel: 1 + matrix: + csp: ["azure", "aws"] runs-on: ubuntu-22.04 permissions: id-token: write @@ -35,3 +40,4 @@ jobs: buildBuddyApiKey: ${{ secrets.BUILDBUDDY_ORG_API_KEY }} cosignPrivateKey: ${{ secrets.COSIGN_DEV_PRIVATE_KEY }} cosignPassword: ${{ secrets.COSIGN_DEV_PASSWORD }} + csp: ${{ matrix.csp }} diff --git a/.github/workflows/e2e-test-daily.yml b/.github/workflows/e2e-test-daily.yml index a9f77c31fd..47ad5a605b 100644 --- a/.github/workflows/e2e-test-daily.yml +++ b/.github/workflows/e2e-test-daily.yml @@ -99,6 +99,9 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} selfManagedInfra: "false" + cloudProvider: ${{ matrix.provider }} + azureClusterDeleteCredentials: ${{ secrets.AZURE_E2E_CLUSTER_CREDENTIALS }} + gcpClusterDeleteServiceAccount: "constellation-e2e-cluster@constellation-331613.iam.gserviceaccount.com" - name: Always delete IAM configuration if: always() diff --git a/.github/workflows/e2e-test-release.yml b/.github/workflows/e2e-test-release.yml index 681a340d2b..2a9989d211 100644 --- a/.github/workflows/e2e-test-release.yml +++ b/.github/workflows/e2e-test-release.yml @@ -248,6 +248,9 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} selfManagedInfra: ${{ matrix.selfManagedInfra == 'true' }} + cloudProvider: ${{ matrix.provider }} + azureClusterDeleteCredentials: ${{ secrets.AZURE_E2E_CLUSTER_CREDENTIALS }} + gcpClusterDeleteServiceAccount: "constellation-e2e-cluster@constellation-331613.iam.gserviceaccount.com" - name: Always delete IAM configuration if: always() diff --git a/.github/workflows/e2e-test-weekly.yml b/.github/workflows/e2e-test-weekly.yml index 02661cfc42..9fda7d3db2 100644 --- a/.github/workflows/e2e-test-weekly.yml +++ b/.github/workflows/e2e-test-weekly.yml @@ -267,6 +267,9 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} selfManagedInfra: ${{ matrix.selfManagedInfra == 'true' }} + cloudProvider: ${{ matrix.provider }} + azureClusterDeleteCredentials: ${{ secrets.AZURE_E2E_CLUSTER_CREDENTIALS }} + gcpClusterDeleteServiceAccount: "constellation-e2e-cluster@constellation-331613.iam.gserviceaccount.com" - name: Always delete IAM configuration if: always() diff --git a/.github/workflows/e2e-test.yml b/.github/workflows/e2e-test.yml index 99dda6b18d..1d0b41f733 100644 --- a/.github/workflows/e2e-test.yml +++ b/.github/workflows/e2e-test.yml @@ -165,7 +165,7 @@ jobs: uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 with: ref: ${{ inputs.git-ref }} - + - name: Get Latest Image id: find-latest-image uses: ./.github/actions/find_latest_image @@ -246,6 +246,9 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} selfManagedInfra: ${{ inputs.selfManagedInfra }} + cloudProvider: ${{ inputs.cloudProvider }} + azureClusterDeleteCredentials: ${{ secrets.AZURE_E2E_CLUSTER_CREDENTIALS }} + gcpClusterDeleteServiceAccount: "constellation-e2e-cluster@constellation-331613.iam.gserviceaccount.com" - name: Always delete IAM configuration if: always() diff --git a/.github/workflows/e2e-upgrade.yml b/.github/workflows/e2e-upgrade.yml index 70d10f9d81..79256fea55 100644 --- a/.github/workflows/e2e-upgrade.yml +++ b/.github/workflows/e2e-upgrade.yml @@ -290,6 +290,9 @@ jobs: with: kubeconfig: ${{ steps.e2e_test.outputs.kubeconfig }} selfManagedInfra: "false" + cloudProvider: ${{ inputs.cloudProvider }} + azureClusterDeleteCredentials: ${{ secrets.AZURE_E2E_CLUSTER_CREDENTIALS }} + gcpClusterDeleteServiceAccount: "constellation-e2e-cluster@constellation-331613.iam.gserviceaccount.com" - name: Always delete IAM configuration if: always() diff --git a/internal/api/attestationconfigapi/cli/e2e/test.sh.in b/internal/api/attestationconfigapi/cli/e2e/test.sh.in index baf4fc4699..773443df45 100755 --- a/internal/api/attestationconfigapi/cli/e2e/test.sh.in +++ b/internal/api/attestationconfigapi/cli/e2e/test.sh.in @@ -19,6 +19,22 @@ configapi_cli=$(realpath @@CONFIGAPI_CLI@@) stat "${configapi_cli}" >> /dev/null configapi_cli="${configapi_cli} --testing" ###### script body ###### +function variant() { + if [[ $1 == "aws" ]]; then + echo "aws-sev-snp" + return 0 + elif [[ $1 == "azure" ]]; then + echo "azure-sev-snp" + return 0 + else + echo "Unknown CSP: $1" + exit 1 + fi +} + +csp=$1 +readonly csp +attestationType=$(variant "$csp") readonly region="eu-west-1" readonly bucket="resource-api-testing" @@ -28,7 +44,7 @@ readonly tmpdir registerExitHandler "rm -rf $tmpdir" # empty the bucket version state -${configapi_cli} delete recursive azure --region "$region" --bucket "$bucket" +${configapi_cli} delete recursive "$csp" --region "$region" --bucket "$bucket" # the high version numbers ensure that it's newer than the current latest value readonly current_report_path="$tmpdir/currentSnpReport.json" @@ -57,7 +73,7 @@ cat << EOF > "$current_report_path" } EOF # upload a fake latest version for the fetcher -${configapi_cli} upload azure snp-report "$current_report_path" --force --upload-date "2000-01-01-01-01" --region "$region" --bucket "$bucket" +${configapi_cli} upload "$csp" snp-report "$current_report_path" --force --upload-date "2000-01-01-01-01" --region "$region" --bucket "$bucket" # the high version numbers ensure that it's newer than the current latest value readonly report_path="$tmpdir/snpReport.json" @@ -115,16 +131,17 @@ EOF # report 3 versions with different dates to fill the reporter cache readonly date_oldest="2023-02-01-03-04" -${configapi_cli} upload azure snp-report "$older_report_path" --upload-date "$date_oldest" --region "$region" --bucket "$bucket" --cache-window-size 3 +${configapi_cli} upload "$csp" snp-report "$older_report_path" --upload-date "$date_oldest" --region "$region" --bucket "$bucket" --cache-window-size 3 readonly date_older="2023-02-02-03-04" -${configapi_cli} upload azure snp-report "$older_report_path" --upload-date "$date_older" --region "$region" --bucket "$bucket" --cache-window-size 3 +${configapi_cli} upload "$csp" snp-report "$older_report_path" --upload-date "$date_older" --region "$region" --bucket "$bucket" --cache-window-size 3 readonly date="2023-02-03-03-04" -${configapi_cli} upload azure snp-report "$report_path" --upload-date "$date" --region "$region" --bucket "$bucket" --cache-window-size 3 +${configapi_cli} upload "$csp" snp-report "$report_path" --upload-date "$date" --region "$region" --bucket "$bucket" --cache-window-size 3 # expect that $date_oldest is served as latest version -baseurl="https://d33dzgxuwsgbpw.cloudfront.net/constellation/v1/attestation/azure-sev-snp" -if ! curl -fsSL ${baseurl}/${date_oldest}.json > version.json; then - echo "Checking for uploaded version file constellation/v1/attestation/azure-sev-snp/${date_oldest}.json: request returned ${?}" +basepath="constellation/v1/attestation/${attestationType}" +baseurl="https://d33dzgxuwsgbpw.cloudfront.net/${basepath}" +if ! curl -fsSL "${baseurl}"/${date_oldest}.json > version.json; then + echo "Checking for uploaded version file ${basepath}/${date_oldest}.json: request returned ${?}" exit 1 fi # check that version values are equal to expected @@ -135,13 +152,13 @@ if ! cmp -s <(echo -n '{"bootloader":255,"tee":255,"snp":255,"microcode":254}') echo '{"bootloader":255,"tee":255,"snp":255,"microcode":254}' exit 1 fi -if ! curl -fsSL ${baseurl}/${date_oldest}.json.sig > /dev/null; then - echo "Checking for uploaded version signature file constellation/v1/attestation/azure-sev-snp/${date_oldest}.json.sig: request returned ${?}" +if ! curl -fsSL "${baseurl}"/${date_oldest}.json.sig > /dev/null; then + echo "Checking for uploaded version signature file ${basepath}/${date_oldest}.json.sig: request returned ${?}" exit 1 fi # check list endpoint -if ! curl -fsSL ${baseurl}/list > list.json; then - echo "Checking for uploaded list file constellation/v1/attestation/azure-sev-snp/list: request returned ${?}" +if ! curl -fsSL "${baseurl}"/list > list.json; then + echo "Checking for uploaded list file ${basepath}/list: request returned ${?}" exit 1 fi # check that version values are equal to expected @@ -154,28 +171,28 @@ if ! cmp -s <(echo -n '["2023-02-01-03-04.json","2000-01-01-01-01.json"]') list. fi # check that the other versions are not uploaded -http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date_older}.json) +http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null "${baseurl}"/${date_older}.json) if [[ $http_code -ne 404 ]]; then - echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date_older}.json, but got ${http_code}" + echo "Expected HTTP code 404 for: ${basepath}/${date_older}.json, but got ${http_code}" exit 1 fi -http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date}.json.sig) +http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null "${baseurl}"/${date}.json.sig) if [[ $http_code -ne 404 ]]; then - echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date}.json, but got ${http_code}" + echo "Expected HTTP code 404 for: ${basepath}/${date}.json, but got ${http_code}" exit 1 fi -${configapi_cli} delete azure snp-report "$date_oldest" --region "$region" --bucket "$bucket" +${configapi_cli} delete "$csp" snp-report "$date_oldest" --region "$region" --bucket "$bucket" # Omit -f to check for 404. We want to check that a file was deleted, therefore we expect the query to fail. -http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date_oldest}.json) +http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null "${baseurl}"/${date_oldest}.json) if [[ $http_code -ne 404 ]]; then - echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date_oldest}.json, but got ${http_code}" + echo "Expected HTTP code 404 for: ${basepath}/${date_oldest}.json, but got ${http_code}" exit 1 fi # Omit -f to check for 404. We want to check that a file was deleted, therefore we expect the query to fail. -http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null ${baseurl}/${date_oldest}.json.sig) +http_code=$(curl -sSL -w '%{http_code}\n' -o /dev/null "${baseurl}"/${date_oldest}.json.sig) if [[ $http_code -ne 404 ]]; then - echo "Expected HTTP code 404 for: constellation/v1/attestation/azure-sev-snp/${date_oldest}.json, but got ${http_code}" + echo "Expected HTTP code 404 for: ${basepath}/${date_oldest}.json, but got ${http_code}" exit 1 fi