diff --git a/.github/actions/versionsapi/Dockerfile b/.github/actions/versionsapi/Dockerfile index 3cafdc0e7..145703dff 100644 --- a/.github/actions/versionsapi/Dockerfile +++ b/.github/actions/versionsapi/Dockerfile @@ -13,11 +13,11 @@ RUN go mod download COPY . . # Build -WORKDIR /workspace/internal/versionsapi/cli +WORKDIR /workspace/internal/api/versionsapi/cli RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o versionsapi . FROM scratch as release -COPY --from=builder /workspace/internal/versionsapi/cli/versionsapi . +COPY --from=builder /workspace/internal/api/versionsapi/cli/versionsapi . CMD ["/notIntendedToBeExecuted"] diff --git a/.github/workflows/build-versionsapi-ci-image.yml b/.github/workflows/build-versionsapi-ci-image.yml index 50e429cab..282859684 100644 --- a/.github/workflows/build-versionsapi-ci-image.yml +++ b/.github/workflows/build-versionsapi-ci-image.yml @@ -6,7 +6,7 @@ on: branches: - main paths: - - "internal/versionsapi/**" + - "internal/api/versionsapi/**" - ".github/workflows/build-versionsapi-ci-image.yml" - ".github/actions/versionsapi/**" diff --git a/CODEOWNERS b/CODEOWNERS index dae290217..e0117a40c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -36,7 +36,7 @@ /internal/retry @katexochen /internal/sigstore @malt3 /internal/versions @katexochen -/internal/versionsapi @katexochen +/internal/api/versionsapi @katexochen /joinservice @daniel-weisse /keyservice @daniel-weisse /operators @malt3 diff --git a/cli/internal/cmd/BUILD.bazel b/cli/internal/cmd/BUILD.bazel index 3bfb323c7..39eb30812 100644 --- a/cli/internal/cmd/BUILD.bazel +++ b/cli/internal/cmd/BUILD.bazel @@ -46,6 +46,8 @@ go_library( "//cli/internal/terraform", "//cli/internal/upgrade", "//disk-mapper/recoverproto", + "//internal/api/fetcher", + "//internal/api/versionsapi", "//internal/atls", "//internal/attestation/measurements", "//internal/cloud/azureshared", @@ -71,8 +73,6 @@ go_library( "//internal/sigstore", "//internal/variant", "//internal/versions", - "//internal/versionsapi", - "//internal/versionsapi/fetcher", "//operators/constellation-node-operator/api/v1alpha1", "//verify/verifyproto", "@com_github_mattn_go_isatty//:go-isatty", @@ -126,6 +126,7 @@ go_test( "//cli/internal/terraform", "//cli/internal/upgrade", "//disk-mapper/recoverproto", + "//internal/api/versionsapi", "//internal/atls", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", @@ -142,7 +143,6 @@ go_test( "//internal/logger", "//internal/variant", "//internal/versions", - "//internal/versionsapi", "//operators/constellation-node-operator/api/v1alpha1", "//verify/verifyproto", "@com_github_spf13_afero//:afero", diff --git a/cli/internal/cmd/configfetchmeasurements.go b/cli/internal/cmd/configfetchmeasurements.go index 43ceeba45..cdb18c2f4 100644 --- a/cli/internal/cmd/configfetchmeasurements.go +++ b/cli/internal/cmd/configfetchmeasurements.go @@ -14,12 +14,12 @@ import ( "net/url" "time" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/sigstore" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "github.com/spf13/afero" "github.com/spf13/cobra" ) @@ -77,7 +77,7 @@ func (cfm *configFetchMeasurementsCmd) configFetchMeasurements( cfm.log.Debugf("Using flags %v", flags) cfm.log.Debugf("Loading configuration file from %q", flags.configPath) - conf, err := config.New(fileHandler, flags.configPath, flags.force) + conf, err := config.NewWithClient(fileHandler, flags.configPath, client, flags.force) var configValidationErr *config.ValidationError if errors.As(err, &configValidationErr) { cmd.PrintErrln(configValidationErr.LongMessage()) diff --git a/cli/internal/cmd/configfetchmeasurements_test.go b/cli/internal/cmd/configfetchmeasurements_test.go index 5da1e04c2..f6b3fcb5e 100644 --- a/cli/internal/cmd/configfetchmeasurements_test.go +++ b/cli/internal/cmd/configfetchmeasurements_test.go @@ -15,12 +15,12 @@ import ( "net/url" "testing" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/cli/internal/cmd/upgradecheck.go b/cli/internal/cmd/upgradecheck.go index 4291549e6..57fa270cd 100644 --- a/cli/internal/cmd/upgradecheck.go +++ b/cli/internal/cmd/upgradecheck.go @@ -17,6 +17,8 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/helm" "github.com/edgelesssys/constellation/v2/cli/internal/kubernetes" + "github.com/edgelesssys/constellation/v2/internal/api/fetcher" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/compatibility" @@ -28,8 +30,6 @@ import ( "github.com/edgelesssys/constellation/v2/internal/sigstore" "github.com/edgelesssys/constellation/v2/internal/variant" "github.com/edgelesssys/constellation/v2/internal/versions" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - "github.com/edgelesssys/constellation/v2/internal/versionsapi/fetcher" "github.com/siderolabs/talos/pkg/machinery/config/encoder" "github.com/spf13/afero" "github.com/spf13/cobra" @@ -67,7 +67,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error { if err != nil { return err } - versionListFetcher := fetcher.NewFetcher() + versionListFetcher := fetcher.NewVersionAPIFetcher() rekor, err := sigstore.NewRekor() if err != nil { return fmt.Errorf("constructing Rekor client: %w", err) @@ -83,7 +83,7 @@ func runUpgradeCheck(cmd *cobra.Command, _ []string) error { flags: flags, cliVersion: compatibility.EnsurePrefixV(constants.VersionInfo()), log: log, - versionsapi: fetcher.NewFetcher(), + versionsapi: fetcher.NewVersionAPIFetcher(), }, log: log, } diff --git a/cli/internal/cmd/upgradecheck_test.go b/cli/internal/cmd/upgradecheck_test.go index 0e3c3ba3a..0a42ff5c9 100644 --- a/cli/internal/cmd/upgradecheck_test.go +++ b/cli/internal/cmd/upgradecheck_test.go @@ -15,6 +15,7 @@ import ( "strings" "testing" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config" @@ -22,7 +23,6 @@ import ( "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/cli/internal/kubernetes/BUILD.bazel b/cli/internal/kubernetes/BUILD.bazel index 53b795e20..cfa2a80c1 100644 --- a/cli/internal/kubernetes/BUILD.bazel +++ b/cli/internal/kubernetes/BUILD.bazel @@ -14,6 +14,7 @@ go_library( "//cli/internal/helm", "//cli/internal/terraform", "//cli/internal/upgrade", + "//internal/api/versionsapi", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", "//internal/compatibility", @@ -26,7 +27,6 @@ go_library( "//internal/variant", "//internal/versions", "//internal/versions/components", - "//internal/versionsapi", "//operators/constellation-node-operator/api/v1alpha1", "@io_k8s_api//core/v1:core", "@io_k8s_apimachinery//pkg/api/errors", diff --git a/cli/internal/kubernetes/upgrade.go b/cli/internal/kubernetes/upgrade.go index 316b1b326..106f43d38 100644 --- a/cli/internal/kubernetes/upgrade.go +++ b/cli/internal/kubernetes/upgrade.go @@ -18,6 +18,7 @@ import ( "github.com/edgelesssys/constellation/v2/cli/internal/helm" "github.com/edgelesssys/constellation/v2/cli/internal/terraform" "github.com/edgelesssys/constellation/v2/cli/internal/upgrade" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/compatibility" @@ -30,7 +31,6 @@ import ( "github.com/edgelesssys/constellation/v2/internal/variant" "github.com/edgelesssys/constellation/v2/internal/versions" "github.com/edgelesssys/constellation/v2/internal/versions/components" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" updatev1alpha1 "github.com/edgelesssys/constellation/v2/operators/constellation-node-operator/v2/api/v1alpha1" corev1 "k8s.io/api/core/v1" k8serrors "k8s.io/apimachinery/pkg/api/errors" diff --git a/debugd/README.md b/debugd/README.md index f1c39a608..f6c516ee0 100644 --- a/debugd/README.md +++ b/debugd/README.md @@ -22,7 +22,7 @@ With `cdbg` and `yq` installed in your path: 1. Run `constellation config generate` to create a new default configuration -2. Locate the latest debugd images by running `(cd internal/versionsapi/cli && go build -o versionsapi . && ./versionsapi latest --ref main --stream debug)` +2. Locate the latest debugd images by running `(cd internal/api/versionsapi/cli && go build -o versionsapi . && ./versionsapi latest --ref main --stream debug)` 3. Modify the `constellation-conf.yaml` to use an image with the debugd already included and add required firewall rules: diff --git a/e2e/internal/upgrade/BUILD.bazel b/e2e/internal/upgrade/BUILD.bazel index 26c6c3b7a..5bcbb0184 100644 --- a/e2e/internal/upgrade/BUILD.bazel +++ b/e2e/internal/upgrade/BUILD.bazel @@ -11,13 +11,13 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/e2e/internal/upgrade", visibility = ["//e2e:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", "//internal/constants", "//internal/imagefetcher", "//internal/logger", "//internal/variant", - "//internal/versionsapi", "@sh_helm_helm_v3//pkg/action", "@sh_helm_helm_v3//pkg/cli", ], diff --git a/e2e/internal/upgrade/image.go b/e2e/internal/upgrade/image.go index 7e8d28e8e..3fe0c4884 100644 --- a/e2e/internal/upgrade/image.go +++ b/e2e/internal/upgrade/image.go @@ -12,11 +12,11 @@ import ( "context" "net/http" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/imagefetcher" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) type upgradeInfo struct { diff --git a/hack/cli-k8s-compatibility/BUILD.bazel b/hack/cli-k8s-compatibility/BUILD.bazel index cae5918cd..83d755b19 100644 --- a/hack/cli-k8s-compatibility/BUILD.bazel +++ b/hack/cli-k8s-compatibility/BUILD.bazel @@ -6,10 +6,10 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/hack/cli-k8s-compatibility", visibility = ["//visibility:private"], deps = [ + "//internal/api/versionsapi", + "//internal/api/versionsapi/client", "//internal/logger", "//internal/versions", - "//internal/versionsapi", - "//internal/versionsapi/client", "@org_uber_go_zap//zapcore", ], ) diff --git a/hack/cli-k8s-compatibility/main.go b/hack/cli-k8s-compatibility/main.go index f840e5f60..c1cf2c672 100644 --- a/hack/cli-k8s-compatibility/main.go +++ b/hack/cli-k8s-compatibility/main.go @@ -11,10 +11,10 @@ import ( "context" "flag" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/versions" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - "github.com/edgelesssys/constellation/v2/internal/versionsapi/client" "go.uber.org/zap/zapcore" ) diff --git a/hack/configapi/BUILD.bazel b/hack/configapi/BUILD.bazel new file mode 100644 index 000000000..ab517c2db --- /dev/null +++ b/hack/configapi/BUILD.bazel @@ -0,0 +1,19 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library") + +go_library( + name = "configapi_lib", + srcs = ["main.go"], + importpath = "github.com/edgelesssys/constellation/v2/hack/configapi", + visibility = ["//visibility:private"], + deps = [ + "//internal/api/configapi", + "//internal/kms/uri", + "@com_github_spf13_cobra//:cobra", + ], +) + +go_binary( + name = "upload", + embed = [":configapi_lib"], + visibility = ["//visibility:public"], +) diff --git a/hack/configapi/main.go b/hack/configapi/main.go new file mode 100644 index 000000000..0cf5bd685 --- /dev/null +++ b/hack/configapi/main.go @@ -0,0 +1,91 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package main + +import ( + "context" + "fmt" + "time" + + "github.com/edgelesssys/constellation/v2/internal/api/configapi" + "github.com/edgelesssys/constellation/v2/internal/kms/uri" + "github.com/spf13/cobra" +) + +const ( + awsRegion = "eu-central-1" + awsBucket = "cdn-constellation-backend" + invalidDefault = 0 +) + +var ( + // AWS S3 credentials. + awsAccessKeyID string + awsAccessKey string + + // Azure SEV-SNP version numbers. + bootloaderVersion uint8 + teeVersion uint8 + snpVersion uint8 + microcodeVersion uint8 +) + +func handleError(err error) { + if err != nil { + panic(err) + } +} + +func main() { + myCmd := &cobra.Command{ + Use: "upload a set of versions specific to the azure-sev-snp attestation variant to the config api", + Short: "upload a set of versions specific to the azure-sev-snp attestation variant to the config api", + Run: func(cmd *cobra.Command, args []string) { + ctx := context.Background() + cfg := uri.AWSS3Config{ + Bucket: awsBucket, + AccessKeyID: awsAccessKeyID, + AccessKey: awsAccessKey, + Region: awsRegion, + } + sut, err := configapi.NewAttestationVersionRepo(ctx, cfg) + if err != nil { + panic(err) + } + versions := configapi.AzureSEVSNPVersion{ + Bootloader: bootloaderVersion, + TEE: teeVersion, + SNP: snpVersion, + Microcode: microcodeVersion, + } + + if err := sut.UploadAzureSEVSNP(ctx, versions, time.Now()); err != nil { + panic(err) + } else { + fmt.Println("Successfully uploaded version numbers", versions) + } + }, + } + myCmd.PersistentFlags().Uint8VarP(&bootloaderVersion, "bootloader-version", "b", invalidDefault, "Bootloader version number") + handleError(myCmd.MarkPersistentFlagRequired("bootloader-version")) + + myCmd.PersistentFlags().Uint8VarP(&teeVersion, "tee-version", "t", invalidDefault, "TEE version number") + handleError(myCmd.MarkPersistentFlagRequired("tee-version")) + + myCmd.PersistentFlags().Uint8VarP(&snpVersion, "snp-version", "s", invalidDefault, "SNP version number") + handleError(myCmd.MarkPersistentFlagRequired("snp-version")) + + myCmd.PersistentFlags().Uint8VarP(µcodeVersion, "microcode-version", "m", invalidDefault, "Microcode version number") + handleError(myCmd.MarkPersistentFlagRequired("microcode-version")) + + myCmd.PersistentFlags().StringVar(&awsAccessKeyID, "key-id", "", "ID of the Access key to use for AWS tests. Required for AWS KMS and storage test.") + handleError(myCmd.MarkPersistentFlagRequired("key-id")) + + myCmd.PersistentFlags().StringVar(&awsAccessKey, "key", "", "Access key to use for AWS tests. Required for AWS KMS and storage test.") + handleError(myCmd.MarkPersistentFlagRequired("key")) + handleError(myCmd.Execute()) +} diff --git a/image/upload/internal/cmd/BUILD.bazel b/image/upload/internal/cmd/BUILD.bazel index e2729b184..e89acc665 100644 --- a/image/upload/internal/cmd/BUILD.bazel +++ b/image/upload/internal/cmd/BUILD.bazel @@ -24,6 +24,7 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/image/upload/internal/cmd", visibility = ["//image/upload:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", "//internal/logger", @@ -36,7 +37,6 @@ go_library( "//internal/osimage/measurementsuploader", "//internal/osimage/nop", "//internal/osimage/secureboot", - "//internal/versionsapi", "@com_github_spf13_afero//:afero", "@com_github_spf13_cobra//:cobra", "@org_uber_go_zap//zapcore", diff --git a/image/upload/internal/cmd/api.go b/image/upload/internal/cmd/api.go index 6da36bd8c..5f6865998 100644 --- a/image/upload/internal/cmd/api.go +++ b/image/upload/internal/cmd/api.go @@ -10,8 +10,8 @@ import ( "context" "io" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/osimage" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) type archivist interface { diff --git a/image/upload/internal/cmd/flags.go b/image/upload/internal/cmd/flags.go index 59ec163e1..233e37a22 100644 --- a/image/upload/internal/cmd/flags.go +++ b/image/upload/internal/cmd/flags.go @@ -12,8 +12,8 @@ import ( "path/filepath" "time" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "github.com/spf13/cobra" "go.uber.org/zap/zapcore" ) diff --git a/image/upload/internal/cmd/info.go b/image/upload/internal/cmd/info.go index 43cf62830..ff7a10dad 100644 --- a/image/upload/internal/cmd/info.go +++ b/image/upload/internal/cmd/info.go @@ -11,9 +11,9 @@ import ( "fmt" "os" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/logger" infoupload "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "github.com/spf13/cobra" ) diff --git a/image/upload/internal/cmd/upload.go b/image/upload/internal/cmd/upload.go index fe6380f3e..2052d7069 100644 --- a/image/upload/internal/cmd/upload.go +++ b/image/upload/internal/cmd/upload.go @@ -13,8 +13,8 @@ import ( "io" "strings" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/osimage" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) func uploadImage(ctx context.Context, archiveC archivist, uploadC uploader, req *osimage.UploadRequest, out io.Writer) error { diff --git a/internal/api/configapi/BUILD.bazel b/internal/api/configapi/BUILD.bazel new file mode 100644 index 000000000..536e45bd2 --- /dev/null +++ b/internal/api/configapi/BUILD.bazel @@ -0,0 +1,36 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//bazel/go:go_test.bzl", "go_test") + +go_library( + name = "configapi", + srcs = [ + "attestation.go", + "attestationversion.go", + "configapi.go", + "repo.go", + ], + importpath = "github.com/edgelesssys/constellation/v2/internal/api/configapi", + visibility = ["//:__subpackages__"], + deps = [ + "//internal/constants", + "//internal/kms/storage", + "//internal/kms/storage/awss3", + "//internal/kms/uri", + "//internal/variant", + ], +) + +go_test( + name = "configapi_test", + srcs = [ + "attestationversion_test.go", + "repo_test.go", + ], + embed = [":configapi"], + deps = [ + "//internal/kms/uri", + "//internal/variant", + "@com_github_stretchr_testify//require", + "@in_gopkg_yaml_v3//:yaml_v3", + ], +) diff --git a/internal/api/configapi/attestation.go b/internal/api/configapi/attestation.go new file mode 100644 index 000000000..da348073d --- /dev/null +++ b/internal/api/configapi/attestation.go @@ -0,0 +1,99 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ +package configapi + +import ( + "fmt" + "net/url" + "path" + "strings" + + "github.com/edgelesssys/constellation/v2/internal/constants" + "github.com/edgelesssys/constellation/v2/internal/variant" +) + +// attestationURLPath is the URL path to the attestation versions. +const attestationURLPath = "constellation/v1/attestation" + +// AzureSEVSNPVersionType is the type of the version to be requested. +type AzureSEVSNPVersionType string + +// AzureSEVSNPVersion tracks the latest version of each component of the Azure SEVSNP. +type AzureSEVSNPVersion struct { + // Bootloader is the latest version of the Azure SEVSNP bootloader. + Bootloader uint8 `json:"bootloader"` + // TEE is the latest version of the Azure SEVSNP TEE. + TEE uint8 `json:"tee"` + // SNP is the latest version of the Azure SEVSNP SNP. + SNP uint8 `json:"snp"` + // Microcode is the latest version of the Azure SEVSNP microcode. + Microcode uint8 `json:"microcode"` +} + +// AzureSEVSNPVersionGet is the request to get the version information of the specific version in the config api. +type AzureSEVSNPVersionGet struct { + Version string `json:"-"` + AzureSEVSNPVersion +} + +// URL returns the URL for the request to the config api. +func (i AzureSEVSNPVersionGet) URL() (string, error) { + url, err := url.Parse(constants.CDNRepositoryURL) + if err != nil { + return "", fmt.Errorf("parsing CDN URL: %w", err) + } + url.Path = i.JSONPath() + return url.String(), nil +} + +// JSONPath returns the path to the JSON file for the request to the config api. +func (i AzureSEVSNPVersionGet) JSONPath() string { + return path.Join(attestationURLPath, variant.AzureSEVSNP{}.String(), i.Version) +} + +// ValidateRequest validates the request. +func (i AzureSEVSNPVersionGet) 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 AzureSEVSNPVersionGet) Validate() error { + return nil +} + +// AzureSEVSNPVersionList is the request to list all versions in the config api. +type AzureSEVSNPVersionList []string + +// URL returns the URL for the request to the config api. +func (i AzureSEVSNPVersionList) URL() (string, error) { + url, err := url.Parse(constants.CDNRepositoryURL) + if err != nil { + return "", fmt.Errorf("parsing CDN URL: %w", err) + } + url.Path = i.JSONPath() + return url.String(), nil +} + +// JSONPath returns the path to the JSON file for the request to the config api. +func (i AzureSEVSNPVersionList) JSONPath() string { + return path.Join(attestationURLPath, variant.AzureSEVSNP{}.String(), "list") +} + +// ValidateRequest is a NoOp as there is no input. +func (i AzureSEVSNPVersionList) ValidateRequest() error { + return nil +} + +// Validate validates the response. +func (i AzureSEVSNPVersionList) Validate() error { + if len(i) < 1 { + return fmt.Errorf("no versions found in /list") + } + return nil +} diff --git a/internal/api/configapi/attestationversion.go b/internal/api/configapi/attestationversion.go new file mode 100644 index 000000000..c7d3bc4bc --- /dev/null +++ b/internal/api/configapi/attestationversion.go @@ -0,0 +1,81 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package configapi + +import ( + "encoding/json" + "fmt" + "strings" +) + +const placeholderVersionValue = 0 + +// NewLatestPlaceholderVersion returns the latest version with a placeholder version value. +func NewLatestPlaceholderVersion() AttestationVersion { + return AttestationVersion{ + Value: placeholderVersionValue, + IsLatest: true, + } +} + +// AttestationVersion is a type that represents a version of a SNP. +type AttestationVersion struct { + Value uint8 + IsLatest bool +} + +// MarshalYAML implements a custom marshaller to resolve "latest" values. +func (v AttestationVersion) MarshalYAML() (any, error) { + if v.IsLatest { + return "latest", nil + } + return v.Value, nil +} + +// UnmarshalYAML implements a custom unmarshaller to resolve "atest" values. +func (v *AttestationVersion) UnmarshalYAML(unmarshal func(any) error) error { + var rawUnmarshal any + if err := unmarshal(&rawUnmarshal); err != nil { + return fmt.Errorf("raw unmarshal: %w", err) + } + + return v.parseRawUnmarshal(rawUnmarshal) +} + +// MarshalJSON implements a custom marshaller to resolve "latest" values. +func (v AttestationVersion) MarshalJSON() ([]byte, error) { + if v.IsLatest { + return json.Marshal("latest") + } + return json.Marshal(v.Value) +} + +// UnmarshalJSON implements a custom unmarshaller to resolve "latest" values. +func (v *AttestationVersion) UnmarshalJSON(data []byte) (err error) { + var rawUnmarshal any + if err := json.Unmarshal(data, &rawUnmarshal); err != nil { + return fmt.Errorf("raw unmarshal: %w", err) + } + return v.parseRawUnmarshal(rawUnmarshal) +} + +func (v *AttestationVersion) parseRawUnmarshal(rawUnmarshal any) error { + switch s := rawUnmarshal.(type) { + case string: + if strings.ToLower(s) == "latest" { + v.IsLatest = true + v.Value = placeholderVersionValue + } else { + return fmt.Errorf("invalid version value: %s", s) + } + case int: + v.Value = uint8(s) + default: + return fmt.Errorf("invalid version value type: %s", s) + } + return nil +} diff --git a/internal/api/configapi/attestationversion_test.go b/internal/api/configapi/attestationversion_test.go new file mode 100644 index 000000000..a5d2136a1 --- /dev/null +++ b/internal/api/configapi/attestationversion_test.go @@ -0,0 +1,46 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package configapi + +import ( + "testing" + + "github.com/stretchr/testify/require" + "gopkg.in/yaml.v3" +) + +func TestVersionMarshalYAML(t *testing.T) { + tests := []struct { + name string + sut AttestationVersion + want string + }{ + { + name: "isLatest resolves to latest", + sut: AttestationVersion{ + Value: 1, + IsLatest: true, + }, + want: "latest\n", + }, + { + name: "value 5 resolves to 5", + sut: AttestationVersion{ + Value: 5, + IsLatest: false, + }, + want: "5\n", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + bt, err := yaml.Marshal(tt.sut) + require.NoError(t, err) + require.Equal(t, tt.want, string(bt)) + }) + } +} diff --git a/internal/api/configapi/configapi.go b/internal/api/configapi/configapi.go new file mode 100644 index 000000000..4b5d201c1 --- /dev/null +++ b/internal/api/configapi/configapi.go @@ -0,0 +1,20 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +/* +# Config API + +The Config API provides information about versions of Constellation components. + +This package defines API types that represents objects of the config API. +The types provide helper methods for validation and commonly used operations on the +information contained in the objects. Especially the paths used for the API are defined +in these helper methods. + +The package also provides helper functions that can be used in context of the config API, +e.g. to validate versions. +*/ +package configapi diff --git a/internal/api/configapi/repo.go b/internal/api/configapi/repo.go new file mode 100644 index 000000000..c23bbec41 --- /dev/null +++ b/internal/api/configapi/repo.go @@ -0,0 +1,96 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ +package configapi + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "path" + "sort" + "time" + + "github.com/edgelesssys/constellation/v2/internal/kms/storage" + "github.com/edgelesssys/constellation/v2/internal/kms/storage/awss3" + "github.com/edgelesssys/constellation/v2/internal/kms/uri" + "github.com/edgelesssys/constellation/v2/internal/variant" +) + +// AttestationVersionRepo manages (modifies) the version information for the attestation variants. +type AttestationVersionRepo struct { + *awss3.Storage +} + +// NewAttestationVersionRepo returns a new AttestationVersionRepo. +func NewAttestationVersionRepo(ctx context.Context, cfg uri.AWSS3Config) (*AttestationVersionRepo, error) { + s3, err := awss3.New(ctx, cfg) + if err != nil { + return nil, fmt.Errorf("failed to create s3 storage: %w", err) + } + return &AttestationVersionRepo{s3}, nil +} + +// UploadAzureSEVSNP uploads the latest version numbers of the Azure SEVSNP. +func (a AttestationVersionRepo) UploadAzureSEVSNP(ctx context.Context, versions AzureSEVSNPVersion, date time.Time) error { + bt, err := json.Marshal(versions) + if err != nil { + return err + } + variant := variant.AzureSEVSNP{} + fname := date.Format("2006-01-02-15-04") + ".json" + + err = a.Put(ctx, fmt.Sprintf("%s/%s/%s", attestationURLPath, variant.String(), fname), bt) + if err != nil { + return err + } + return a.addVersionToList(ctx, variant, fname) +} + +// List returns the list of versions for the given attestation type. +func (a AttestationVersionRepo) List(ctx context.Context, attestation variant.Variant) ([]string, error) { + key := path.Join(attestationURLPath, attestation.String(), "list") + bt, err := a.Get(ctx, key) + if err != nil { + return nil, err + } + var versions []string + if err := json.Unmarshal(bt, &versions); err != nil { + return nil, err + } + return versions, nil +} + +// DeleteList empties the list of versions for the given attestation type. +func (a AttestationVersionRepo) DeleteList(ctx context.Context, attestation variant.Variant) error { + versions := []string{} + bt, err := json.Marshal(&versions) + if err != nil { + return err + } + return a.Put(ctx, path.Join(attestationURLPath, attestation.String(), "list"), bt) +} + +func (a AttestationVersionRepo) addVersionToList(ctx context.Context, attestation variant.Variant, fname string) error { + versions := []string{} + key := path.Join(attestationURLPath, attestation.String(), "list") + bt, err := a.Get(ctx, key) + if err == nil { + if err := json.Unmarshal(bt, &versions); err != nil { + return err + } + } else if !errors.Is(err, storage.ErrDEKUnset) { + return err + } + versions = append(versions, fname) + versions = variant.RemoveDuplicate(versions) + sort.Sort(sort.Reverse(sort.StringSlice(versions))) + json, err := json.Marshal(versions) + if err != nil { + return err + } + return a.Put(ctx, key, json) +} diff --git a/internal/api/configapi/repo_test.go b/internal/api/configapi/repo_test.go new file mode 100644 index 000000000..f1c939986 --- /dev/null +++ b/internal/api/configapi/repo_test.go @@ -0,0 +1,85 @@ +//go:build e2e + +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ +package configapi_test + +import ( + "context" + "flag" + "fmt" + "os" + "testing" + "time" + + "github.com/edgelesssys/constellation/v2/internal/api/configapi" + "github.com/edgelesssys/constellation/v2/internal/kms/uri" + "github.com/edgelesssys/constellation/v2/internal/variant" + "github.com/stretchr/testify/require" +) + +var ( + awsRegion = flag.String("aws-region", "us-east-1", "Region to use for AWS tests. Required for AWS KMS test.") + awsAccessKeyID = flag.String("aws-access-key-id", "", "ID of the Access key to use for AWS tests. Required for AWS KMS and storage test.") + awsAccessKey = flag.String("aws-access-key", "", "Access key to use for AWS tests. Required for AWS KMS and storage test.") + awsBucket = flag.String("aws-bucket", "", "Name of the S3 bucket to use for AWS storage test. Required for AWS storage test.") +) + +func TestMain(m *testing.M) { + flag.Parse() + if *awsAccessKey == "" || *awsAccessKeyID == "" || *awsBucket == "" || *awsRegion == "" { + flag.Usage() + fmt.Println("Required flags not set: --aws-access-key, --aws-access-key-id, --aws-bucket, --aws-region. Skipping tests.") + os.Exit(0) + } + os.Exit(m.Run()) +} + +var cfg = uri.AWSS3Config{ + Bucket: *awsBucket, + AccessKeyID: *awsAccessKeyID, + AccessKey: *awsAccessKey, + Region: *awsRegion, +} + +var versionValues = configapi.AzureSEVSNPVersion{ + Bootloader: 2, + TEE: 0, + SNP: 6, + Microcode: 93, +} + +func TestUploadAzureSEVSNPVersions(t *testing.T) { + ctx := context.Background() + sut, err := configapi.NewAttestationVersionRepo(ctx, cfg) + require.NoError(t, err) + d := time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC) + require.NoError(t, sut.UploadAzureSEVSNP(ctx, versionValues, d)) +} + +func TestListVersions(t *testing.T) { + ctx := context.Background() + + sut, err := configapi.NewAttestationVersionRepo(ctx, cfg) + require.NoError(t, err) + + err = sut.DeleteList(ctx, variant.AzureSEVSNP{}) + require.NoError(t, err) + + res, err := sut.List(ctx, variant.AzureSEVSNP{}) + require.NoError(t, err) + require.Equal(t, []string{}, res) + + d := time.Date(2021, 1, 1, 1, 1, 1, 1, time.UTC) + err = sut.UploadAzureSEVSNP(ctx, versionValues, d) + require.NoError(t, err) + res, err = sut.List(ctx, variant.AzureSEVSNP{}) + require.NoError(t, err) + require.Equal(t, []string{"2021-01-01-01-01.json"}, res) + + err = sut.DeleteList(ctx, variant.AzureSEVSNP{}) + require.NoError(t, err) +} diff --git a/internal/versionsapi/fetcher/BUILD.bazel b/internal/api/fetcher/BUILD.bazel similarity index 56% rename from internal/versionsapi/fetcher/BUILD.bazel rename to internal/api/fetcher/BUILD.bazel index 5e80f1b29..b04641cb2 100644 --- a/internal/versionsapi/fetcher/BUILD.bazel +++ b/internal/api/fetcher/BUILD.bazel @@ -3,18 +3,29 @@ load("//bazel/go:go_test.bzl", "go_test") go_library( name = "fetcher", - srcs = ["fetcher.go"], - importpath = "github.com/edgelesssys/constellation/v2/internal/versionsapi/fetcher", + srcs = [ + "configapi.go", + "fetcher.go", + "versionapi.go", + ], + importpath = "github.com/edgelesssys/constellation/v2/internal/api/fetcher", visibility = ["//:__subpackages__"], - deps = ["//internal/versionsapi"], + deps = [ + "//internal/api/configapi", + "//internal/api/versionsapi", + ], ) go_test( name = "fetcher_test", - srcs = ["fetcher_test.go"], + srcs = [ + "configapi_test.go", + "versionapi_test.go", + ], embed = [":fetcher"], deps = [ - "//internal/versionsapi", + "//internal/api/configapi", + "//internal/api/versionsapi", "@com_github_stretchr_testify//assert", "@com_github_stretchr_testify//require", "@org_uber_go_goleak//:goleak", diff --git a/internal/api/fetcher/configapi.go b/internal/api/fetcher/configapi.go new file mode 100644 index 000000000..c32ae407a --- /dev/null +++ b/internal/api/fetcher/configapi.go @@ -0,0 +1,55 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package fetcher + +import ( + "context" + "fmt" + + "github.com/edgelesssys/constellation/v2/internal/api/configapi" +) + +// ConfigAPIFetcher fetches config API resources without authentication. +type ConfigAPIFetcher struct { + *fetcher +} + +// NewConfigAPIFetcher returns a new Fetcher. +func NewConfigAPIFetcher() *ConfigAPIFetcher { + return &ConfigAPIFetcher{newFetcher()} +} + +// NewConfigAPIFetcherWithClient returns a new Fetcher with custom http client. +func NewConfigAPIFetcherWithClient(client HTTPClient) *ConfigAPIFetcher { + return &ConfigAPIFetcher{newFetcherWith(client)} +} + +// FetchAzureSEVSNPVersionList fetches the version list information from the config API. +func (f *ConfigAPIFetcher) FetchAzureSEVSNPVersionList(ctx context.Context, attestation configapi.AzureSEVSNPVersionList) (configapi.AzureSEVSNPVersionList, error) { + return fetch(ctx, f.httpc, attestation) +} + +// FetchAzureSEVSNPVersion fetches the version information from the config API. +func (f *ConfigAPIFetcher) FetchAzureSEVSNPVersion(ctx context.Context, attestation configapi.AzureSEVSNPVersionGet) (configapi.AzureSEVSNPVersionGet, error) { + // TODO(elchead): follow-up PR for AB#3045 to check signature (sigstore.VerifySignature) + return fetch(ctx, f.httpc, attestation) +} + +// FetchLatestAzureSEVSNPVersion returns the latest versions of the given type. +func (f *ConfigAPIFetcher) FetchLatestAzureSEVSNPVersion(ctx context.Context) (res configapi.AzureSEVSNPVersion, err error) { + var versions configapi.AzureSEVSNPVersionList + versions, err = f.FetchAzureSEVSNPVersionList(ctx, versions) + if err != nil { + return res, fmt.Errorf("fetching versions list: %w", err) + } + get := configapi.AzureSEVSNPVersionGet{Version: versions[0]} // get latest version (as sorted reversely alphanumerically) + get, err = f.FetchAzureSEVSNPVersion(ctx, get) + if err != nil { + return res, fmt.Errorf("failed fetching version: %w", err) + } + return get.AzureSEVSNPVersion, nil +} diff --git a/internal/api/fetcher/configapi_test.go b/internal/api/fetcher/configapi_test.go new file mode 100644 index 000000000..3c9446d0f --- /dev/null +++ b/internal/api/fetcher/configapi_test.go @@ -0,0 +1,65 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ +package fetcher + +import ( + "bytes" + "context" + "encoding/json" + "errors" + "io" + "net/http" + "testing" + + "github.com/edgelesssys/constellation/v2/internal/api/configapi" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetVersion(t *testing.T) { + client := &http.Client{ + Transport: &fakeConfigAPIHandler{}, + } + fetcher := NewConfigAPIFetcherWithClient(client) + res, err := fetcher.FetchLatestAzureSEVSNPVersion(context.Background()) + require.NoError(t, err) + assert.Equal(t, uint8(2), res.Bootloader) +} + +type fakeConfigAPIHandler struct{} + +// RoundTrip resolves the request and returns a dummy response. +func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, error) { + if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/list" { + res := &http.Response{} + data := []string{"2021-01-01-01-01.json"} + bt, err := json.Marshal(data) + if err != nil { + return nil, err + } + res.Body = io.NopCloser(bytes.NewReader(bt)) + res.Header = http.Header{} + res.Header.Set("Content-Type", "application/json") + res.StatusCode = http.StatusOK + return res, nil + } else if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/2021-01-01-01-01.json" { + res := &http.Response{} + bt, err := json.Marshal(configapi.AzureSEVSNPVersion{ + Microcode: 93, + TEE: 0, + SNP: 6, + Bootloader: 2, + }) + if err != nil { + return nil, err + } + res.Body = io.NopCloser(bytes.NewReader(bt)) + res.StatusCode = http.StatusOK + return res, nil + + } + return nil, errors.New("no endpoint found") +} diff --git a/internal/versionsapi/fetcher/fetcher.go b/internal/api/fetcher/fetcher.go similarity index 61% rename from internal/versionsapi/fetcher/fetcher.go rename to internal/api/fetcher/fetcher.go index 930e4eebc..609f00720 100644 --- a/internal/versionsapi/fetcher/fetcher.go +++ b/internal/api/fetcher/fetcher.go @@ -18,40 +18,26 @@ import ( "encoding/json" "fmt" "net/http" - - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) -// Fetcher fetches versions API resources without authentication. -type Fetcher struct { - httpc httpc +// fetcher fetches versions API resources without authentication. +type fetcher struct { + httpc HTTPClient } -// NewFetcher returns a new Fetcher. -func NewFetcher() *Fetcher { - return &Fetcher{ - httpc: http.DefaultClient, +// NewHTTPClient returns a new http client. +func NewHTTPClient() HTTPClient { + return &http.Client{Transport: &http.Transport{DisableKeepAlives: true}} // DisableKeepAlives fixes concurrency issue see https://stackoverflow.com/a/75816347 +} + +func newFetcherWith(client HTTPClient) *fetcher { + return &fetcher{ + httpc: client, } } -// FetchVersionList fetches the given version list from the versions API. -func (f *Fetcher) FetchVersionList(ctx context.Context, list versionsapi.List) (versionsapi.List, error) { - return fetch(ctx, f.httpc, list) -} - -// FetchVersionLatest fetches the latest version from the versions API. -func (f *Fetcher) FetchVersionLatest(ctx context.Context, latest versionsapi.Latest) (versionsapi.Latest, error) { - return fetch(ctx, f.httpc, latest) -} - -// FetchImageInfo fetches the given image info from the versions API. -func (f *Fetcher) FetchImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error) { - return fetch(ctx, f.httpc, imageInfo) -} - -// FetchCLIInfo fetches the given cli info from the versions API. -func (f *Fetcher) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) { - return fetch(ctx, f.httpc, cliInfo) +func newFetcher() *fetcher { + return newFetcherWith(NewHTTPClient()) // DisableKeepAlives fixes concurrency issue see https://stackoverflow.com/a/75816347 } type apiObject interface { @@ -60,7 +46,7 @@ type apiObject interface { URL() (string, error) } -func fetch[T apiObject](ctx context.Context, c httpc, obj T) (T, error) { +func fetch[T apiObject](ctx context.Context, c HTTPClient, obj T) (T, error) { if err := obj.ValidateRequest(); err != nil { return *new(T), fmt.Errorf("validating request for %T: %w", obj, err) } @@ -113,6 +99,7 @@ func (e *NotFoundError) Unwrap() error { return e.err } -type httpc interface { +// HTTPClient is an interface for http clients. +type HTTPClient interface { Do(req *http.Request) (*http.Response, error) } diff --git a/internal/api/fetcher/versionapi.go b/internal/api/fetcher/versionapi.go new file mode 100644 index 000000000..8fb0d0ef8 --- /dev/null +++ b/internal/api/fetcher/versionapi.go @@ -0,0 +1,43 @@ +/* +Copyright (c) Edgeless Systems GmbH + +SPDX-License-Identifier: AGPL-3.0-only +*/ + +package fetcher + +import ( + "context" + + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" +) + +// VersionAPIFetcher fetches version API resources without authentication. +type VersionAPIFetcher struct { + *fetcher +} + +// NewVersionAPIFetcher returns a new Fetcher. +func NewVersionAPIFetcher() *VersionAPIFetcher { + return &VersionAPIFetcher{newFetcher()} +} + +// FetchVersionList fetches the given version list from the versions API. +func (f *VersionAPIFetcher) FetchVersionList(ctx context.Context, list versionsapi.List) (versionsapi.List, error) { + return fetch(ctx, f.httpc, list) +} + +// FetchVersionLatest fetches the latest version from the versions API. +func (f *VersionAPIFetcher) FetchVersionLatest(ctx context.Context, latest versionsapi.Latest) (versionsapi.Latest, error) { + return fetch(ctx, f.httpc, latest) +} + +// FetchImageInfo fetches the given image info from the versions API. +func (f *VersionAPIFetcher) FetchImageInfo(ctx context.Context, imageInfo versionsapi.ImageInfo) (versionsapi.ImageInfo, error) { + return fetch(ctx, f.httpc, imageInfo) +} + +// FetchCLIInfo fetches the given cli info from the versions API. +func (f *VersionAPIFetcher) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) (versionsapi.CLIInfo, error) { + return fetch(ctx, f.httpc, cliInfo) +} diff --git a/internal/versionsapi/fetcher/fetcher_test.go b/internal/api/fetcher/versionapi_test.go similarity index 97% rename from internal/versionsapi/fetcher/fetcher_test.go rename to internal/api/fetcher/versionapi_test.go index 15999ce49..af2d5da67 100644 --- a/internal/versionsapi/fetcher/fetcher_test.go +++ b/internal/api/fetcher/versionapi_test.go @@ -14,7 +14,7 @@ import ( "net/http" "testing" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/goleak" @@ -190,7 +190,7 @@ func TestFetchVersionList(t *testing.T) { return tc.serverResp }) - fetcher := &Fetcher{httpc: client} + fetcher := VersionAPIFetcher{&fetcher{httpc: client}} list, err := fetcher.FetchVersionList(context.Background(), tc.list) diff --git a/internal/versionsapi/BUILD.bazel b/internal/api/versionsapi/BUILD.bazel similarity index 97% rename from internal/versionsapi/BUILD.bazel rename to internal/api/versionsapi/BUILD.bazel index 466ab3b62..803aa5637 100644 --- a/internal/versionsapi/BUILD.bazel +++ b/internal/api/versionsapi/BUILD.bazel @@ -12,7 +12,7 @@ go_library( "version.go", "versionsapi.go", ], - importpath = "github.com/edgelesssys/constellation/v2/internal/versionsapi", + importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi", visibility = ["//:__subpackages__"], deps = [ "//internal/constants", diff --git a/internal/versionsapi/apiconstants.go b/internal/api/versionsapi/apiconstants.go similarity index 100% rename from internal/versionsapi/apiconstants.go rename to internal/api/versionsapi/apiconstants.go diff --git a/internal/versionsapi/cli/BUILD.bazel b/internal/api/versionsapi/cli/BUILD.bazel similarity index 91% rename from internal/versionsapi/cli/BUILD.bazel rename to internal/api/versionsapi/cli/BUILD.bazel index 255ced3c2..50d952a8b 100644 --- a/internal/versionsapi/cli/BUILD.bazel +++ b/internal/api/versionsapi/cli/BUILD.bazel @@ -9,12 +9,12 @@ go_library( "main.go", "rm.go", ], - importpath = "github.com/edgelesssys/constellation/v2/internal/versionsapi/cli", + importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/cli", visibility = ["//visibility:private"], deps = [ + "//internal/api/versionsapi", + "//internal/api/versionsapi/client", "//internal/logger", - "//internal/versionsapi", - "//internal/versionsapi/client", "@com_github_aws_aws_sdk_go_v2_config//:config", "@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2", "@com_github_aws_smithy_go//:smithy-go", diff --git a/internal/versionsapi/cli/add.go b/internal/api/versionsapi/cli/add.go similarity index 98% rename from internal/versionsapi/cli/add.go rename to internal/api/versionsapi/cli/add.go index e07e576ec..f1df7a25d 100644 --- a/internal/versionsapi/cli/add.go +++ b/internal/api/versionsapi/cli/add.go @@ -11,9 +11,9 @@ import ( "errors" "fmt" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" + verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - verclient "github.com/edgelesssys/constellation/v2/internal/versionsapi/client" "github.com/spf13/cobra" "go.uber.org/zap/zapcore" "golang.org/x/mod/semver" diff --git a/internal/versionsapi/cli/latest.go b/internal/api/versionsapi/cli/latest.go similarity index 95% rename from internal/versionsapi/cli/latest.go rename to internal/api/versionsapi/cli/latest.go index 437cafcb0..03af7ab83 100644 --- a/internal/versionsapi/cli/latest.go +++ b/internal/api/versionsapi/cli/latest.go @@ -10,9 +10,9 @@ import ( "encoding/json" "fmt" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" + verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - verclient "github.com/edgelesssys/constellation/v2/internal/versionsapi/client" "github.com/spf13/cobra" "go.uber.org/zap/zapcore" ) diff --git a/internal/versionsapi/cli/list.go b/internal/api/versionsapi/cli/list.go similarity index 97% rename from internal/versionsapi/cli/list.go rename to internal/api/versionsapi/cli/list.go index 97c07d32b..d9fcc4139 100644 --- a/internal/versionsapi/cli/list.go +++ b/internal/api/versionsapi/cli/list.go @@ -16,9 +16,9 @@ import ( "go.uber.org/zap/zapcore" "golang.org/x/mod/semver" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" + verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - verclient "github.com/edgelesssys/constellation/v2/internal/versionsapi/client" ) func newListCmd() *cobra.Command { diff --git a/internal/versionsapi/cli/main.go b/internal/api/versionsapi/cli/main.go similarity index 100% rename from internal/versionsapi/cli/main.go rename to internal/api/versionsapi/cli/main.go diff --git a/internal/versionsapi/cli/rm.go b/internal/api/versionsapi/cli/rm.go similarity index 99% rename from internal/versionsapi/cli/rm.go rename to internal/api/versionsapi/cli/rm.go index 1e4e4e69e..8d85db959 100644 --- a/internal/versionsapi/cli/rm.go +++ b/internal/api/versionsapi/cli/rm.go @@ -24,9 +24,9 @@ import ( awsconfig "github.com/aws/aws-sdk-go-v2/config" "github.com/aws/aws-sdk-go-v2/service/ec2" "github.com/aws/smithy-go" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" + verclient "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - verclient "github.com/edgelesssys/constellation/v2/internal/versionsapi/client" gaxv2 "github.com/googleapis/gax-go/v2" "github.com/spf13/cobra" "go.uber.org/zap/zapcore" diff --git a/internal/versionsapi/client/BUILD.bazel b/internal/api/versionsapi/client/BUILD.bazel similarity index 92% rename from internal/versionsapi/client/BUILD.bazel rename to internal/api/versionsapi/client/BUILD.bazel index 67970662b..521ddc3d4 100644 --- a/internal/versionsapi/client/BUILD.bazel +++ b/internal/api/versionsapi/client/BUILD.bazel @@ -3,12 +3,12 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "client", srcs = ["client.go"], - importpath = "github.com/edgelesssys/constellation/v2/internal/versionsapi/client", + importpath = "github.com/edgelesssys/constellation/v2/internal/api/versionsapi/client", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/constants", "//internal/logger", - "//internal/versionsapi", "@com_github_aws_aws_sdk_go_v2//aws", "@com_github_aws_aws_sdk_go_v2_config//:config", "@com_github_aws_aws_sdk_go_v2_feature_s3_manager//:manager", diff --git a/internal/versionsapi/client/client.go b/internal/api/versionsapi/client/client.go similarity index 99% rename from internal/versionsapi/client/client.go rename to internal/api/versionsapi/client/client.go index 4519afc57..3c20d921c 100644 --- a/internal/versionsapi/client/client.go +++ b/internal/api/versionsapi/client/client.go @@ -42,9 +42,9 @@ import ( s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "golang.org/x/mod/semver" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Client is the client for the versions API. diff --git a/internal/versionsapi/cliinfo.go b/internal/api/versionsapi/cliinfo.go similarity index 100% rename from internal/versionsapi/cliinfo.go rename to internal/api/versionsapi/cliinfo.go diff --git a/internal/versionsapi/cliinfo_test.go b/internal/api/versionsapi/cliinfo_test.go similarity index 100% rename from internal/versionsapi/cliinfo_test.go rename to internal/api/versionsapi/cliinfo_test.go diff --git a/internal/versionsapi/imageinfo.go b/internal/api/versionsapi/imageinfo.go similarity index 100% rename from internal/versionsapi/imageinfo.go rename to internal/api/versionsapi/imageinfo.go diff --git a/internal/versionsapi/imageinfo_test.go b/internal/api/versionsapi/imageinfo_test.go similarity index 100% rename from internal/versionsapi/imageinfo_test.go rename to internal/api/versionsapi/imageinfo_test.go diff --git a/internal/versionsapi/latest.go b/internal/api/versionsapi/latest.go similarity index 100% rename from internal/versionsapi/latest.go rename to internal/api/versionsapi/latest.go diff --git a/internal/versionsapi/latest_test.go b/internal/api/versionsapi/latest_test.go similarity index 100% rename from internal/versionsapi/latest_test.go rename to internal/api/versionsapi/latest_test.go diff --git a/internal/versionsapi/list.go b/internal/api/versionsapi/list.go similarity index 100% rename from internal/versionsapi/list.go rename to internal/api/versionsapi/list.go diff --git a/internal/versionsapi/list_test.go b/internal/api/versionsapi/list_test.go similarity index 100% rename from internal/versionsapi/list_test.go rename to internal/api/versionsapi/list_test.go diff --git a/internal/versionsapi/version.go b/internal/api/versionsapi/version.go similarity index 100% rename from internal/versionsapi/version.go rename to internal/api/versionsapi/version.go diff --git a/internal/versionsapi/version_test.go b/internal/api/versionsapi/version_test.go similarity index 100% rename from internal/versionsapi/version_test.go rename to internal/api/versionsapi/version_test.go diff --git a/internal/versionsapi/versionsapi.go b/internal/api/versionsapi/versionsapi.go similarity index 85% rename from internal/versionsapi/versionsapi.go rename to internal/api/versionsapi/versionsapi.go index 20ce5a67e..54fa65123 100644 --- a/internal/versionsapi/versionsapi.go +++ b/internal/api/versionsapi/versionsapi.go @@ -7,7 +7,7 @@ SPDX-License-Identifier: AGPL-3.0-only /* # Versions API -The Versions API is a provides information about versions of Constellation components. +The Versions API provides information about versions of Constellation components. This package defines API types that represents objects of the versions API. The types provide helper methods for validation and commonly used operations on the diff --git a/internal/attestation/azure/snp/validator.go b/internal/attestation/azure/snp/validator.go index f1f85fbfe..40a40d15e 100644 --- a/internal/attestation/azure/snp/validator.go +++ b/internal/attestation/azure/snp/validator.go @@ -148,7 +148,7 @@ func (v *Validator) validateSNPReport( return errDebugEnabled } - if !report.CommittedTCB.isVersion(v.config.BootloaderVersion, v.config.TEEVersion, v.config.SNPVersion, v.config.MicrocodeVersion) { + if !report.CommittedTCB.isVersion(v.config.BootloaderVersion.Value, v.config.TEEVersion.Value, v.config.SNPVersion.Value, v.config.MicrocodeVersion.Value) { return &versionError{"COMMITTED_TCB", report.CommittedTCB} } if report.LaunchTCB != report.CommittedTCB { diff --git a/internal/attestation/azure/snp/validator_test.go b/internal/attestation/azure/snp/validator_test.go index 8751b0d70..4c8ca8887 100644 --- a/internal/attestation/azure/snp/validator_test.go +++ b/internal/attestation/azure/snp/validator_test.go @@ -348,7 +348,7 @@ func TestNewSNPReportFromBytes(t *testing.T) { wantErr: true, }, } - + cfg := config.DefaultForAzureSEVSNP() for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) @@ -363,8 +363,7 @@ func TestNewSNPReportFromBytes(t *testing.T) { assert.NotNil(report) assert.Equal(hex.EncodeToString(report.IDKeyDigest[:]), "57e229e0ffe5fa92d0faddff6cae0e61c926fc9ef9afd20a8b8cfcf7129db9338cbe5bf3f6987733a2bf65d06dc38fc1") // This is a canary for us: If this fails in the future we possibly downgraded a SVN. - cfg := config.DefaultForAzureSEVSNP() - assert.True(report.LaunchTCB.isVersion(cfg.BootloaderVersion, cfg.TEEVersion, cfg.SNPVersion, cfg.MicrocodeVersion)) + assert.True(report.LaunchTCB.isVersion(cfg.BootloaderVersion.Value, cfg.TEEVersion.Value, cfg.SNPVersion.Value, cfg.MicrocodeVersion.Value)) } }) } diff --git a/internal/attestation/measurements/BUILD.bazel b/internal/attestation/measurements/BUILD.bazel index 44c172a45..1f0203feb 100644 --- a/internal/attestation/measurements/BUILD.bazel +++ b/internal/attestation/measurements/BUILD.bazel @@ -13,10 +13,10 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/cloud/cloudprovider", "//internal/sigstore", "//internal/variant", - "//internal/versionsapi", "@com_github_google_go_tpm//tpmutil", "@com_github_siderolabs_talos_pkg_machinery//config/encoder", "@in_gopkg_yaml_v3//:yaml_v3", @@ -28,9 +28,9 @@ go_test( srcs = ["measurements_test.go"], embed = [":measurements"], deps = [ + "//internal/api/versionsapi", "//internal/cloud/cloudprovider", "//internal/variant", - "//internal/versionsapi", "@com_github_siderolabs_talos_pkg_machinery//config/encoder", "@com_github_stretchr_testify//assert", "@com_github_stretchr_testify//require", diff --git a/internal/attestation/measurements/measurement-generator/BUILD.bazel b/internal/attestation/measurements/measurement-generator/BUILD.bazel index 2e5b3e905..b8bb0137c 100644 --- a/internal/attestation/measurements/measurement-generator/BUILD.bazel +++ b/internal/attestation/measurements/measurement-generator/BUILD.bazel @@ -7,13 +7,13 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/attestation/measurements/measurement-generator", visibility = ["//visibility:private"], deps = [ + "//internal/api/versionsapi", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", "//internal/config", "//internal/constants", "//internal/sigstore", "//internal/variant", - "//internal/versionsapi", "@org_golang_x_tools//go/ast/astutil", ], ) diff --git a/internal/attestation/measurements/measurement-generator/generate.go b/internal/attestation/measurements/measurement-generator/generate.go index 544062adc..6cb44e1da 100644 --- a/internal/attestation/measurements/measurement-generator/generate.go +++ b/internal/attestation/measurements/measurement-generator/generate.go @@ -23,13 +23,13 @@ import ( "sort" "strings" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/sigstore" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "golang.org/x/tools/go/ast/astutil" ) diff --git a/internal/attestation/measurements/measurements.go b/internal/attestation/measurements/measurements.go index a5bde8951..75538af75 100644 --- a/internal/attestation/measurements/measurements.go +++ b/internal/attestation/measurements/measurements.go @@ -32,10 +32,10 @@ import ( "github.com/siderolabs/talos/pkg/machinery/config/encoder" "gopkg.in/yaml.v3" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/sigstore" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) const ( diff --git a/internal/attestation/measurements/measurements_test.go b/internal/attestation/measurements/measurements_test.go index 3a8d9e741..8b1bb36d4 100644 --- a/internal/attestation/measurements/measurements_test.go +++ b/internal/attestation/measurements/measurements_test.go @@ -20,9 +20,9 @@ import ( "github.com/stretchr/testify/require" "gopkg.in/yaml.v3" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) func TestMarshal(t *testing.T) { diff --git a/internal/config/BUILD.bazel b/internal/config/BUILD.bazel index cfd4ed8f1..61bbcb710 100644 --- a/internal/config/BUILD.bazel +++ b/internal/config/BUILD.bazel @@ -18,18 +18,19 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/config", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/configapi", + "//internal/api/fetcher", + "//internal/api/versionsapi", "//internal/attestation/idkeydigest", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", "//internal/compatibility", "//internal/config/imageversion", "//internal/config/instancetypes", - "//internal/config/snpversion", "//internal/constants", "//internal/file", "//internal/variant", "//internal/versions", - "//internal/versionsapi", "@com_github_go_playground_locales//en", "@com_github_go_playground_universal_translator//:universal-translator", "@com_github_go_playground_validator_v10//:validator", @@ -49,6 +50,7 @@ go_test( data = glob(["testdata/**"]), embed = [":config"], deps = [ + "//internal/api/configapi", "//internal/attestation/measurements", "//internal/cloud/cloudprovider", "//internal/config/instancetypes", diff --git a/internal/config/azure.go b/internal/config/azure.go index 23c31762d..b6a1640a9 100644 --- a/internal/config/azure.go +++ b/internal/config/azure.go @@ -8,14 +8,14 @@ package config import ( "bytes" + "context" "fmt" - "strconv" - "strings" + "github.com/edgelesssys/constellation/v2/internal/api/configapi" + "github.com/edgelesssys/constellation/v2/internal/api/fetcher" "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" - "github.com/edgelesssys/constellation/v2/internal/config/snpversion" "github.com/edgelesssys/constellation/v2/internal/variant" ) @@ -26,16 +26,16 @@ type AzureSEVSNP struct { Measurements measurements.M `json:"measurements" yaml:"measurements" validate:"required,no_placeholders"` // description: | // Lowest acceptable bootloader version. - BootloaderVersion uint8 `json:"bootloaderVersion" yaml:"bootloaderVersion"` + BootloaderVersion configapi.AttestationVersion `json:"bootloaderVersion" yaml:"bootloaderVersion"` // description: | // Lowest acceptable TEE version. - TEEVersion uint8 `json:"teeVersion" yaml:"teeVersion"` + TEEVersion configapi.AttestationVersion `json:"teeVersion" yaml:"teeVersion"` // description: | // Lowest acceptable SEV-SNP version. - SNPVersion uint8 `json:"snpVersion" yaml:"snpVersion"` + SNPVersion configapi.AttestationVersion `json:"snpVersion" yaml:"snpVersion"` // description: | // Lowest acceptable microcode version. - MicrocodeVersion uint8 `json:"microcodeVersion" yaml:"microcodeVersion"` + MicrocodeVersion configapi.AttestationVersion `json:"microcodeVersion" yaml:"microcodeVersion"` // description: | // Configuration for validating the firmware signature. FirmwareSignerConfig SNPFirmwareSignerConfig `json:"firmwareSignerConfig" yaml:"firmwareSignerConfig"` @@ -45,14 +45,14 @@ type AzureSEVSNP struct { } // DefaultForAzureSEVSNP returns the default configuration for Azure SEV-SNP attestation. -// Version numbers are hard coded and should be updated with each new release. +// Version numbers have placeholder values and the latest available values can be fetched using [AzureSEVSNP.FetchAndSetLatestVersionNumbers]. func DefaultForAzureSEVSNP() *AzureSEVSNP { return &AzureSEVSNP{ Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureSEVSNP{}), - BootloaderVersion: snpversion.GetLatest(snpversion.Bootloader), - TEEVersion: snpversion.GetLatest(snpversion.TEE), - SNPVersion: snpversion.GetLatest(snpversion.SNP), - MicrocodeVersion: snpversion.GetLatest(snpversion.Microcode), + BootloaderVersion: configapi.NewLatestPlaceholderVersion(), + TEEVersion: configapi.NewLatestPlaceholderVersion(), + SNPVersion: configapi.NewLatestPlaceholderVersion(), + MicrocodeVersion: configapi.NewLatestPlaceholderVersion(), FirmwareSignerConfig: SNPFirmwareSignerConfig{ AcceptedKeyDigests: idkeydigest.DefaultList(), EnforcementPolicy: idkeydigest.MAAFallback, @@ -95,26 +95,25 @@ func (c AzureSEVSNP) EqualTo(old AttestationCfg) (bool, error) { return firmwareSignerCfgEqual && measurementsEqual && bootloaderEqual && teeEqual && snpEqual && microcodeEqual && rootKeyEqual, nil } -// UnmarshalYAML implements a custom unmarshaler to support setting "latest" as version. -func (c *AzureSEVSNP) UnmarshalYAML(unmarshal func(any) error) error { - aux := &fusedAzureSEVSNP{ - auxAzureSEVSNP: (*auxAzureSEVSNP)(c), - } - if err := unmarshal(aux); err != nil { - return fmt.Errorf("unmarshal AzureSEVSNP: %w", err) - } - c = (*AzureSEVSNP)(aux.auxAzureSEVSNP) - - for _, versionType := range []snpversion.Type{snpversion.Bootloader, snpversion.TEE, snpversion.SNP, snpversion.Microcode} { - if !convertLatestToNumber(c, versionType, aux) { - if err := convertStringToUint(c, versionType, aux); err != nil { - return fmt.Errorf("convert %s version to number: %w", versionType, err) - } - } +// FetchAndSetLatestVersionNumbers fetches the latest version numbers from the configapi and sets them. +func (c *AzureSEVSNP) FetchAndSetLatestVersionNumbers(client fetcher.HTTPClient) error { + fetcher := fetcher.NewConfigAPIFetcherWithClient(client) + versions, err := fetcher.FetchLatestAzureSEVSNPVersion(context.Background()) + if err != nil { + return err } + // set number and keep isLatest flag + c.mergeVersionNumbers(versions) return nil } +func (c *AzureSEVSNP) mergeVersionNumbers(versions configapi.AzureSEVSNPVersion) { + c.BootloaderVersion.Value = versions.Bootloader + c.TEEVersion.Value = versions.TEE + c.SNPVersion.Value = versions.SNP + c.MicrocodeVersion.Value = versions.Microcode +} + // AzureTrustedLaunch is the configuration for Azure Trusted Launch attestation. type AzureTrustedLaunch struct { // description: | @@ -145,84 +144,3 @@ func (c AzureTrustedLaunch) EqualTo(other AttestationCfg) (bool, error) { } return c.Measurements.EqualTo(otherCfg.Measurements), nil } - -// auxAzureSEVSNP is a helper struct for unmarshaling the config from YAML for handling the version parsing. -// The version fields are kept to make it convertable to the native AzureSEVSNP struct. -type auxAzureSEVSNP struct { - // description: | - // Expected TPM measurements. - Measurements measurements.M `json:"measurements" yaml:"measurements" validate:"required,no_placeholders"` - // description: | - // Lowest acceptable bootloader version. - BootloaderVersion uint8 `yaml:"-"` - // description: | - // Lowest acceptable TEE version. - TEEVersion uint8 `json:"teeVersion" yaml:"-"` - // description: | - // Lowest acceptable SEV-SNP version. - SNPVersion uint8 `json:"snpVersion" yaml:"-"` - // description: | - // Lowest acceptable microcode version. - MicrocodeVersion uint8 `json:"microcodeVersion" yaml:"-"` - // description: | - // Configuration for validating the firmware signature. - FirmwareSignerConfig SNPFirmwareSignerConfig `json:"firmwareSignerConfig" yaml:"firmwareSignerConfig"` - // description: | - // AMD Root Key certificate used to verify the SEV-SNP certificate chain. - AMDRootKey Certificate `json:"amdRootKey" yaml:"amdRootKey"` -} - -// fusedAzureSEVSNP is a helper struct for unmarshaling the config from YAML for handling the version parsing. -type fusedAzureSEVSNP struct { - *auxAzureSEVSNP `yaml:",inline"` - // description: | - // Lowest acceptable bootloader version. - BootloaderVersion string `yaml:"bootloaderVersion"` - // description: | - // Lowest acceptable bootloader version. - TEEVersion string `yaml:"teeVersion"` - // description: | - // Lowest acceptable bootloader version. - SNPVersion string `yaml:"snpVersion"` - // description: | - // Lowest acceptable bootloader version. - MicrocodeVersion string `yaml:"microcodeVersion"` -} - -func convertStringToUint(c *AzureSEVSNP, versionType snpversion.Type, aux *fusedAzureSEVSNP) error { - v, stringV := getUintAndStringPtrToVersion(c, versionType, aux) - - bvInt, err := strconv.ParseInt(*stringV, 10, 8) - if err != nil { - return err - } - *v = uint8(bvInt) - return nil -} - -func convertLatestToNumber(c *AzureSEVSNP, versionType snpversion.Type, aux *fusedAzureSEVSNP) bool { - v, stringV := getUintAndStringPtrToVersion(c, versionType, aux) - if strings.ToLower(*stringV) == "latest" { - *v = snpversion.GetLatest(versionType) - return true - } - return false -} - -func getUintAndStringPtrToVersion(c *AzureSEVSNP, versionType snpversion.Type, aux *fusedAzureSEVSNP) (versionUint *uint8, versionString *string) { - switch versionType { - case snpversion.Bootloader: - versionUint = &c.BootloaderVersion - versionString = &aux.BootloaderVersion - case snpversion.TEE: - versionUint = &c.TEEVersion - versionString = &aux.TEEVersion - case snpversion.SNP: - versionUint = &c.SNPVersion - versionString = &aux.SNPVersion - case snpversion.Microcode: - versionUint = &c.MicrocodeVersion - versionString = &aux.MicrocodeVersion - } - return -} diff --git a/internal/config/config.go b/internal/config/config.go index 897a232f7..5863f6d95 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -31,6 +31,7 @@ import ( "github.com/go-playground/validator/v10" en_translations "github.com/go-playground/validator/v10/translations/en" + "github.com/edgelesssys/constellation/v2/internal/api/fetcher" "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" @@ -381,14 +382,25 @@ func fromFile(fileHandler file.Handler, name string) (*Config, error) { // New creates a new config by: // 1. Reading config file via provided fileHandler from file with name. -// 2. Read secrets from environment variables. -// 3. Validate config. If `--force` is set the version validation will be disabled and any version combination is allowed. +// 2. For "latest" version values of the attestation variants fetch the version numbers. +// 3. Read secrets from environment variables. +// 4. Validate config. If `--force` is set the version validation will be disabled and any version combination is allowed. func New(fileHandler file.Handler, name string, force bool) (*Config, error) { + return NewWithClient(fileHandler, name, fetcher.NewHTTPClient(), force) +} + +// NewWithClient is New with a custom HTTP client. +func NewWithClient(fileHandler file.Handler, name string, client fetcher.HTTPClient, force bool) (*Config, error) { // Read config file c, err := fromFile(fileHandler, name) if err != nil { return nil, err } + if azure := c.Attestation.AzureSEVSNP; azure != nil { + if err := azure.FetchAndSetLatestVersionNumbers(client); err != nil { + return c, err + } + } // Read secrets from env-vars. clientSecretValue := os.Getenv(constants.EnvVarAzureClientSecretValue) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 1eb807bfe..d5f811da4 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -7,7 +7,11 @@ SPDX-License-Identifier: AGPL-3.0-only package config import ( + "bytes" + "encoding/json" "errors" + "io" + "net/http" "reflect" "testing" @@ -20,6 +24,7 @@ import ( "go.uber.org/goleak" "gopkg.in/yaml.v3" + "github.com/edgelesssys/constellation/v2/internal/api/configapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config/instancetypes" @@ -37,37 +42,57 @@ func TestDefaultConfig(t *testing.T) { assert.NotNil(def) } -func TestSettingLatestAsVersion(t *testing.T) { +func TestDefaultConfigWritesLatestVersion(t *testing.T) { + conf := Default() + bt, err := yaml.Marshal(conf) + require := require.New(t) + require.NoError(err) + + var mp configMap + require.NoError(yaml.Unmarshal(bt, &mp)) + assert := assert.New(t) + assert.Equal("latest", mp.getAzureSEVSNPVersion("microcodeVersion")) + assert.Equal("latest", mp.getAzureSEVSNPVersion("teeVersion")) + assert.Equal("latest", mp.getAzureSEVSNPVersion("snpVersion")) + assert.Equal("latest", mp.getAzureSEVSNPVersion("bootloaderVersion")) +} + +func TestReadConfigFile(t *testing.T) { testCases := map[string]struct { - config map[string]interface{} + config configMap configName string wantResult *Config wantErr bool }{ - "mix of latest and uint as version value": { - config: func() map[string]interface{} { + "mix of Latest and uint as version value": { + config: func() configMap { conf := Default() - // modify versions as string m := getConfigAsMap(conf, t) - m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["microcodeVersion"] = "latest" - m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["teeVersion"] = "latest" - m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["snpVersion"] = "latest" - m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["bootloaderVersion"] = 1 + m.setAzureSEVSNPVersion("microcodeVersion", "Latest") // check uppercase also works + m.setAzureSEVSNPVersion("teeVersion", 2) + m.setAzureSEVSNPVersion("bootloaderVersion", 1) return m }(), configName: constants.ConfigFilename, wantResult: func() *Config { conf := Default() - conf.Attestation.AzureSEVSNP.BootloaderVersion = 1 + conf.Attestation.AzureSEVSNP.BootloaderVersion = configapi.AttestationVersion{ + Value: 1, + IsLatest: false, + } + conf.Attestation.AzureSEVSNP.TEEVersion = configapi.AttestationVersion{ + Value: 2, + IsLatest: false, + } return conf }(), }, "refuse invalid version value": { - config: func() map[string]interface{} { + config: func() configMap { conf := Default() m := getConfigAsMap(conf, t) - m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["microcodeVersion"] = "1a" + m.setAzureSEVSNPVersion("microcodeVersion", "1a") return m }(), configName: constants.ConfigFilename, @@ -84,29 +109,16 @@ func TestSettingLatestAsVersion(t *testing.T) { require.NoError(fileHandler.WriteYAML(tc.configName, tc.config, file.OptNone)) } result, err := fromFile(fileHandler, tc.configName) - if tc.wantErr { assert.Error(err) } else { - require.NoError(err) + assert.NoError(err) assert.Equal(tc.wantResult, result) } }) } } -// getConfigAsMap returns a map of the config. -func getConfigAsMap(conf *Config, t *testing.T) (res map[string]interface{}) { - bytes, err := yaml.Marshal(&conf) - if err != nil { - t.Fatal(err) - } - if err := yaml.Unmarshal(bytes, &res); err != nil { - t.Fatal(err) - } - return -} - func TestFromFile(t *testing.T) { testCases := map[string]struct { config *Config @@ -233,7 +245,7 @@ func TestNewWithDefaultOptions(t *testing.T) { wantClientSecretValue: "some-secret", }, } - + client := newTestClient(&fakeConfigAPIHandler{}) for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) @@ -248,8 +260,7 @@ func TestNewWithDefaultOptions(t *testing.T) { } // Test - c, err := New(fileHandler, constants.ConfigFilename, false) - + c, err := NewWithClient(fileHandler, constants.ConfigFilename, client, false) if tc.wantErr { assert.Error(err) return @@ -846,3 +857,68 @@ func TestConfigVersionCompatibility(t *testing.T) { }) } } + +// configMap is used to un-/marshal the config as an unstructured map. +type configMap map[string]interface{} + +func (c configMap) setAzureSEVSNPVersion(versionType string, value interface{}) { + c["attestation"].(configMap)["azureSEVSNP"].(configMap)[versionType] = value +} + +func (c configMap) getAzureSEVSNPVersion(versionType string) interface{} { + return c["attestation"].(configMap)["azureSEVSNP"].(configMap)[versionType] +} + +// getConfigAsMap returns a map of the config. +func getConfigAsMap(conf *Config, t *testing.T) (res configMap) { + bytes, err := yaml.Marshal(&conf) + if err != nil { + t.Fatal(err) + } + if err := yaml.Unmarshal(bytes, &res); err != nil { + t.Fatal(err) + } + return +} + +type fakeConfigAPIHandler struct{} + +// RoundTrip resolves the request and returns a dummy response. +func (f *fakeConfigAPIHandler) RoundTrip(req *http.Request) (*http.Response, error) { + if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/list" { + res := &http.Response{} + data := []string{"2021-01-01-01-01.json"} + bt, err := json.Marshal(data) + if err != nil { + return nil, err + } + res.Body = io.NopCloser(bytes.NewReader(bt)) + res.Header = http.Header{} + res.Header.Set("Content-Type", "application/json") + res.StatusCode = http.StatusOK + return res, nil + } else if req.URL.Path == "/constellation/v1/attestation/azure-sev-snp/2021-01-01-01-01.json" { + res := &http.Response{} + bt, err := json.Marshal(configapi.AzureSEVSNPVersion{ + Microcode: 93, + TEE: 0, + SNP: 6, + Bootloader: 2, + }) + if err != nil { + return nil, err + } + res.Body = io.NopCloser(bytes.NewReader(bt)) + res.StatusCode = http.StatusOK + return res, nil + + } + return nil, errors.New("no endpoint found") +} + +// newTestClient returns *http.Client with Transport replaced to avoid making real calls. +func newTestClient(fn *fakeConfigAPIHandler) *http.Client { + return &http.Client{ + Transport: fn, + } +} diff --git a/internal/config/snpversion/BUILD.bazel b/internal/config/snpversion/BUILD.bazel deleted file mode 100644 index 190a445df..000000000 --- a/internal/config/snpversion/BUILD.bazel +++ /dev/null @@ -1,8 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "snpversion", - srcs = ["snpversion.go"], - importpath = "github.com/edgelesssys/constellation/v2/internal/config/snpversion", - visibility = ["//:__subpackages__"], -) diff --git a/internal/config/snpversion/snpversion.go b/internal/config/snpversion/snpversion.go deleted file mode 100644 index be0ead82c..000000000 --- a/internal/config/snpversion/snpversion.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package snpversion - -const ( - Bootloader Type = "bootloader" // Bootloader is the version of the Azure SEVSNP bootloader. - TEE Type = "tee" // TEE is the version of the Azure SEVSNP TEE. - SNP Type = "snp" // SNP is the version of the Azure SEVSNP SNP. - Microcode Type = "microcode" // Microcode is the version of the Azure SEVSNP microcode. -) - -// Type is the type of the version to be requested. -type Type string - -// GetLatest returns the version of the given type. -func GetLatest(t Type) uint8 { - switch t { - case Bootloader: - return 2 - case TEE: - return 0 - case SNP: - return 6 - case Microcode: - return 93 - default: - panic("invalid version type") - } -} diff --git a/internal/config/validation.go b/internal/config/validation.go index 28c2999c5..4246ff71b 100644 --- a/internal/config/validation.go +++ b/internal/config/validation.go @@ -19,6 +19,7 @@ import ( "github.com/go-playground/validator/v10" "golang.org/x/mod/semver" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/compatibility" @@ -26,7 +27,6 @@ import ( "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/variant" "github.com/edgelesssys/constellation/v2/internal/versions" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // ValidationError occurs when the validation of a config fails. diff --git a/internal/imagefetcher/BUILD.bazel b/internal/imagefetcher/BUILD.bazel index 009c9dab0..7afc93b2f 100644 --- a/internal/imagefetcher/BUILD.bazel +++ b/internal/imagefetcher/BUILD.bazel @@ -10,10 +10,10 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/imagefetcher", visibility = ["//cli:__subpackages__"], deps = [ + "//internal/api/fetcher", + "//internal/api/versionsapi", "//internal/cloud/cloudprovider", "//internal/variant", - "//internal/versionsapi", - "//internal/versionsapi/fetcher", "@com_github_schollz_progressbar_v3//:progressbar", "@com_github_spf13_afero//:afero", ], @@ -27,10 +27,10 @@ go_test( ], embed = [":imagefetcher"], deps = [ + "//internal/api/versionsapi", "//internal/cloud/cloudprovider", "//internal/file", "//internal/variant", - "//internal/versionsapi", "@com_github_spf13_afero//:afero", "@com_github_stretchr_testify//assert", "@com_github_stretchr_testify//require", diff --git a/internal/imagefetcher/imagefetcher.go b/internal/imagefetcher/imagefetcher.go index f18b6bf8a..47689986b 100644 --- a/internal/imagefetcher/imagefetcher.go +++ b/internal/imagefetcher/imagefetcher.go @@ -19,10 +19,10 @@ import ( "io/fs" "regexp" + "github.com/edgelesssys/constellation/v2/internal/api/fetcher" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" - "github.com/edgelesssys/constellation/v2/internal/versionsapi/fetcher" "github.com/spf13/afero" ) @@ -35,7 +35,7 @@ type Fetcher struct { // New returns a new image fetcher. func New() *Fetcher { return &Fetcher{ - fetcher: fetcher.NewFetcher(), + fetcher: fetcher.NewVersionAPIFetcher(), fs: &afero.Afero{Fs: afero.NewOsFs()}, } } diff --git a/internal/imagefetcher/imagefetcher_test.go b/internal/imagefetcher/imagefetcher_test.go index 5b5e75280..5543e17f8 100644 --- a/internal/imagefetcher/imagefetcher_test.go +++ b/internal/imagefetcher/imagefetcher_test.go @@ -13,10 +13,10 @@ import ( "net/http" "testing" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/file" "github.com/edgelesssys/constellation/v2/internal/variant" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" diff --git a/internal/kms/storage/awss3/awss3.go b/internal/kms/storage/awss3/awss3.go index ee7d5d9a7..535ab944e 100644 --- a/internal/kms/storage/awss3/awss3.go +++ b/internal/kms/storage/awss3/awss3.go @@ -27,6 +27,7 @@ type awsS3ClientAPI interface { GetObject(ctx context.Context, params *s3.GetObjectInput, optFns ...func(*s3.Options)) (*s3.GetObjectOutput, error) PutObject(ctx context.Context, params *s3.PutObjectInput, optFns ...func(*s3.Options)) (*s3.PutObjectOutput, error) CreateBucket(ctx context.Context, params *s3.CreateBucketInput, optFns ...func(*s3.Options)) (*s3.CreateBucketOutput, error) + DeleteObject(ctx context.Context, params *s3.DeleteObjectInput, optFns ...func(*s3.Options)) (*s3.DeleteObjectOutput, error) } // Storage is an implementation of the Storage interface, storing keys in AWS S3 buckets. @@ -76,6 +77,18 @@ func (s *Storage) Get(ctx context.Context, keyID string) ([]byte, error) { return io.ReadAll(output.Body) } +// Delete removes a DEK from AWS S3 Storage by key ID. +func (s *Storage) Delete(ctx context.Context, keyID string) error { + deleteObjectInput := &s3.DeleteObjectInput{ + Bucket: &s.bucketID, + Key: &keyID, + } + if _, err := s.client.DeleteObject(ctx, deleteObjectInput); err != nil { + return fmt.Errorf("deleting DEK from storage: %w", err) + } + return nil +} + // Put saves a DEK to AWS S3 Storage by key ID. func (s *Storage) Put(ctx context.Context, keyID string, data []byte) error { putObjectInput := &s3.PutObjectInput{ diff --git a/internal/kms/storage/awss3/awss3_test.go b/internal/kms/storage/awss3/awss3_test.go index e6fbf4f94..4e07ab84d 100644 --- a/internal/kms/storage/awss3/awss3_test.go +++ b/internal/kms/storage/awss3/awss3_test.go @@ -43,6 +43,10 @@ func (s *stubAWSS3StorageClient) PutObject(_ context.Context, params *s3.PutObje return &s3.PutObjectOutput{}, s.putObjectErr } +func (s *stubAWSS3StorageClient) DeleteObject(_ context.Context, _ *s3.DeleteObjectInput, _ ...func(*s3.Options)) (*s3.DeleteObjectOutput, error) { + return &s3.DeleteObjectOutput{}, nil +} + func (s *stubAWSS3StorageClient) CreateBucket(_ context.Context, _ *s3.CreateBucketInput, _ ...func(*s3.Options)) (*s3.CreateBucketOutput, error) { s.createBucketCalled = true return &s3.CreateBucketOutput{}, s.createBucketErr diff --git a/internal/osimage/BUILD.bazel b/internal/osimage/BUILD.bazel index 111c5884b..3e9285662 100644 --- a/internal/osimage/BUILD.bazel +++ b/internal/osimage/BUILD.bazel @@ -6,8 +6,8 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/cloud/cloudprovider", "//internal/osimage/secureboot", - "//internal/versionsapi", ], ) diff --git a/internal/osimage/archive/BUILD.bazel b/internal/osimage/archive/BUILD.bazel index 8cfa40529..164327ab2 100644 --- a/internal/osimage/archive/BUILD.bazel +++ b/internal/osimage/archive/BUILD.bazel @@ -6,9 +6,9 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/archive", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/constants", "//internal/logger", - "//internal/versionsapi", "@com_github_aws_aws_sdk_go_v2_config//:config", "@com_github_aws_aws_sdk_go_v2_feature_s3_manager//:manager", "@com_github_aws_aws_sdk_go_v2_service_s3//:s3", diff --git a/internal/osimage/archive/archive.go b/internal/osimage/archive/archive.go index 2f1ce6974..a447075f5 100644 --- a/internal/osimage/archive/archive.go +++ b/internal/osimage/archive/archive.go @@ -16,9 +16,9 @@ import ( s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Archivist uploads OS images to S3. diff --git a/internal/osimage/aws/BUILD.bazel b/internal/osimage/aws/BUILD.bazel index 7721504b3..640714442 100644 --- a/internal/osimage/aws/BUILD.bazel +++ b/internal/osimage/aws/BUILD.bazel @@ -6,10 +6,10 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/aws", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/logger", "//internal/osimage", "//internal/osimage/secureboot", - "//internal/versionsapi", "@com_github_aws_aws_sdk_go_v2_config//:config", "@com_github_aws_aws_sdk_go_v2_feature_s3_manager//:manager", "@com_github_aws_aws_sdk_go_v2_service_ec2//:ec2", diff --git a/internal/osimage/aws/awsupload.go b/internal/osimage/aws/awsupload.go index c5b722186..611ff801a 100644 --- a/internal/osimage/aws/awsupload.go +++ b/internal/osimage/aws/awsupload.go @@ -23,10 +23,10 @@ import ( s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" "github.com/aws/smithy-go" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/osimage" "github.com/edgelesssys/constellation/v2/internal/osimage/secureboot" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Uploader can upload and remove os images on GCP. diff --git a/internal/osimage/azure/BUILD.bazel b/internal/osimage/azure/BUILD.bazel index 86dec0251..8951f29dc 100644 --- a/internal/osimage/azure/BUILD.bazel +++ b/internal/osimage/azure/BUILD.bazel @@ -9,9 +9,9 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/azure", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/logger", "//internal/osimage", - "//internal/versionsapi", "@com_github_azure_azure_sdk_for_go_sdk_azcore//runtime", "@com_github_azure_azure_sdk_for_go_sdk_azidentity//:azidentity", "@com_github_azure_azure_sdk_for_go_sdk_resourcemanager_compute_armcompute_v4//:armcompute", diff --git a/internal/osimage/azure/azureupload.go b/internal/osimage/azure/azureupload.go index 22b23af5e..a7aceb163 100644 --- a/internal/osimage/azure/azureupload.go +++ b/internal/osimage/azure/azureupload.go @@ -21,9 +21,9 @@ import ( armcomputev4 "github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute/v4" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/blob" "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/pageblob" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/osimage" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Uploader can upload and remove os images on Azure. diff --git a/internal/osimage/gcp/BUILD.bazel b/internal/osimage/gcp/BUILD.bazel index d6883f2f1..d2b5afcaf 100644 --- a/internal/osimage/gcp/BUILD.bazel +++ b/internal/osimage/gcp/BUILD.bazel @@ -6,10 +6,10 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/gcp", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/logger", "//internal/osimage", "//internal/osimage/secureboot", - "//internal/versionsapi", "@com_github_googleapis_gax_go_v2//:gax-go", "@com_google_cloud_go_compute//apiv1", "@com_google_cloud_go_compute//apiv1/computepb", diff --git a/internal/osimage/gcp/gcpupload.go b/internal/osimage/gcp/gcpupload.go index 995b730eb..da8046f8c 100644 --- a/internal/osimage/gcp/gcpupload.go +++ b/internal/osimage/gcp/gcpupload.go @@ -19,10 +19,10 @@ import ( compute "cloud.google.com/go/compute/apiv1" "cloud.google.com/go/compute/apiv1/computepb" "cloud.google.com/go/storage" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/osimage" "github.com/edgelesssys/constellation/v2/internal/osimage/secureboot" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" gaxv2 "github.com/googleapis/gax-go/v2" ) diff --git a/internal/osimage/imageinfo/BUILD.bazel b/internal/osimage/imageinfo/BUILD.bazel index 92decbc45..1dfadef3b 100644 --- a/internal/osimage/imageinfo/BUILD.bazel +++ b/internal/osimage/imageinfo/BUILD.bazel @@ -6,9 +6,9 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/imageinfo", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/constants", "//internal/logger", - "//internal/versionsapi", "@com_github_aws_aws_sdk_go_v2_config//:config", "@com_github_aws_aws_sdk_go_v2_feature_s3_manager//:manager", "@com_github_aws_aws_sdk_go_v2_service_s3//:s3", diff --git a/internal/osimage/imageinfo/imageinfo.go b/internal/osimage/imageinfo/imageinfo.go index e87eb9ff0..aa31b3ee3 100644 --- a/internal/osimage/imageinfo/imageinfo.go +++ b/internal/osimage/imageinfo/imageinfo.go @@ -17,9 +17,9 @@ import ( s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Uploader uploads image info to S3. diff --git a/internal/osimage/measurementsuploader/BUILD.bazel b/internal/osimage/measurementsuploader/BUILD.bazel index 189835a05..8f285080c 100644 --- a/internal/osimage/measurementsuploader/BUILD.bazel +++ b/internal/osimage/measurementsuploader/BUILD.bazel @@ -6,10 +6,10 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/measurementsuploader", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/attestation/measurements", "//internal/constants", "//internal/logger", - "//internal/versionsapi", "@com_github_aws_aws_sdk_go_v2_config//:config", "@com_github_aws_aws_sdk_go_v2_feature_s3_manager//:manager", "@com_github_aws_aws_sdk_go_v2_service_s3//:s3", diff --git a/internal/osimage/measurementsuploader/measurementsuploader.go b/internal/osimage/measurementsuploader/measurementsuploader.go index 53964b7ae..1ada764fd 100644 --- a/internal/osimage/measurementsuploader/measurementsuploader.go +++ b/internal/osimage/measurementsuploader/measurementsuploader.go @@ -18,10 +18,10 @@ import ( s3manager "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/aws/aws-sdk-go-v2/service/s3" s3types "github.com/aws/aws-sdk-go-v2/service/s3/types" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" "github.com/edgelesssys/constellation/v2/internal/constants" "github.com/edgelesssys/constellation/v2/internal/logger" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Uploader uploads image info to S3. diff --git a/internal/osimage/nop/BUILD.bazel b/internal/osimage/nop/BUILD.bazel index b0a9f49e3..6e5b5d915 100644 --- a/internal/osimage/nop/BUILD.bazel +++ b/internal/osimage/nop/BUILD.bazel @@ -6,8 +6,8 @@ go_library( importpath = "github.com/edgelesssys/constellation/v2/internal/osimage/nop", visibility = ["//:__subpackages__"], deps = [ + "//internal/api/versionsapi", "//internal/logger", "//internal/osimage", - "//internal/versionsapi", ], ) diff --git a/internal/osimage/nop/nop.go b/internal/osimage/nop/nop.go index 05b207f00..c329dd5ea 100644 --- a/internal/osimage/nop/nop.go +++ b/internal/osimage/nop/nop.go @@ -10,9 +10,9 @@ package nop import ( "context" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/logger" "github.com/edgelesssys/constellation/v2/internal/osimage" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // Uploader is a no-op uploader. diff --git a/internal/osimage/osimage.go b/internal/osimage/osimage.go index 9e6032cb9..780df2320 100644 --- a/internal/osimage/osimage.go +++ b/internal/osimage/osimage.go @@ -11,9 +11,9 @@ import ( "io" "time" + "github.com/edgelesssys/constellation/v2/internal/api/versionsapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/osimage/secureboot" - "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // UploadRequest is a request to upload an os image. diff --git a/internal/variant/variant.go b/internal/variant/variant.go index 3c70e764b..2cfe113f6 100644 --- a/internal/variant/variant.go +++ b/internal/variant/variant.go @@ -82,7 +82,7 @@ func GetAvailableAttestationTypes() []Variant { for _, k := range keys { res = append(res, providerAttestationMapping[k]...) } - return removeDuplicate(res) + return RemoveDuplicate(res) } // Getter returns an ASN.1 Object Identifier. @@ -259,9 +259,10 @@ func (QEMUTDX) Equal(other Getter) bool { return other.OID().Equal(QEMUTDX{}.OID()) } -func removeDuplicate(sliceList []Variant) []Variant { - allKeys := make(map[Variant]bool) - list := []Variant{} +// RemoveDuplicate removes duplicate elements from a slice. +func RemoveDuplicate[T comparable](sliceList []T) []T { + allKeys := make(map[T]bool) + list := []T{} for _, item := range sliceList { if _, value := allKeys[item]; !value { allKeys[item] = true