Skip to content

Commit

Permalink
Enable attestationconfigapi CLI e2e test for azure-tdx
Browse files Browse the repository at this point in the history
Signed-off-by: Daniel Weiße <[email protected]>
  • Loading branch information
daniel-weisse committed Jun 13, 2024
1 parent 6fadbaf commit 427126b
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 193 deletions.
8 changes: 4 additions & 4 deletions .github/actions/e2e_attestationconfigapi/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +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"
attestationVariant:
description: "attestation variant to run tests against"
default: "azure-sev-snp"
cosignPrivateKey:
description: "Cosign private key"
required: true
Expand All @@ -30,4 +30,4 @@ runs:
COSIGN_PRIVATE_KEY: ${{ inputs.cosignPrivateKey }}
COSIGN_PASSWORD: ${{ inputs.cosignPassword }}
run: |
bazel run //internal/api/attestationconfigapi/cli:cli_e2e_test -- ${{ inputs.csp }}
bazel run //internal/api/attestationconfigapi/cli:cli_e2e_test -- ${{ inputs.attestationVariant }}
13 changes: 5 additions & 8 deletions .github/actions/e2e_verify/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ runs:
case "${{ inputs.attestationVariant }}"
in
"azure-sev-snp"|"aws-sev-snp"|"gcp-sev-snp")
"azure-sev-snp"|"azure-tdx"|"aws-sev-snp"|"gcp-sev-snp")
echo "Extracting TCB versions for API update"
constellation verify --cluster-id "${clusterID}" --node-endpoint localhost:9090 -o json > "snp-report-${node}.json"
constellation verify --cluster-id "${clusterID}" --node-endpoint localhost:9090 -o json > "attestation-report-${node}.json"
;;
*)
constellation verify --cluster-id "${clusterID}" --node-endpoint localhost:9090
Expand All @@ -88,22 +88,19 @@ runs:
aws-region: eu-central-1

- name: Upload extracted TCBs
if: github.ref_name == 'main' && (inputs.attestationVariant == 'azure-sev-snp' || inputs.attestationVariant == 'aws-sev-snp' || inputs.attestationVariant == 'gcp-sev-snp')
if: github.ref_name == 'main' && (inputs.attestationVariant == 'azure-sev-snp' || inputs.attestationVariant == 'azure-tdx' || inputs.attestationVariant == 'aws-sev-snp' || inputs.attestationVariant == 'gcp-sev-snp')
shell: bash
env:
COSIGN_PASSWORD: ${{ inputs.cosignPassword }}
COSIGN_PRIVATE_KEY: ${{ inputs.cosignPrivateKey }}
run: |
reports=(snp-report-*.json)
reports=(attestation-report-*.json)
if [ -z ${#reports[@]} ]; then
exit 1
fi
attestationVariant=${{ inputs.attestationVariant }}
cloudProvider=${attestationVariant%%-*}
for file in "${reports[@]}"; do
path=$(realpath "${file}")
cat "${path}"
bazel run //internal/api/attestationconfigapi/cli -- upload "${cloudProvider}" snp-report "${path}"
bazel run //internal/api/attestationconfigapi/cli -- upload {{ inputs.attestationVariant }} attestation-report "${path}"
done
4 changes: 2 additions & 2 deletions .github/workflows/e2e-attestationconfigapi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
fail-fast: false
max-parallel: 1
matrix:
csp: ["azure", "aws", "gcp"]
attestationVariant: ["azure-sev-snp", "azure-tdx", "aws-sev-snp", "gcp-sev-snp"]
runs-on: ubuntu-22.04
permissions:
id-token: write
Expand All @@ -36,4 +36,4 @@ jobs:
with:
cosignPrivateKey: ${{ secrets.COSIGN_DEV_PRIVATE_KEY }}
cosignPassword: ${{ secrets.COSIGN_DEV_PASSWORD }}
csp: ${{ matrix.csp }}
attestationVariant: ${{ matrix.attestationVariant }}
1 change: 0 additions & 1 deletion internal/api/attestationconfigapi/cli/client/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ go_test(
embed = [":client"],
deps = [
"//internal/api/attestationconfigapi",
"//internal/attestation/variant",
"@com_github_stretchr_testify//assert",
],
)
24 changes: 0 additions & 24 deletions internal/api/attestationconfigapi/cli/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"log/slog"
"path"
"strings"
"time"

"github.com/aws/aws-sdk-go-v2/service/s3"
"github.com/aws/aws-sdk-go/aws"
Expand Down Expand Up @@ -108,29 +107,6 @@ func (c Client) deleteVersion(versions attestationconfigapi.VersionList, version
return ops, nil
}

func (c Client) constructUploadCmd(attestation variant.Variant, version attestationconfigapi.SEVSNPVersion, versionNames attestationconfigapi.VersionList, date time.Time) []crudCmd {
if !attestation.Equal(versionNames.Variant) {
return nil
}

dateStr := date.Format(VersionFormat) + ".json"
var res []crudCmd

res = append(res, putCmd{
apiObject: attestationconfigapi.VersionAPIEntry{Version: dateStr, Variant: attestation, SEVSNPVersion: version},
signer: c.signer,
})

versionNames.AddVersion(dateStr)

res = append(res, putCmd{
apiObject: versionNames,
signer: c.signer,
})

return res
}

func (c Client) listCachedVersions(ctx context.Context, attestation variant.Variant) ([]string, error) {
list, err := c.s3Client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
Bucket: aws.String(c.bucketID),
Expand Down
32 changes: 0 additions & 32 deletions internal/api/attestationconfigapi/cli/client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,37 +7,11 @@ package client

import (
"testing"
"time"

"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
"github.com/stretchr/testify/assert"
)

func TestUploadAzureSEVSNP(t *testing.T) {
sut := Client{
bucketID: "bucket",
signer: fakeSigner{},
}
version := attestationconfigapi.SEVSNPVersion{}
date := time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC)
ops := sut.constructUploadCmd(variant.AzureSEVSNP{}, version, attestationconfigapi.VersionList{List: []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, Variant: variant.AzureSEVSNP{}}, date)
dateStr := "2023-01-01-01-01.json"
assert := assert.New(t)
assert.Contains(ops, putCmd{
apiObject: attestationconfigapi.VersionAPIEntry{
Variant: variant.AzureSEVSNP{},
Version: dateStr,
SEVSNPVersion: version,
},
signer: fakeSigner{},
})
assert.Contains(ops, putCmd{
apiObject: attestationconfigapi.VersionList{Variant: variant.AzureSEVSNP{}, List: []string{"2023-01-01-01-01.json", "2021-01-01-01-01.json", "2019-01-01-01-01.json"}},
signer: fakeSigner{},
})
}

func TestDeleteAzureSEVSNPVersions(t *testing.T) {
sut := Client{
bucketID: "bucket",
Expand All @@ -58,9 +32,3 @@ func TestDeleteAzureSEVSNPVersions(t *testing.T) {
apiObject: attestationconfigapi.VersionList{List: []string{"2023-01-01.json", "2019-01-01.json"}},
})
}

type fakeSigner struct{}

func (fakeSigner) Sign(_ []byte) ([]byte, error) {
return []byte("signature"), nil
}
83 changes: 43 additions & 40 deletions internal/api/attestationconfigapi/cli/client/reportersnp.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ func (c Client) UploadSEVSNPVersionLatest(
}
c.s3Client.Logger.Info(fmt.Sprintf("Found minimal version: %+v with date: %s", minVersion, minDate))

if isInputNewerThanOtherVersion(minVersion, latestVersionInAPI) {
c.s3Client.Logger.Info(fmt.Sprintf("Input version: %+v is not newer than latest API version: %+v", minVersion, latestVersionInAPI))
if !isInputNewerThanOtherVersion(minVersion, latestVersionInAPI) {
c.s3Client.Logger.Info(fmt.Sprintf("Input version: %+v is not newer than latest API version: %+v. Skipping list update", minVersion, latestVersionInAPI))
return ErrNoNewerVersion
}

Expand All @@ -92,7 +92,24 @@ func (c Client) uploadSEVSNPVersion(ctx context.Context, attestation variant.Var
if err != nil {
return fmt.Errorf("fetch version list: %w", err)
}
ops := c.constructUploadCmd(attestation, version, versions, date)
if !attestation.Equal(versions.Variant) {
return nil
}

dateStr := date.Format(VersionFormat) + ".json"
var ops []crudCmd

ops = append(ops, putCmd{
apiObject: apiSEVSNPVersion{version: dateStr, variant: attestation, SEVSNPVersion: version, cached: false},
signer: c.signer,
})

versions.AddVersion(dateStr)

ops = append(ops, putCmd{
apiObject: versions,
signer: c.signer,
})

return executeAllCmds(ctx, c.s3Client, ops)
}
Expand All @@ -101,36 +118,43 @@ func (c Client) uploadSEVSNPVersion(ctx context.Context, attestation variant.Var
func (c Client) cacheSEVSNPVersion(ctx context.Context, variant variant.Variant, version attestationconfigapi.SEVSNPVersion, date time.Time) error {
dateStr := date.Format(VersionFormat) + ".json"
res := putCmd{
apiObject: cachedSEVSNPVersion{version: dateStr, variant: variant, SEVSNPVersion: version},
apiObject: apiSEVSNPVersion{version: dateStr, variant: variant, SEVSNPVersion: version, cached: true},
signer: c.signer,
}
return res.Execute(ctx, c.s3Client)
}

// findMinSEVSNPVersion finds the minimal version of the given version dates among the latest cached values in the version window size.
// findMinSEVSNPVersion finds the minimal version (the version with the lowest SVNs) of the given version dates among the latest cached values in the version window size.
func (c Client) findMinSEVSNPVersion(ctx context.Context, attestationVariant variant.Variant, versionDates []string) (attestationconfigapi.SEVSNPVersion, string, error) {
var minimalVersion attestationconfigapi.SEVSNPVersion
var minimalVersion *attestationconfigapi.SEVSNPVersion
var minimalDate string
sort.Sort(sort.Reverse(sort.StringSlice(versionDates))) // sort in reverse order to slice the latest versions
versionDates = versionDates[:c.cacheWindowSize]
sort.Strings(versionDates) // sort with oldest first to to take the minimal version with the oldest date

for _, date := range versionDates {
obj, err := client.Fetch(ctx, c.s3Client, cachedSEVSNPVersion{version: date + ".json", variant: attestationVariant})
obj, err := client.Fetch(ctx, c.s3Client, apiSEVSNPVersion{version: date + ".json", variant: attestationVariant, cached: true})
if err != nil {
return attestationconfigapi.SEVSNPVersion{}, "", fmt.Errorf("get object: %w", err)
}
// Need to set this explicitly as the variant is not part of the marshalled JSON.
obj.variant = attestationVariant

// If the version we fetched has higher SVNs than the current minimal version, update the minimal version.
if isInputNewerThanOtherVersion(obj.SEVSNPVersion, minimalVersion) {
minimalVersion = obj.SEVSNPVersion
if minimalVersion == nil {
minimalVersion = &obj.SEVSNPVersion
minimalDate = date
continue
}

// If the current minimal version has newer versions than the one we just fetched,
// update the minimal version to the older version.
if isInputNewerThanOtherVersion(*minimalVersion, obj.SEVSNPVersion) {
minimalVersion = &obj.SEVSNPVersion
minimalDate = date
}
}

return minimalVersion, minimalDate, nil
return *minimalVersion, minimalDate, nil
}

// isInputNewerThanOtherVersion compares all version fields and returns true if any input field is newer.
Expand All @@ -153,52 +177,31 @@ func isInputNewerThanOtherVersion(input, other attestationconfigapi.SEVSNPVersio
return true
}

type cachedSEVSNPVersion struct {
type apiSEVSNPVersion struct {
version string `json:"-"`
variant variant.Variant `json:"-"`
cached bool `json:"-"`
attestationconfigapi.SEVSNPVersion
}

// JSONPath returns the path to the JSON file for the request to the config api.
// This is the path to the cached version in the S3 bucket.
func (c cachedSEVSNPVersion) JSONPath() string {
return path.Join(reportVersionDir(c.variant), c.version)
}

// ValidateRequest validates the request.
func (c cachedSEVSNPVersion) ValidateRequest() error {
if !strings.HasSuffix(c.version, ".json") {
return fmt.Errorf("version has no .json suffix")
func (c apiSEVSNPVersion) JSONPath() string {
if c.cached {
return path.Join(reportVersionDir(c.variant), c.version)
}
return nil
}

// Validate is a No-Op at the moment.
func (c cachedSEVSNPVersion) Validate() error {
return nil
}

type cachedTDXVersion struct {
version string `json:"-"`
variant variant.Variant `json:"-"`
attestationconfigapi.TDXVersion
}

// JSONPath returns the path to the JSON file for the request to the config api.
// This is the path to the cached version in the S3 bucket.
func (c cachedTDXVersion) JSONPath() string {
return path.Join(reportVersionDir(c.variant), c.version)
return path.Join(attestationconfigapi.AttestationURLPath, c.variant.String(), c.version)
}

// ValidateRequest validates the request.
func (c cachedTDXVersion) ValidateRequest() error {
func (c apiSEVSNPVersion) ValidateRequest() error {
if !strings.HasSuffix(c.version, ".json") {
return fmt.Errorf("version has no .json suffix")
}
return nil
}

// Validate is a No-Op at the moment.
func (c cachedTDXVersion) Validate() error {
func (c apiSEVSNPVersion) Validate() error {
return nil
}
Loading

0 comments on commit 427126b

Please sign in to comment.