mirror of
https://github.com/edgelesssys/constellation.git
synced 2024-12-11 17:04:22 -05:00
Enable versions API to handle TDX versions
Signed-off-by: Daniel Weiße <dw@edgeless.systems>
This commit is contained in:
parent
fbddbc9867
commit
a34493caa6
@ -204,18 +204,8 @@ func (f stubVerifyFetcher) FetchAndVerifyMeasurements(_ context.Context, _ strin
|
||||
|
||||
type stubAttestationFetcher struct{}
|
||||
|
||||
func (f stubAttestationFetcher) FetchSEVSNPVersionList(_ context.Context, _ attestationconfigapi.SEVSNPVersionList) (attestationconfigapi.SEVSNPVersionList, error) {
|
||||
return attestationconfigapi.SEVSNPVersionList{}, nil
|
||||
}
|
||||
|
||||
func (f stubAttestationFetcher) FetchSEVSNPVersion(_ context.Context, _ attestationconfigapi.SEVSNPVersionAPI) (attestationconfigapi.SEVSNPVersionAPI, error) {
|
||||
return attestationconfigapi.SEVSNPVersionAPI{
|
||||
SEVSNPVersion: testCfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f stubAttestationFetcher) FetchLatestVersion(_ context.Context, _ variant.Variant) (attestationconfigapi.SEVSNPVersionAPI, error) {
|
||||
return attestationconfigapi.SEVSNPVersionAPI{
|
||||
func (f stubAttestationFetcher) FetchLatestVersion(_ context.Context, _ variant.Variant) (attestationconfigapi.VersionAPIEntry, error) {
|
||||
return attestationconfigapi.VersionAPIEntry{
|
||||
SEVSNPVersion: testCfg,
|
||||
}, nil
|
||||
}
|
||||
|
@ -171,14 +171,6 @@ type stubConfigFetcher struct {
|
||||
fetchLatestErr error
|
||||
}
|
||||
|
||||
func (s *stubConfigFetcher) FetchSEVSNPVersion(context.Context, attestationconfigapi.SEVSNPVersionAPI) (attestationconfigapi.SEVSNPVersionAPI, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (s *stubConfigFetcher) FetchSEVSNPVersionList(context.Context, attestationconfigapi.SEVSNPVersionList) (attestationconfigapi.SEVSNPVersionList, error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func (s *stubConfigFetcher) FetchLatestVersion(context.Context, variant.Variant) (attestationconfigapi.SEVSNPVersionAPI, error) {
|
||||
return attestationconfigapi.SEVSNPVersionAPI{}, s.fetchLatestErr
|
||||
func (s *stubConfigFetcher) FetchLatestVersion(context.Context, variant.Variant) (attestationconfigapi.VersionAPIEntry, error) {
|
||||
return attestationconfigapi.VersionAPIEntry{}, s.fetchLatestErr
|
||||
}
|
||||
|
@ -80,20 +80,20 @@ func (a Client) DeleteSEVSNPVersion(ctx context.Context, attestation variant.Var
|
||||
}
|
||||
|
||||
// List returns the list of versions for the given attestation variant.
|
||||
func (a Client) List(ctx context.Context, attestation variant.Variant) (attestationconfigapi.SEVSNPVersionList, error) {
|
||||
func (a Client) List(ctx context.Context, attestation variant.Variant) (attestationconfigapi.VersionList, error) {
|
||||
if !attestation.Equal(variant.AzureSEVSNP{}) &&
|
||||
!attestation.Equal(variant.AWSSEVSNP{}) &&
|
||||
!attestation.Equal(variant.GCPSEVSNP{}) {
|
||||
return attestationconfigapi.SEVSNPVersionList{}, fmt.Errorf("unsupported attestation variant: %s", attestation)
|
||||
return attestationconfigapi.VersionList{}, fmt.Errorf("unsupported attestation variant: %s", attestation)
|
||||
}
|
||||
|
||||
versions, err := apiclient.Fetch(ctx, a.s3Client, attestationconfigapi.SEVSNPVersionList{Variant: attestation})
|
||||
versions, err := apiclient.Fetch(ctx, a.s3Client, attestationconfigapi.VersionList{Variant: attestation})
|
||||
if err != nil {
|
||||
var notFoundErr *apiclient.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
return attestationconfigapi.SEVSNPVersionList{Variant: attestation}, nil
|
||||
return attestationconfigapi.VersionList{Variant: attestation}, nil
|
||||
}
|
||||
return attestationconfigapi.SEVSNPVersionList{}, err
|
||||
return attestationconfigapi.VersionList{}, err
|
||||
}
|
||||
|
||||
versions.Variant = attestation
|
||||
@ -101,10 +101,10 @@ func (a Client) List(ctx context.Context, attestation variant.Variant) (attestat
|
||||
return versions, nil
|
||||
}
|
||||
|
||||
func (a Client) deleteSEVSNPVersion(versions attestationconfigapi.SEVSNPVersionList, versionStr string) (ops []crudCmd, err error) {
|
||||
func (a Client) deleteSEVSNPVersion(versions attestationconfigapi.VersionList, versionStr string) (ops []crudCmd, err error) {
|
||||
versionStr = versionStr + ".json"
|
||||
ops = append(ops, deleteCmd{
|
||||
apiObject: attestationconfigapi.SEVSNPVersionAPI{
|
||||
apiObject: attestationconfigapi.VersionAPIEntry{
|
||||
Variant: versions.Variant,
|
||||
Version: versionStr,
|
||||
},
|
||||
@ -121,7 +121,7 @@ func (a Client) deleteSEVSNPVersion(versions attestationconfigapi.SEVSNPVersionL
|
||||
return ops, nil
|
||||
}
|
||||
|
||||
func (a Client) constructUploadCmd(attestation variant.Variant, version attestationconfigapi.SEVSNPVersion, versionNames attestationconfigapi.SEVSNPVersionList, date time.Time) []crudCmd {
|
||||
func (a Client) constructUploadCmd(attestation variant.Variant, version attestationconfigapi.SEVSNPVersion, versionNames attestationconfigapi.VersionList, date time.Time) []crudCmd {
|
||||
if !attestation.Equal(versionNames.Variant) {
|
||||
return nil
|
||||
}
|
||||
@ -130,7 +130,7 @@ func (a Client) constructUploadCmd(attestation variant.Variant, version attestat
|
||||
var res []crudCmd
|
||||
|
||||
res = append(res, putCmd{
|
||||
apiObject: attestationconfigapi.SEVSNPVersionAPI{Version: dateStr, Variant: attestation, SEVSNPVersion: version},
|
||||
apiObject: attestationconfigapi.VersionAPIEntry{Version: dateStr, Variant: attestation, SEVSNPVersion: version},
|
||||
signer: a.signer,
|
||||
})
|
||||
|
||||
@ -144,19 +144,19 @@ func (a Client) constructUploadCmd(attestation variant.Variant, version attestat
|
||||
return res
|
||||
}
|
||||
|
||||
func removeVersion(list attestationconfigapi.SEVSNPVersionList, versionStr string) (removedVersions attestationconfigapi.SEVSNPVersionList, err error) {
|
||||
func removeVersion(list attestationconfigapi.VersionList, versionStr string) (removedVersions attestationconfigapi.VersionList, err error) {
|
||||
versions := list.List
|
||||
for i, v := range versions {
|
||||
if v == versionStr {
|
||||
if i == len(versions)-1 {
|
||||
removedVersions = attestationconfigapi.SEVSNPVersionList{List: versions[:i], Variant: list.Variant}
|
||||
removedVersions = attestationconfigapi.VersionList{List: versions[:i], Variant: list.Variant}
|
||||
} else {
|
||||
removedVersions = attestationconfigapi.SEVSNPVersionList{List: append(versions[:i], versions[i+1:]...), Variant: list.Variant}
|
||||
removedVersions = attestationconfigapi.VersionList{List: append(versions[:i], versions[i+1:]...), Variant: list.Variant}
|
||||
}
|
||||
return removedVersions, nil
|
||||
}
|
||||
}
|
||||
return attestationconfigapi.SEVSNPVersionList{}, fmt.Errorf("version %s not found in list %v", versionStr, versions)
|
||||
return attestationconfigapi.VersionList{}, fmt.Errorf("version %s not found in list %v", versionStr, versions)
|
||||
}
|
||||
|
||||
type crudCmd interface {
|
||||
|
@ -21,11 +21,11 @@ func TestUploadAzureSEVSNP(t *testing.T) {
|
||||
}
|
||||
version := attestationconfigapi.SEVSNPVersion{}
|
||||
date := time.Date(2023, 1, 1, 1, 1, 1, 1, time.UTC)
|
||||
ops := sut.constructUploadCmd(variant.AzureSEVSNP{}, version, attestationconfigapi.SEVSNPVersionList{List: []string{"2021-01-01-01-01.json", "2019-01-01-01-01.json"}, Variant: variant.AzureSEVSNP{}}, date)
|
||||
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.SEVSNPVersionAPI{
|
||||
apiObject: attestationconfigapi.VersionAPIEntry{
|
||||
Variant: variant.AzureSEVSNP{},
|
||||
Version: dateStr,
|
||||
SEVSNPVersion: version,
|
||||
@ -33,7 +33,7 @@ func TestUploadAzureSEVSNP(t *testing.T) {
|
||||
signer: fakeSigner{},
|
||||
})
|
||||
assert.Contains(ops, putCmd{
|
||||
apiObject: attestationconfigapi.SEVSNPVersionList{Variant: variant.AzureSEVSNP{}, List: []string{"2023-01-01-01-01.json", "2021-01-01-01-01.json", "2019-01-01-01-01.json"}},
|
||||
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{},
|
||||
})
|
||||
}
|
||||
@ -42,20 +42,20 @@ func TestDeleteAzureSEVSNPVersions(t *testing.T) {
|
||||
sut := Client{
|
||||
bucketID: "bucket",
|
||||
}
|
||||
versions := attestationconfigapi.SEVSNPVersionList{List: []string{"2023-01-01.json", "2021-01-01.json", "2019-01-01.json"}}
|
||||
versions := attestationconfigapi.VersionList{List: []string{"2023-01-01.json", "2021-01-01.json", "2019-01-01.json"}}
|
||||
|
||||
ops, err := sut.deleteSEVSNPVersion(versions, "2021-01-01")
|
||||
|
||||
assert := assert.New(t)
|
||||
assert.NoError(err)
|
||||
assert.Contains(ops, deleteCmd{
|
||||
apiObject: attestationconfigapi.SEVSNPVersionAPI{
|
||||
apiObject: attestationconfigapi.VersionAPIEntry{
|
||||
Version: "2021-01-01.json",
|
||||
},
|
||||
})
|
||||
|
||||
assert.Contains(ops, putCmd{
|
||||
apiObject: attestationconfigapi.SEVSNPVersionList{List: []string{"2023-01-01.json", "2019-01-01.json"}},
|
||||
apiObject: attestationconfigapi.VersionList{List: []string{"2023-01-01.json", "2019-01-01.json"}},
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import (
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/attestationconfigapi/cli/client"
|
||||
"github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
"github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider"
|
||||
"github.com/edgelesssys/constellation/v2/internal/file"
|
||||
@ -127,7 +128,8 @@ func uploadReport(ctx context.Context,
|
||||
|
||||
latestAPIVersionAPI, err := attestationconfigapi.NewFetcherWithCustomCDNAndCosignKey(cfg.url, cfg.cosignPublicKey).FetchLatestVersion(ctx, attestation)
|
||||
if err != nil {
|
||||
if errors.Is(err, attestationconfigapi.ErrNoVersionsFound) {
|
||||
var notFoundErr *fetcher.NotFoundError
|
||||
if errors.As(err, ¬FoundErr) {
|
||||
log.Info("No versions found in API, but assuming that we are uploading the first version.")
|
||||
} else {
|
||||
return fmt.Errorf("fetching latest version: %w", err)
|
||||
|
@ -8,7 +8,6 @@ package attestationconfigapi
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
apifetcher "github.com/edgelesssys/constellation/v2/internal/api/fetcher"
|
||||
@ -19,12 +18,9 @@ import (
|
||||
|
||||
const cosignPublicKey = constants.CosignPublicKeyReleases
|
||||
|
||||
// ErrNoVersionsFound is returned if no versions are found.
|
||||
var ErrNoVersionsFound = errors.New("no versions found")
|
||||
|
||||
// Fetcher fetches config API resources without authentication.
|
||||
type Fetcher interface {
|
||||
FetchLatestVersion(ctx context.Context, attestation variant.Variant) (SEVSNPVersionAPI, error)
|
||||
FetchLatestVersion(ctx context.Context, attestation variant.Variant) (VersionAPIEntry, error)
|
||||
}
|
||||
|
||||
// fetcher fetches AttestationCfg API resources without authentication.
|
||||
@ -64,46 +60,43 @@ func newFetcherWithClientAndVerifier(client apifetcher.HTTPClient, cosignVerifie
|
||||
}
|
||||
|
||||
// FetchLatestVersion returns the latest versions of the given type.
|
||||
func (f *fetcher) FetchLatestVersion(ctx context.Context, attesation variant.Variant) (res SEVSNPVersionAPI, err error) {
|
||||
list, err := f.fetchVersionList(ctx, SEVSNPVersionList{Variant: attesation})
|
||||
func (f *fetcher) FetchLatestVersion(ctx context.Context, variant variant.Variant) (VersionAPIEntry, error) {
|
||||
list, err := f.fetchVersionList(ctx, variant)
|
||||
if err != nil {
|
||||
return res, ErrNoVersionsFound
|
||||
return VersionAPIEntry{}, err
|
||||
}
|
||||
|
||||
getVersionRequest := SEVSNPVersionAPI{
|
||||
Version: list.List[0], // latest version is first in list
|
||||
Variant: attesation,
|
||||
}
|
||||
res, err = f.fetchVersion(ctx, getVersionRequest)
|
||||
if err != nil {
|
||||
return res, err
|
||||
}
|
||||
return
|
||||
// latest version is first in list
|
||||
return f.fetchVersion(ctx, list.List[0], variant)
|
||||
}
|
||||
|
||||
// fetchVersionList fetches the version list information from the config API.
|
||||
func (f *fetcher) fetchVersionList(ctx context.Context, list SEVSNPVersionList) (SEVSNPVersionList, error) {
|
||||
// TODO(derpsteb): Replace with FetchAndVerify once we move to v2 of the config API.
|
||||
fetchedList, err := apifetcher.Fetch(ctx, f.HTTPClient, f.cdnURL, list)
|
||||
func (f *fetcher) fetchVersionList(ctx context.Context, variant variant.Variant) (VersionList, error) {
|
||||
// TODO(derpsteb): Replace with FetchAndVerify once we move to v2 of the config API and the list is saved as (.json) file.
|
||||
fetchedList, err := apifetcher.Fetch(ctx, f.HTTPClient, f.cdnURL, VersionList{Variant: variant})
|
||||
if err != nil {
|
||||
return list, fmt.Errorf("fetching version list: %w", err)
|
||||
return VersionList{}, fmt.Errorf("fetching version list: %w", err)
|
||||
}
|
||||
|
||||
// Need to set this explicitly as the variant is not part of the marshalled JSON.
|
||||
fetchedList.Variant = list.Variant
|
||||
// Set the attestation variant of the list as it is not part of the marshalled JSON retrieved by Fetch
|
||||
fetchedList.Variant = variant
|
||||
|
||||
return fetchedList, nil
|
||||
}
|
||||
|
||||
// fetchVersion fetches the version information from the config API.
|
||||
func (f *fetcher) fetchVersion(ctx context.Context, version SEVSNPVersionAPI) (SEVSNPVersionAPI, error) {
|
||||
fetchedVersion, err := apifetcher.FetchAndVerify(ctx, f.HTTPClient, f.cdnURL, version, f.verifier)
|
||||
func (f *fetcher) fetchVersion(ctx context.Context, version string, variant variant.Variant) (VersionAPIEntry, error) {
|
||||
obj := VersionAPIEntry{
|
||||
Version: version,
|
||||
Variant: variant,
|
||||
}
|
||||
fetchedVersion, err := apifetcher.FetchAndVerify(ctx, f.HTTPClient, f.cdnURL, obj, f.verifier)
|
||||
if err != nil {
|
||||
return fetchedVersion, fmt.Errorf("fetching version %s: %w", version.Version, err)
|
||||
return VersionAPIEntry{}, fmt.Errorf("fetching version %q: %w", version, err)
|
||||
}
|
||||
|
||||
// Need to set this explicitly as the variant is not part of the marshalled JSON.
|
||||
fetchedVersion.Variant = version.Variant
|
||||
// Set the attestation variant of the list as it is not part of the marshalled JSON retrieved by FetchAndVerify
|
||||
fetchedVersion.Variant = variant
|
||||
|
||||
return fetchedVersion, nil
|
||||
}
|
||||
|
@ -22,58 +22,7 @@ import (
|
||||
)
|
||||
|
||||
func TestFetchLatestSEVSNPVersion(t *testing.T) {
|
||||
latestStr := "2023-06-11-14-09.json"
|
||||
olderStr := "2019-01-01-01-01.json"
|
||||
testcases := map[string]struct {
|
||||
fetcherVersions []string
|
||||
timeAtTest time.Time
|
||||
wantErr bool
|
||||
attestation variant.Variant
|
||||
expectedVersion func() SEVSNPVersionAPI
|
||||
olderVersion func() SEVSNPVersionAPI
|
||||
latestVersion func() SEVSNPVersionAPI
|
||||
}{
|
||||
"get latest version azure": {
|
||||
fetcherVersions: []string{latestStr, olderStr},
|
||||
attestation: variant.AzureSEVSNP{},
|
||||
expectedVersion: func() SEVSNPVersionAPI { tmp := latestVersion; tmp.Variant = variant.AzureSEVSNP{}; return tmp },
|
||||
olderVersion: func() SEVSNPVersionAPI { tmp := olderVersion; tmp.Variant = variant.AzureSEVSNP{}; return tmp },
|
||||
latestVersion: func() SEVSNPVersionAPI { tmp := latestVersion; tmp.Variant = variant.AzureSEVSNP{}; return tmp },
|
||||
},
|
||||
"get latest version aws": {
|
||||
fetcherVersions: []string{latestStr, olderStr},
|
||||
attestation: variant.AWSSEVSNP{},
|
||||
expectedVersion: func() SEVSNPVersionAPI { tmp := latestVersion; tmp.Variant = variant.AWSSEVSNP{}; return tmp },
|
||||
olderVersion: func() SEVSNPVersionAPI { tmp := olderVersion; tmp.Variant = variant.AWSSEVSNP{}; return tmp },
|
||||
latestVersion: func() SEVSNPVersionAPI { tmp := latestVersion; tmp.Variant = variant.AWSSEVSNP{}; return tmp },
|
||||
},
|
||||
}
|
||||
for name, tc := range testcases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Transport: &fakeConfigAPIHandler{
|
||||
attestation: tc.attestation,
|
||||
versions: tc.fetcherVersions,
|
||||
latestDate: latestStr,
|
||||
latestVersion: tc.latestVersion(),
|
||||
olderDate: olderStr,
|
||||
olderVersion: tc.olderVersion(),
|
||||
},
|
||||
}
|
||||
fetcher := newFetcherWithClientAndVerifier(client, dummyVerifier{}, constants.CDNRepositoryURL)
|
||||
res, err := fetcher.FetchLatestVersion(context.Background(), tc.attestation)
|
||||
assert := assert.New(t)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.expectedVersion(), res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
var latestVersion = SEVSNPVersionAPI{
|
||||
latestVersionSNP := VersionAPIEntry{
|
||||
SEVSNPVersion: SEVSNPVersion{
|
||||
Microcode: 93,
|
||||
TEE: 0,
|
||||
@ -81,8 +30,7 @@ var latestVersion = SEVSNPVersionAPI{
|
||||
Bootloader: 2,
|
||||
},
|
||||
}
|
||||
|
||||
var olderVersion = SEVSNPVersionAPI{
|
||||
olderVersionSNP := VersionAPIEntry{
|
||||
SEVSNPVersion: SEVSNPVersion{
|
||||
Microcode: 1,
|
||||
TEE: 0,
|
||||
@ -90,14 +38,90 @@ var olderVersion = SEVSNPVersionAPI{
|
||||
Bootloader: 1,
|
||||
},
|
||||
}
|
||||
latestVersionTDX := VersionAPIEntry{
|
||||
TDXVersion: TDXVersion{
|
||||
QESVN: 2,
|
||||
PCESVN: 3,
|
||||
TEETCBSVN: [16]byte{4},
|
||||
QEVendorID: [16]byte{5},
|
||||
XFAM: [8]byte{6},
|
||||
},
|
||||
}
|
||||
olderVersionTDX := VersionAPIEntry{
|
||||
TDXVersion: TDXVersion{
|
||||
QESVN: 1,
|
||||
PCESVN: 2,
|
||||
TEETCBSVN: [16]byte{3},
|
||||
QEVendorID: [16]byte{4},
|
||||
XFAM: [8]byte{5},
|
||||
},
|
||||
}
|
||||
|
||||
latestStr := "2023-06-11-14-09.json"
|
||||
olderStr := "2019-01-01-01-01.json"
|
||||
testCases := map[string]struct {
|
||||
fetcherVersions []string
|
||||
timeAtTest time.Time
|
||||
wantErr bool
|
||||
attestation variant.Variant
|
||||
expectedVersion VersionAPIEntry
|
||||
olderVersion VersionAPIEntry
|
||||
latestVersion VersionAPIEntry
|
||||
}{
|
||||
"get latest version azure-sev-snp": {
|
||||
fetcherVersions: []string{latestStr, olderStr},
|
||||
attestation: variant.AzureSEVSNP{},
|
||||
expectedVersion: func() VersionAPIEntry { tmp := latestVersionSNP; tmp.Variant = variant.AzureSEVSNP{}; return tmp }(),
|
||||
olderVersion: func() VersionAPIEntry { tmp := olderVersionSNP; tmp.Variant = variant.AzureSEVSNP{}; return tmp }(),
|
||||
latestVersion: func() VersionAPIEntry { tmp := latestVersionSNP; tmp.Variant = variant.AzureSEVSNP{}; return tmp }(),
|
||||
},
|
||||
"get latest version aws-sev-snp": {
|
||||
fetcherVersions: []string{latestStr, olderStr},
|
||||
attestation: variant.AWSSEVSNP{},
|
||||
expectedVersion: func() VersionAPIEntry { tmp := latestVersionSNP; tmp.Variant = variant.AWSSEVSNP{}; return tmp }(),
|
||||
olderVersion: func() VersionAPIEntry { tmp := olderVersionSNP; tmp.Variant = variant.AWSSEVSNP{}; return tmp }(),
|
||||
latestVersion: func() VersionAPIEntry { tmp := latestVersionSNP; tmp.Variant = variant.AWSSEVSNP{}; return tmp }(),
|
||||
},
|
||||
"get latest version azure-tdx": {
|
||||
fetcherVersions: []string{latestStr, olderStr},
|
||||
attestation: variant.AzureTDX{},
|
||||
expectedVersion: func() VersionAPIEntry { tmp := latestVersionTDX; tmp.Variant = variant.AzureTDX{}; return tmp }(),
|
||||
olderVersion: func() VersionAPIEntry { tmp := olderVersionTDX; tmp.Variant = variant.AzureTDX{}; return tmp }(),
|
||||
latestVersion: func() VersionAPIEntry { tmp := latestVersionTDX; tmp.Variant = variant.AzureTDX{}; return tmp }(),
|
||||
},
|
||||
}
|
||||
for name, tc := range testCases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
client := &http.Client{
|
||||
Transport: &fakeConfigAPIHandler{
|
||||
attestation: tc.attestation,
|
||||
versions: tc.fetcherVersions,
|
||||
latestDate: latestStr,
|
||||
latestVersion: tc.latestVersion,
|
||||
olderDate: olderStr,
|
||||
olderVersion: tc.olderVersion,
|
||||
},
|
||||
}
|
||||
fetcher := newFetcherWithClientAndVerifier(client, stubVerifier{}, constants.CDNRepositoryURL)
|
||||
res, err := fetcher.FetchLatestVersion(context.Background(), tc.attestation)
|
||||
assert := assert.New(t)
|
||||
if tc.wantErr {
|
||||
assert.Error(err)
|
||||
} else {
|
||||
assert.NoError(err)
|
||||
assert.Equal(tc.expectedVersion, res)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
type fakeConfigAPIHandler struct {
|
||||
attestation variant.Variant
|
||||
versions []string
|
||||
latestDate string
|
||||
latestVersion SEVSNPVersionAPI
|
||||
latestVersion VersionAPIEntry
|
||||
olderDate string
|
||||
olderVersion SEVSNPVersionAPI
|
||||
olderVersion VersionAPIEntry
|
||||
}
|
||||
|
||||
// RoundTrip resolves the request and returns a dummy response.
|
||||
@ -148,8 +172,8 @@ func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, err
|
||||
return nil, errors.New("no endpoint found")
|
||||
}
|
||||
|
||||
type dummyVerifier struct{}
|
||||
type stubVerifier struct{}
|
||||
|
||||
func (s dummyVerifier) VerifySignature(_, _ []byte) error {
|
||||
func (s stubVerifier) VerifySignature(_, _ []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package attestationconfigapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
)
|
||||
|
||||
// AttestationURLPath is the URL path to the attestation versions.
|
||||
const AttestationURLPath = "constellation/v1/attestation"
|
||||
|
||||
// SEVSNPVersion tracks the latest version of each component of the SEVSNP.
|
||||
type SEVSNPVersion struct {
|
||||
// Bootloader is the latest version of the SEVSNP bootloader.
|
||||
Bootloader uint8 `json:"bootloader"`
|
||||
// TEE is the latest version of the SEVSNP TEE.
|
||||
TEE uint8 `json:"tee"`
|
||||
// SNP is the latest version of the SEVSNP SNP.
|
||||
SNP uint8 `json:"snp"`
|
||||
// Microcode is the latest version of the SEVSNP microcode.
|
||||
Microcode uint8 `json:"microcode"`
|
||||
}
|
||||
|
||||
// SEVSNPVersionAPI is the request to get the version information of the specific version in the config api.
|
||||
// Because variant is not part of the marshalled JSON, fetcher and client methods need to fill the variant property.
|
||||
// Once we switch to v2 of the API we should embed the variant in the object.
|
||||
// That would remove the possibility of some fetcher/client code forgetting to set the variant.
|
||||
type SEVSNPVersionAPI struct {
|
||||
Version string `json:"-"`
|
||||
Variant variant.Variant `json:"-"`
|
||||
SEVSNPVersion
|
||||
}
|
||||
|
||||
// JSONPath returns the path to the JSON file for the request to the config api.
|
||||
func (i SEVSNPVersionAPI) JSONPath() string {
|
||||
return path.Join(AttestationURLPath, i.Variant.String(), i.Version)
|
||||
}
|
||||
|
||||
// ValidateRequest validates the request.
|
||||
func (i SEVSNPVersionAPI) ValidateRequest() error {
|
||||
if !strings.HasSuffix(i.Version, ".json") {
|
||||
return fmt.Errorf("version has no .json suffix")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate is a No-Op at the moment.
|
||||
func (i SEVSNPVersionAPI) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SEVSNPVersionList is the request to list all versions in the config api.
|
||||
// Because variant is not part of the marshalled JSON, fetcher and client methods need to fill the variant property.
|
||||
// Once we switch to v2 of the API we could embed the variant in the object and remove some code from fetcher & client.
|
||||
// That would remove the possibility of some fetcher/client code forgetting to set the variant.
|
||||
type SEVSNPVersionList struct {
|
||||
Variant variant.Variant
|
||||
List []string
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the i's list property to JSON.
|
||||
func (i SEVSNPVersionList) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.List)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a list of strings into i's list property.
|
||||
func (i *SEVSNPVersionList) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &i.List)
|
||||
}
|
||||
|
||||
// JSONPath returns the path to the JSON file for the request to the config api.
|
||||
func (i SEVSNPVersionList) JSONPath() string {
|
||||
return path.Join(AttestationURLPath, i.Variant.String(), "list")
|
||||
}
|
||||
|
||||
// ValidateRequest is a NoOp as there is no input.
|
||||
func (i SEVSNPVersionList) ValidateRequest() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SortReverse sorts the list of versions in reverse order.
|
||||
func (i *SEVSNPVersionList) SortReverse() {
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(i.List)))
|
||||
}
|
||||
|
||||
// AddVersion adds new to i's list and sorts the element in descending order.
|
||||
func (i *SEVSNPVersionList) AddVersion(new string) {
|
||||
i.List = append(i.List, new)
|
||||
i.List = variant.RemoveDuplicate(i.List)
|
||||
|
||||
i.SortReverse()
|
||||
}
|
||||
|
||||
// Validate validates the response.
|
||||
func (i SEVSNPVersionList) Validate() error {
|
||||
if len(i.List) < 1 {
|
||||
return fmt.Errorf("no versions found in /list")
|
||||
}
|
||||
return nil
|
||||
}
|
127
internal/api/attestationconfigapi/version.go
Normal file
127
internal/api/attestationconfigapi/version.go
Normal file
@ -0,0 +1,127 @@
|
||||
/*
|
||||
Copyright (c) Edgeless Systems GmbH
|
||||
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package attestationconfigapi
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"path"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/edgelesssys/constellation/v2/internal/attestation/variant"
|
||||
)
|
||||
|
||||
// AttestationURLPath is the URL path to the attestation versions.
|
||||
const AttestationURLPath = "constellation/v1/attestation"
|
||||
|
||||
// SEVSNPVersion tracks the latest version of each component for SEV-SNP.
|
||||
type SEVSNPVersion struct {
|
||||
// Bootloader is the latest version of the SEV-SNP bootloader.
|
||||
Bootloader uint8 `json:"bootloader,omitempty"`
|
||||
// TEE is the latest version of the SEV-SNP TEE.
|
||||
TEE uint8 `json:"tee,omitempty"`
|
||||
// SNP is the latest version of the SEV-SNP SNP.
|
||||
SNP uint8 `json:"snp,omitempty"`
|
||||
// Microcode is the latest version of the SEV-SNP microcode.
|
||||
Microcode uint8 `json:"microcode,omitempty"`
|
||||
}
|
||||
|
||||
// TDXVersion tracks the latest version of each component for TDX.
|
||||
type TDXVersion struct {
|
||||
// QESVN is the latest QE security version number.
|
||||
QESVN uint16 `json:"qeSVN,omitempty"`
|
||||
// PCESVN is the latest PCE security version number.
|
||||
PCESVN uint16 `json:"pceSVN,omitempty"`
|
||||
// TEETCBSVN are the latest component-wise security version numbers for the TEE.
|
||||
TEETCBSVN [16]byte `json:"teeTCBSVN,omitempty"`
|
||||
// QEVendorID is the latest QE vendor ID.
|
||||
QEVendorID [16]byte `json:"qeVendorID,omitempty"`
|
||||
// XFAM is the latest XFAM field.
|
||||
XFAM [8]byte `json:"xfam,omitempty"`
|
||||
}
|
||||
|
||||
// VersionAPIEntry is the request to get the version information of the specific version in the config api.
|
||||
//
|
||||
// TODO: Because variant is not part of the marshalled JSON, fetcher and client methods need to fill the variant property.
|
||||
// In API v2 we should embed the variant in the object and remove some code from fetcher & client.
|
||||
// That would remove the possibility of some fetcher/client code forgetting to set the variant.
|
||||
type VersionAPIEntry struct {
|
||||
Version string `json:"-"`
|
||||
Variant variant.Variant `json:"-"`
|
||||
SEVSNPVersion
|
||||
TDXVersion
|
||||
}
|
||||
|
||||
// JSONPath returns the path to the JSON file for the request to the config api.
|
||||
func (i VersionAPIEntry) JSONPath() string {
|
||||
return path.Join(AttestationURLPath, i.Variant.String(), i.Version)
|
||||
}
|
||||
|
||||
// ValidateRequest validates the request.
|
||||
func (i VersionAPIEntry) ValidateRequest() error {
|
||||
if !strings.HasSuffix(i.Version, ".json") {
|
||||
return fmt.Errorf("version has no .json suffix")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Validate is a No-Op at the moment.
|
||||
func (i VersionAPIEntry) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// VersionList is the request to retrieve of all versions in the API for one attestation variant.
|
||||
//
|
||||
// TODO: Because variant is not part of the marshalled JSON, fetcher and client methods need to fill the variant property.
|
||||
// In API v2 we should embed the variant in the object and remove some code from fetcher & client.
|
||||
// That would remove the possibility of some fetcher/client code forgetting to set the variant.
|
||||
type VersionList struct {
|
||||
Variant variant.Variant
|
||||
List []string
|
||||
}
|
||||
|
||||
// MarshalJSON marshals the i's list property to JSON.
|
||||
func (i VersionList) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(i.List)
|
||||
}
|
||||
|
||||
// UnmarshalJSON unmarshals a list of strings into i's list property.
|
||||
func (i *VersionList) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &i.List)
|
||||
}
|
||||
|
||||
// JSONPath returns the path to the JSON file for the request to the config api.
|
||||
func (i VersionList) JSONPath() string {
|
||||
return path.Join(AttestationURLPath, i.Variant.String(), "list")
|
||||
}
|
||||
|
||||
// ValidateRequest is a NoOp as there is no input.
|
||||
func (i VersionList) ValidateRequest() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// SortReverse sorts the list of versions in reverse order.
|
||||
func (i *VersionList) SortReverse() {
|
||||
sort.Sort(sort.Reverse(sort.StringSlice(i.List)))
|
||||
}
|
||||
|
||||
// AddVersion adds new to i's list and sorts the element in descending order.
|
||||
func (i *VersionList) AddVersion(new string) {
|
||||
i.List = append(i.List, new)
|
||||
i.List = variant.RemoveDuplicate(i.List)
|
||||
|
||||
i.SortReverse()
|
||||
}
|
||||
|
||||
// Validate validates the response.
|
||||
func (i VersionList) Validate() error {
|
||||
if len(i.List) < 1 {
|
||||
return fmt.Errorf("no versions found in /list")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -14,23 +14,23 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestSEVSNPVersionListMarshalUnmarshalJSON(t *testing.T) {
|
||||
func TestVersionListMarshalUnmarshalJSON(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
input SEVSNPVersionList
|
||||
output SEVSNPVersionList
|
||||
input VersionList
|
||||
output VersionList
|
||||
wantDiff bool
|
||||
}{
|
||||
"success": {
|
||||
input: SEVSNPVersionList{List: []string{"v1", "v2"}},
|
||||
output: SEVSNPVersionList{List: []string{"v1", "v2"}},
|
||||
input: VersionList{List: []string{"v1", "v2"}},
|
||||
output: VersionList{List: []string{"v1", "v2"}},
|
||||
},
|
||||
"variant is lost": {
|
||||
input: SEVSNPVersionList{List: []string{"v1", "v2"}, Variant: variant.AzureSEVSNP{}},
|
||||
output: SEVSNPVersionList{List: []string{"v1", "v2"}},
|
||||
input: VersionList{List: []string{"v1", "v2"}, Variant: variant.AzureSEVSNP{}},
|
||||
output: VersionList{List: []string{"v1", "v2"}},
|
||||
},
|
||||
"wrong order": {
|
||||
input: SEVSNPVersionList{List: []string{"v1", "v2"}},
|
||||
output: SEVSNPVersionList{List: []string{"v2", "v1"}},
|
||||
input: VersionList{List: []string{"v1", "v2"}},
|
||||
output: VersionList{List: []string{"v2", "v1"}},
|
||||
wantDiff: true,
|
||||
},
|
||||
}
|
||||
@ -40,7 +40,7 @@ func TestSEVSNPVersionListMarshalUnmarshalJSON(t *testing.T) {
|
||||
inputRaw, err := tc.input.MarshalJSON()
|
||||
require.NoError(t, err)
|
||||
|
||||
var actual SEVSNPVersionList
|
||||
var actual VersionList
|
||||
err = actual.UnmarshalJSON(inputRaw)
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -53,7 +53,7 @@ func TestSEVSNPVersionListMarshalUnmarshalJSON(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSEVSNPVersionListAddVersion(t *testing.T) {
|
||||
func TestVersionListAddVersion(t *testing.T) {
|
||||
tests := map[string]struct {
|
||||
versions []string
|
||||
new string
|
||||
@ -68,7 +68,7 @@ func TestSEVSNPVersionListAddVersion(t *testing.T) {
|
||||
|
||||
for name, tc := range tests {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
v := SEVSNPVersionList{List: tc.versions}
|
||||
v := VersionList{List: tc.versions}
|
||||
v.AddVersion(tc.new)
|
||||
|
||||
assert.Equal(t, tc.expected, v.List)
|
@ -1051,18 +1051,8 @@ func getConfigAsMap(conf *Config, t *testing.T) (res configMap) {
|
||||
|
||||
type stubAttestationFetcher struct{}
|
||||
|
||||
func (f stubAttestationFetcher) FetchSEVSNPVersionList(_ context.Context, _ attestationconfigapi.SEVSNPVersionList) (attestationconfigapi.SEVSNPVersionList, error) {
|
||||
return attestationconfigapi.SEVSNPVersionList{}, nil
|
||||
}
|
||||
|
||||
func (f stubAttestationFetcher) FetchSEVSNPVersion(_ context.Context, _ attestationconfigapi.SEVSNPVersionAPI) (attestationconfigapi.SEVSNPVersionAPI, error) {
|
||||
return attestationconfigapi.SEVSNPVersionAPI{
|
||||
SEVSNPVersion: testCfg,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (f stubAttestationFetcher) FetchLatestVersion(_ context.Context, _ variant.Variant) (attestationconfigapi.SEVSNPVersionAPI, error) {
|
||||
return attestationconfigapi.SEVSNPVersionAPI{
|
||||
func (f stubAttestationFetcher) FetchLatestVersion(_ context.Context, _ variant.Variant) (attestationconfigapi.VersionAPIEntry, error) {
|
||||
return attestationconfigapi.VersionAPIEntry{
|
||||
SEVSNPVersion: testCfg,
|
||||
}, nil
|
||||
}
|
||||
|
@ -162,7 +162,7 @@ func (d *AttestationDataSource) Read(ctx context.Context, req datasource.ReadReq
|
||||
|
||||
insecureFetch := data.Insecure.ValueBool()
|
||||
|
||||
snpVersions := attestationconfigapi.SEVSNPVersionAPI{}
|
||||
snpVersions := attestationconfigapi.VersionAPIEntry{}
|
||||
if attestationVariant.Equal(variant.AzureSEVSNP{}) ||
|
||||
attestationVariant.Equal(variant.AWSSEVSNP{}) ||
|
||||
attestationVariant.Equal(variant.GCPSEVSNP{}) {
|
||||
|
@ -137,7 +137,7 @@ func convertFromTfAttestationCfg(tfAttestation attestationAttribute, attestation
|
||||
}
|
||||
|
||||
// convertToTfAttestationCfg converts the constellation attestation config to the related terraform structs.
|
||||
func convertToTfAttestation(attVar variant.Variant, snpVersions attestationconfigapi.SEVSNPVersionAPI) (tfAttestation attestationAttribute, err error) {
|
||||
func convertToTfAttestation(attVar variant.Variant, snpVersions attestationconfigapi.VersionAPIEntry) (tfAttestation attestationAttribute, err error) {
|
||||
tfAttestation = attestationAttribute{
|
||||
Variant: attVar.String(),
|
||||
BootloaderVersion: snpVersions.Bootloader,
|
||||
|
Loading…
Reference in New Issue
Block a user