mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-08-10 16:00:19 -04:00
api: refactor attestationconfigapi client/fetcher
There is now one SEVSNPVersions type that has a variant property. That property is used to build the correct JSON path. The surrounding methods handling the version objects are also updated to receive a variant argument and work for multiple variants. This simplifies adding AWS support.
This commit is contained in:
parent
5542f9c63c
commit
350397923f
16 changed files with 411 additions and 262 deletions
|
@ -6,6 +6,8 @@ SPDX-License-Identifier: AGPL-3.0-only
|
|||
|
||||
/*
|
||||
The reporter contains the logic to determine a latest version for Azure SEVSNP based on cached version values observed on CVM instances.
|
||||
Some code in this file (e.g. listing cached files) does not rely on dedicated API objects and instead uses the AWS SDK directly,
|
||||
for no other reason than original development speed.
|
||||
*/
|
||||
package attestationconfigapi
|
||||
|
||||
|
@ -28,25 +30,27 @@ import (
|
|||
// cachedVersionsSubDir is the subdirectory in the bucket where the cached versions are stored.
|
||||
const cachedVersionsSubDir = "cached-versions"
|
||||
|
||||
var reportVersionDir = path.Join(attestationURLPath, variant.AzureSEVSNP{}.String(), cachedVersionsSubDir)
|
||||
|
||||
// ErrNoNewerVersion is returned if the input version is not newer than the latest API version.
|
||||
var ErrNoNewerVersion = errors.New("input version is not newer than latest API version")
|
||||
|
||||
// UploadAzureSEVSNPVersionLatest saves the given version to the cache, determines the smallest
|
||||
func reportVersionDir(attestation variant.Variant) string {
|
||||
return path.Join(attestationURLPath, attestation.String(), cachedVersionsSubDir)
|
||||
}
|
||||
|
||||
// UploadSEVSNPVersionLatest saves the given version to the cache, determines the smallest
|
||||
// TCB version in the cache among the last cacheWindowSize versions and updates
|
||||
// the latest version in the API if there is an update.
|
||||
// force can be used to bypass the validation logic against the cached versions.
|
||||
func (c Client) UploadAzureSEVSNPVersionLatest(ctx context.Context, inputVersion,
|
||||
latestAPIVersion AzureSEVSNPVersion, now time.Time, force bool,
|
||||
func (c Client) UploadSEVSNPVersionLatest(ctx context.Context, attestation variant.Variant, inputVersion,
|
||||
latestAPIVersion SEVSNPVersion, now time.Time, force bool,
|
||||
) error {
|
||||
if err := c.cacheAzureSEVSNPVersion(ctx, inputVersion, now); err != nil {
|
||||
if err := c.cacheSEVSNPVersion(ctx, attestation, inputVersion, now); err != nil {
|
||||
return fmt.Errorf("reporting version: %w", err)
|
||||
}
|
||||
if force {
|
||||
return c.uploadAzureSEVSNPVersion(ctx, inputVersion, now)
|
||||
return c.uploadSEVSNPVersion(ctx, attestation, inputVersion, now)
|
||||
}
|
||||
versionDates, err := c.listCachedVersions(ctx)
|
||||
versionDates, err := c.listCachedVersions(ctx, attestation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("list reported versions: %w", err)
|
||||
}
|
||||
|
@ -54,7 +58,7 @@ func (c Client) UploadAzureSEVSNPVersionLatest(ctx context.Context, inputVersion
|
|||
c.s3Client.Logger.Warnf("Skipping version update, found %d, expected %d reported versions.", len(versionDates), c.cacheWindowSize)
|
||||
return nil
|
||||
}
|
||||
minVersion, minDate, err := c.findMinVersion(ctx, versionDates)
|
||||
minVersion, minDate, err := c.findMinVersion(ctx, attestation, versionDates)
|
||||
if err != nil {
|
||||
return fmt.Errorf("get minimal version: %w", err)
|
||||
}
|
||||
|
@ -72,27 +76,27 @@ func (c Client) UploadAzureSEVSNPVersionLatest(ctx context.Context, inputVersion
|
|||
if err != nil {
|
||||
return fmt.Errorf("parsing date: %w", err)
|
||||
}
|
||||
if err := c.uploadAzureSEVSNPVersion(ctx, minVersion, t); err != nil {
|
||||
if err := c.uploadSEVSNPVersion(ctx, attestation, minVersion, t); err != nil {
|
||||
return fmt.Errorf("uploading version: %w", err)
|
||||
}
|
||||
c.s3Client.Logger.Infof("Successfully uploaded new Azure SEV-SNP version: %+v", minVersion)
|
||||
return nil
|
||||
}
|
||||
|
||||
// cacheAzureSEVSNPVersion uploads the latest observed version numbers of the Azure SEVSNP. This version is used to later report the latest version numbers to the API.
|
||||
func (c Client) cacheAzureSEVSNPVersion(ctx context.Context, version AzureSEVSNPVersion, date time.Time) error {
|
||||
// cacheSEVSNPVersion uploads the latest observed version numbers of the Azure SEVSNP. This version is used to later report the latest version numbers to the API.
|
||||
func (c Client) cacheSEVSNPVersion(ctx context.Context, attestation variant.Variant, version SEVSNPVersion, date time.Time) error {
|
||||
dateStr := date.Format(VersionFormat) + ".json"
|
||||
res := putCmd{
|
||||
apiObject: reportedAzureSEVSNPVersionAPI{Version: dateStr, AzureSEVSNPVersion: version},
|
||||
apiObject: reportedSEVSNPVersionAPI{Version: dateStr, variant: attestation, SEVSNPVersion: version},
|
||||
signer: c.signer,
|
||||
}
|
||||
return res.Execute(ctx, c.s3Client)
|
||||
}
|
||||
|
||||
func (c Client) listCachedVersions(ctx context.Context) ([]string, error) {
|
||||
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),
|
||||
Prefix: aws.String(reportVersionDir),
|
||||
Prefix: aws.String(reportVersionDir(attestation)),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("list objects: %w", err)
|
||||
|
@ -108,28 +112,30 @@ func (c Client) listCachedVersions(ctx context.Context) ([]string, error) {
|
|||
}
|
||||
|
||||
// findMinVersion finds the minimal version of the given version dates among the latest values in the version window size.
|
||||
func (c Client) findMinVersion(ctx context.Context, versionDates []string) (AzureSEVSNPVersion, string, error) {
|
||||
var minimalVersion *AzureSEVSNPVersion
|
||||
func (c Client) findMinVersion(ctx context.Context, attesation variant.Variant, versionDates []string) (SEVSNPVersion, string, error) {
|
||||
var minimalVersion *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, reportedAzureSEVSNPVersionAPI{Version: date + ".json"})
|
||||
obj, err := client.Fetch(ctx, c.s3Client, reportedSEVSNPVersionAPI{Version: date + ".json", variant: attesation})
|
||||
if err != nil {
|
||||
return AzureSEVSNPVersion{}, "", fmt.Errorf("get object: %w", err)
|
||||
return SEVSNPVersion{}, "", fmt.Errorf("get object: %w", err)
|
||||
}
|
||||
// Need to set this explicitly as the variant is not part of the marshalled JSON.
|
||||
obj.variant = attesation
|
||||
|
||||
if minimalVersion == nil {
|
||||
minimalVersion = &obj.AzureSEVSNPVersion
|
||||
minimalVersion = &obj.SEVSNPVersion
|
||||
minimalDate = date
|
||||
} else {
|
||||
shouldUpdateMinimal, err := isInputNewerThanOtherVersion(*minimalVersion, obj.AzureSEVSNPVersion)
|
||||
shouldUpdateMinimal, err := isInputNewerThanOtherVersion(*minimalVersion, obj.SEVSNPVersion)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if shouldUpdateMinimal {
|
||||
minimalVersion = &obj.AzureSEVSNPVersion
|
||||
minimalVersion = &obj.SEVSNPVersion
|
||||
minimalDate = date
|
||||
}
|
||||
}
|
||||
|
@ -138,7 +144,7 @@ func (c Client) findMinVersion(ctx context.Context, versionDates []string) (Azur
|
|||
}
|
||||
|
||||
// isInputNewerThanOtherVersion compares all version fields and returns true if any input field is newer.
|
||||
func isInputNewerThanOtherVersion(input, other AzureSEVSNPVersion) (bool, error) {
|
||||
func isInputNewerThanOtherVersion(input, other SEVSNPVersion) (bool, error) {
|
||||
if input == other {
|
||||
return false, nil
|
||||
}
|
||||
|
@ -157,19 +163,20 @@ func isInputNewerThanOtherVersion(input, other AzureSEVSNPVersion) (bool, error)
|
|||
return true, nil
|
||||
}
|
||||
|
||||
// reportedAzureSEVSNPVersionAPI is the request to get the version information of the specific version in the config api.
|
||||
type reportedAzureSEVSNPVersionAPI struct {
|
||||
Version string `json:"-"`
|
||||
AzureSEVSNPVersion
|
||||
// reportedSEVSNPVersionAPI is the request to get the version information of the specific version in the config api.
|
||||
type reportedSEVSNPVersionAPI 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 reportedAzureSEVSNPVersionAPI) JSONPath() string {
|
||||
return path.Join(reportVersionDir, i.Version)
|
||||
func (i reportedSEVSNPVersionAPI) JSONPath() string {
|
||||
return path.Join(reportVersionDir(i.variant), i.Version)
|
||||
}
|
||||
|
||||
// ValidateRequest validates the request.
|
||||
func (i reportedAzureSEVSNPVersionAPI) ValidateRequest() error {
|
||||
func (i reportedSEVSNPVersionAPI) ValidateRequest() error {
|
||||
if !strings.HasSuffix(i.Version, ".json") {
|
||||
return fmt.Errorf("version has no .json suffix")
|
||||
}
|
||||
|
@ -177,6 +184,6 @@ func (i reportedAzureSEVSNPVersionAPI) ValidateRequest() error {
|
|||
}
|
||||
|
||||
// Validate is a No-Op at the moment.
|
||||
func (i reportedAzureSEVSNPVersionAPI) Validate() error {
|
||||
func (i reportedSEVSNPVersionAPI) Validate() error {
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue