diff --git a/cli/internal/cloudcmd/create_test.go b/cli/internal/cloudcmd/create_test.go index eded26230..d7d243066 100644 --- a/cli/internal/cloudcmd/create_test.go +++ b/cli/internal/cloudcmd/create_test.go @@ -41,18 +41,18 @@ func TestCreator(t *testing.T) { "gcp": { tfClient: &stubTerraformClient{ip: ip}, provider: cloudprovider.GCP, - config: config.Default(), + config: config.DefaultWithPanic(), }, "gcp newTerraformClient error": { newTfClientErr: someErr, provider: cloudprovider.GCP, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: true, }, "gcp create cluster error": { tfClient: &stubTerraformClient{createClusterErr: someErr}, provider: cloudprovider.GCP, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: true, wantRollback: true, wantTerraformRollback: true, @@ -61,7 +61,7 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{ip: ip}, provider: cloudprovider.Azure, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) return cfg }(), @@ -71,7 +71,7 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{ip: ip}, provider: cloudprovider.Azure, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.Attestation = config.AttestationConfig{ AzureTrustedLaunch: &config.AzureTrustedLaunch{}, } @@ -83,7 +83,7 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{ip: ip}, provider: cloudprovider.Azure, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) return cfg }(), @@ -94,7 +94,7 @@ func TestCreator(t *testing.T) { newTfClientErr: someErr, provider: cloudprovider.Azure, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) return cfg }(), @@ -105,7 +105,7 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{createClusterErr: someErr}, provider: cloudprovider.Azure, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.RemoveProviderAndAttestationExcept(cloudprovider.Azure) return cfg }(), @@ -119,7 +119,7 @@ func TestCreator(t *testing.T) { libvirt: &stubLibvirtRunner{}, provider: cloudprovider.OpenStack, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.Provider.OpenStack.Cloud = "testcloud" return cfg }(), @@ -128,7 +128,7 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{ip: ip}, libvirt: &stubLibvirtRunner{}, provider: cloudprovider.OpenStack, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: true, }, "openstack newTerraformClient error": { @@ -136,7 +136,7 @@ func TestCreator(t *testing.T) { libvirt: &stubLibvirtRunner{}, provider: cloudprovider.OpenStack, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.Provider.OpenStack.Cloud = "testcloud" return cfg }(), @@ -147,7 +147,7 @@ func TestCreator(t *testing.T) { libvirt: &stubLibvirtRunner{}, provider: cloudprovider.OpenStack, config: func() *config.Config { - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.Provider.OpenStack.Cloud = "testcloud" return cfg }(), @@ -159,21 +159,21 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{ip: ip}, libvirt: &stubLibvirtRunner{}, provider: cloudprovider.QEMU, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: failOnNonAMD64, }, "qemu newTerraformClient error": { newTfClientErr: someErr, libvirt: &stubLibvirtRunner{}, provider: cloudprovider.QEMU, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: true, }, "qemu create cluster error": { tfClient: &stubTerraformClient{createClusterErr: someErr}, libvirt: &stubLibvirtRunner{}, provider: cloudprovider.QEMU, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: true, wantRollback: !failOnNonAMD64, // if we run on non-AMD64/linux, we don't get to a point where rollback is needed wantTerraformRollback: true, @@ -182,14 +182,14 @@ func TestCreator(t *testing.T) { tfClient: &stubTerraformClient{ip: ip}, libvirt: &stubLibvirtRunner{startErr: someErr}, provider: cloudprovider.QEMU, - config: config.Default(), + config: config.DefaultWithPanic(), wantRollback: !failOnNonAMD64, wantTerraformRollback: false, wantErr: true, }, "unknown provider": { provider: cloudprovider.Unknown, - config: config.Default(), + config: config.DefaultWithPanic(), wantErr: true, }, } diff --git a/cli/internal/cmd/configfetchmeasurements_test.go b/cli/internal/cmd/configfetchmeasurements_test.go index 483433457..49610720b 100644 --- a/cli/internal/cmd/configfetchmeasurements_test.go +++ b/cli/internal/cmd/configfetchmeasurements_test.go @@ -250,7 +250,7 @@ func TestConfigFetchMeasurements(t *testing.T) { cmd.Flags().Bool("force", true, "") // register persistent flag manually fileHandler := file.NewHandler(afero.NewMemMapFs()) - gcpConfig := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.GCP) + gcpConfig := defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), cloudprovider.GCP) gcpConfig.Image = "v999.999.999" err := fileHandler.WriteYAML(constants.ConfigFilename, gcpConfig, file.OptMkdirAll) diff --git a/cli/internal/cmd/configgenerate.go b/cli/internal/cmd/configgenerate.go index 6fad71ba8..8decce1b6 100644 --- a/cli/internal/cmd/configgenerate.go +++ b/cli/internal/cmd/configgenerate.go @@ -36,7 +36,7 @@ func newConfigGenerateCmd() *cobra.Command { RunE: runConfigGenerate, } cmd.Flags().StringP("file", "f", constants.ConfigFilename, "path to output file, or '-' for stdout") - cmd.Flags().StringP("kubernetes", "k", semver.MajorMinor(config.Default().KubernetesVersion), "Kubernetes version to use in format MAJOR.MINOR") + cmd.Flags().StringP("kubernetes", "k", semver.MajorMinor(config.DefaultWithPanic().KubernetesVersion), "Kubernetes version to use in format MAJOR.MINOR") cmd.Flags().StringP("attestation", "a", "", fmt.Sprintf("attestation variant to use %s. If not specified, the default for the cloud provider is used", printFormattedSlice(variant.GetAvailableAttestationTypes()))) return cmd @@ -103,7 +103,10 @@ func (cg *configGenerateCmd) configGenerate(cmd *cobra.Command, fileHandler file // createConfig creates a config file for the given provider. func createConfigWithAttestationType(provider cloudprovider.Provider, attestationVariant variant.Variant) (*config.Config, error) { - conf := config.Default() + conf, err := config.Default() + if err != nil { + return nil, fmt.Errorf("creating default config: %w", err) + } conf.RemoveProviderExcept(provider) // set a lower default for QEMU's state disk diff --git a/cli/internal/cmd/configgenerate_test.go b/cli/internal/cmd/configgenerate_test.go index 343fa12da..a5ce36c32 100644 --- a/cli/internal/cmd/configgenerate_test.go +++ b/cli/internal/cmd/configgenerate_test.go @@ -79,7 +79,7 @@ func TestConfigGenerateDefault(t *testing.T) { var readConfig config.Config err := fileHandler.ReadYAML(constants.ConfigFilename, &readConfig) assert.NoError(err) - assert.Equal(*config.Default(), readConfig) + assert.Equal(*config.DefaultWithPanic(), readConfig) } func TestConfigGenerateDefaultGCPSpecific(t *testing.T) { @@ -89,7 +89,7 @@ func TestConfigGenerateDefaultGCPSpecific(t *testing.T) { fileHandler := file.NewHandler(afero.NewMemMapFs()) cmd := newConfigGenerateCmd() - wantConf := config.Default() + wantConf := config.DefaultWithPanic() wantConf.RemoveProviderAndAttestationExcept(cloudprovider.GCP) cg := &configGenerateCmd{log: logger.NewTest(t)} @@ -140,7 +140,7 @@ func TestConfigGenerateStdOut(t *testing.T) { var readConfig config.Config require.NoError(yaml.NewDecoder(&outBuffer).Decode(&readConfig)) - assert.Equal(*config.Default(), readConfig) + assert.Equal(*config.DefaultWithPanic(), readConfig) } func TestNoValidProviderAttestationCombination(t *testing.T) { @@ -163,7 +163,7 @@ func TestNoValidProviderAttestationCombination(t *testing.T) { } func TestValidProviderAttestationCombination(t *testing.T) { - defaultAttestation := config.Default().Attestation + defaultAttestation := config.DefaultWithPanic().Attestation tests := []struct { provider cloudprovider.Provider attestation variant.Variant @@ -213,7 +213,7 @@ func TestValidProviderAttestationCombination(t *testing.T) { } func TestAttestationArgument(t *testing.T) { - defaultAttestation := config.Default().Attestation + defaultAttestation := config.DefaultWithPanic().Attestation tests := []struct { name string provider cloudprovider.Provider diff --git a/cli/internal/cmd/create_test.go b/cli/internal/cmd/create_test.go index 1ac36b39b..4a82a7a3b 100644 --- a/cli/internal/cmd/create_test.go +++ b/cli/internal/cmd/create_test.go @@ -27,7 +27,7 @@ func TestCreate(t *testing.T) { fsWithDefaultConfig := func(require *require.Assertions, provider cloudprovider.Provider) afero.Fs { fs := afero.NewMemMapFs() file := file.NewHandler(fs) - require.NoError(file.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), provider))) + require.NoError(file.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), provider))) return fs } idFile := clusterid.File{IP: "192.0.2.1"} @@ -114,7 +114,7 @@ func TestCreate(t *testing.T) { fs := afero.NewMemMapFs() fileHandler := file.NewHandler(fs) require.NoError(fileHandler.Write(constants.AdminConfFilename, []byte{1}, file.OptNone)) - require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), csp))) + require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), csp))) return fs }, creator: &stubCloudCreator{}, @@ -129,7 +129,7 @@ func TestCreate(t *testing.T) { fs := afero.NewMemMapFs() fileHandler := file.NewHandler(fs) require.NoError(fileHandler.Write(constants.MasterSecretFilename, []byte{1}, file.OptNone)) - require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), csp))) + require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), csp))) return fs }, creator: &stubCloudCreator{}, @@ -162,7 +162,7 @@ func TestCreate(t *testing.T) { setupFs: func(require *require.Assertions, csp cloudprovider.Provider) afero.Fs { fs := afero.NewMemMapFs() fileHandler := file.NewHandler(fs) - require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.Default(), csp))) + require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), csp))) return afero.NewReadOnlyFs(fs) }, creator: &stubCloudCreator{}, diff --git a/cli/internal/cmd/iamcreate.go b/cli/internal/cmd/iamcreate.go index fe3d1b04c..b4a5b37bd 100644 --- a/cli/internal/cmd/iamcreate.go +++ b/cli/internal/cmd/iamcreate.go @@ -60,7 +60,7 @@ func newIAMCreateCmd() *cobra.Command { cmd.PersistentFlags().BoolP("yes", "y", false, "create the IAM configuration without further confirmation") cmd.PersistentFlags().Bool("generate-config", false, "automatically generate a configuration file and fill in the required fields") - cmd.PersistentFlags().StringP("kubernetes", "k", semver.MajorMinor(config.Default().KubernetesVersion), "Kubernetes version to use in format MAJOR.MINOR - only usable in combination with --generate-config") + cmd.PersistentFlags().StringP("kubernetes", "k", semver.MajorMinor(config.DefaultWithPanic().KubernetesVersion), "Kubernetes version to use in format MAJOR.MINOR - only usable in combination with --generate-config") cmd.AddCommand(newIAMCreateAWSCmd()) cmd.AddCommand(newIAMCreateAzureCmd()) diff --git a/cli/internal/cmd/iamcreate_test.go b/cli/internal/cmd/iamcreate_test.go index 429952b20..0b7853ef2 100644 --- a/cli/internal/cmd/iamcreate_test.go +++ b/cli/internal/cmd/iamcreate_test.go @@ -275,7 +275,7 @@ func TestIAMCreateAWS(t *testing.T) { // register persistent flags manually cmd.Flags().String("config", constants.ConfigFilename, "") cmd.Flags().Bool("generate-config", false, "") - cmd.Flags().String("kubernetes", semver.MajorMinor(config.Default().KubernetesVersion), "") + cmd.Flags().String("kubernetes", semver.MajorMinor(config.DefaultWithPanic().KubernetesVersion), "") cmd.Flags().Bool("yes", false, "") cmd.Flags().String("name", "constell", "") cmd.Flags().String("tf-log", "NONE", "") @@ -554,7 +554,7 @@ func TestIAMCreateAzure(t *testing.T) { // register persistent flags manually cmd.Flags().String("config", constants.ConfigFilename, "") cmd.Flags().Bool("generate-config", false, "") - cmd.Flags().String("kubernetes", semver.MajorMinor(config.Default().KubernetesVersion), "") + cmd.Flags().String("kubernetes", semver.MajorMinor(config.DefaultWithPanic().KubernetesVersion), "") cmd.Flags().Bool("yes", false, "") cmd.Flags().String("name", "constell", "") cmd.Flags().String("tf-log", "NONE", "") @@ -861,7 +861,7 @@ func TestIAMCreateGCP(t *testing.T) { // register persistent flags manually cmd.Flags().String("config", constants.ConfigFilename, "") cmd.Flags().Bool("generate-config", false, "") - cmd.Flags().String("kubernetes", semver.MajorMinor(config.Default().KubernetesVersion), "") + cmd.Flags().String("kubernetes", semver.MajorMinor(config.DefaultWithPanic().KubernetesVersion), "") cmd.Flags().Bool("yes", false, "") cmd.Flags().String("name", "constell", "") cmd.Flags().String("tf-log", "NONE", "") diff --git a/cli/internal/cmd/init_test.go b/cli/internal/cmd/init_test.go index 35b276839..b1827b4de 100644 --- a/cli/internal/cmd/init_test.go +++ b/cli/internal/cmd/init_test.go @@ -156,7 +156,7 @@ func TestInitialize(t *testing.T) { // File system preparation fs := afero.NewMemMapFs() fileHandler := file.NewHandler(fs) - config := defaultConfigWithExpectedMeasurements(t, config.Default(), tc.provider) + config := defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), tc.provider) if tc.configMutator != nil { tc.configMutator(config) } @@ -427,7 +427,7 @@ func TestAttestation(t *testing.T) { fileHandler := file.NewHandler(fs) require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFileName, existingIDFile, file.OptNone)) - cfg := config.Default() + cfg := config.DefaultWithPanic() cfg.Image = "image" cfg.RemoveProviderAndAttestationExcept(cloudprovider.QEMU) cfg.Attestation.QEMUVTPM.Measurements[0] = measurements.WithAllBytes(0x00, measurements.Enforce, measurements.PCRMeasurementLength) diff --git a/cli/internal/cmd/miniup.go b/cli/internal/cmd/miniup.go index ae287d0bd..ce5ce7c3d 100644 --- a/cli/internal/cmd/miniup.go +++ b/cli/internal/cmd/miniup.go @@ -214,7 +214,10 @@ func (m *miniUpCmd) prepareConfig(cmd *cobra.Command, fileHandler file.Handler, } } - config := config.Default() + config, err := config.Default() + if err != nil { + return nil, err + } config.Name = constants.MiniConstellationUID config.RemoveProviderAndAttestationExcept(cloudprovider.QEMU) config.StateDiskSizeGB = 8 diff --git a/cli/internal/cmd/recover_test.go b/cli/internal/cmd/recover_test.go index a54a2dc20..911fbbf9f 100644 --- a/cli/internal/cmd/recover_test.go +++ b/cli/internal/cmd/recover_test.go @@ -153,7 +153,7 @@ func TestRecover(t *testing.T) { fs := afero.NewMemMapFs() fileHandler := file.NewHandler(fs) - config := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.GCP) + config := defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), cloudprovider.GCP) require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, config)) require.NoError(fileHandler.WriteJSON( diff --git a/cli/internal/cmd/upgradeapply_test.go b/cli/internal/cmd/upgradeapply_test.go index 6b6cc933b..57f98295a 100644 --- a/cli/internal/cmd/upgradeapply_test.go +++ b/cli/internal/cmd/upgradeapply_test.go @@ -30,6 +30,8 @@ import ( func TestUpgradeApply(t *testing.T) { someErr := errors.New("some error") + azureSEVSNP, err := config.DefaultForAzureSEVSNP() + require.NoError(t, err) testCases := map[string]struct { upgrader stubUpgrader fetcher stubImageFetcher @@ -38,12 +40,12 @@ func TestUpgradeApply(t *testing.T) { stdin string }{ "success": { - upgrader: stubUpgrader{currentConfig: config.DefaultForAzureSEVSNP()}, + upgrader: stubUpgrader{currentConfig: azureSEVSNP}, yesFlag: true, }, "nodeVersion some error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, nodeVersionErr: someErr, }, wantErr: true, @@ -51,14 +53,14 @@ func TestUpgradeApply(t *testing.T) { }, "nodeVersion in progress error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, nodeVersionErr: kubernetes.ErrInProgress, }, yesFlag: true, }, "helm other error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, helmErr: someErr, }, wantErr: true, @@ -67,7 +69,7 @@ func TestUpgradeApply(t *testing.T) { }, "check terraform error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, checkTerraformErr: someErr, }, fetcher: stubImageFetcher{}, @@ -76,7 +78,7 @@ func TestUpgradeApply(t *testing.T) { }, "abort": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, terraformDiff: true, }, fetcher: stubImageFetcher{}, @@ -85,7 +87,7 @@ func TestUpgradeApply(t *testing.T) { }, "clean terraform error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, cleanTerraformErr: someErr, terraformDiff: true, }, @@ -95,7 +97,7 @@ func TestUpgradeApply(t *testing.T) { }, "plan terraform error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, planTerraformErr: someErr, }, fetcher: stubImageFetcher{}, @@ -104,7 +106,7 @@ func TestUpgradeApply(t *testing.T) { }, "apply terraform error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, applyTerraformErr: someErr, terraformDiff: true, }, @@ -114,7 +116,7 @@ func TestUpgradeApply(t *testing.T) { }, "fetch reference error": { upgrader: stubUpgrader{ - currentConfig: config.DefaultForAzureSEVSNP(), + currentConfig: azureSEVSNP, }, fetcher: stubImageFetcher{fetchReferenceErr: someErr}, wantErr: true, @@ -138,7 +140,7 @@ func TestUpgradeApply(t *testing.T) { } handler := file.NewHandler(afero.NewMemMapFs()) - cfg := defaultConfigWithExpectedMeasurements(t, config.Default(), cloudprovider.Azure) + cfg := defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), cloudprovider.Azure) require.NoError(handler.WriteYAML(constants.ConfigFilename, cfg)) require.NoError(handler.WriteJSON(constants.ClusterIDsFileName, clusterid.File{})) diff --git a/cli/internal/cmd/upgradecheck_test.go b/cli/internal/cmd/upgradecheck_test.go index 6ab3c9700..358e44ad2 100644 --- a/cli/internal/cmd/upgradecheck_test.go +++ b/cli/internal/cmd/upgradecheck_test.go @@ -261,7 +261,7 @@ func TestUpgradeCheck(t *testing.T) { require := require.New(t) fileHandler := file.NewHandler(afero.NewMemMapFs()) - cfg := defaultConfigWithExpectedMeasurements(t, config.Default(), tc.csp) + cfg := defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), tc.csp) require.NoError(fileHandler.WriteYAML(tc.flags.configPath, cfg)) checkCmd := upgradeCheckCmd{ diff --git a/cli/internal/cmd/verify_test.go b/cli/internal/cmd/verify_test.go index 1126fd666..d93f1ec2f 100644 --- a/cli/internal/cmd/verify_test.go +++ b/cli/internal/cmd/verify_test.go @@ -183,7 +183,7 @@ func TestVerify(t *testing.T) { } fileHandler := file.NewHandler(afero.NewMemMapFs()) - config := defaultConfigWithExpectedMeasurements(t, config.Default(), tc.provider) + config := defaultConfigWithExpectedMeasurements(t, config.DefaultWithPanic(), tc.provider) require.NoError(fileHandler.WriteYAML(constants.ConfigFilename, config)) if tc.idFile != nil { require.NoError(fileHandler.WriteJSON(constants.ClusterIDsFileName, tc.idFile, file.OptNone)) diff --git a/cli/internal/helm/client_test.go b/cli/internal/helm/client_test.go index 4375c117e..3db1b357d 100644 --- a/cli/internal/helm/client_test.go +++ b/cli/internal/helm/client_test.go @@ -88,7 +88,7 @@ func TestUpgradeRelease(t *testing.T) { chart, err := loadChartsDir(helmFS, certManagerInfo.path) require.NoError(err) - err = client.upgradeRelease(context.Background(), 0, config.Default(), chart, tc.allowDestructive) + err = client.upgradeRelease(context.Background(), 0, config.DefaultWithPanic(), chart, tc.allowDestructive) if tc.wantError { tc.assertCorrectError(t, err) return diff --git a/cli/internal/kubernetes/upgrade_test.go b/cli/internal/kubernetes/upgrade_test.go index bcbae368d..765a6d5b7 100644 --- a/cli/internal/kubernetes/upgrade_test.go +++ b/cli/internal/kubernetes/upgrade_test.go @@ -46,7 +46,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }{ "success": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.3" conf.KubernetesVersion = versions.SupportedK8sVersions()[1] return conf @@ -62,7 +62,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "only k8s upgrade": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.2" conf.KubernetesVersion = versions.SupportedK8sVersions()[1] return conf @@ -83,7 +83,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "only image upgrade": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.3" conf.KubernetesVersion = versions.SupportedK8sVersions()[0] return conf @@ -104,7 +104,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "not an upgrade": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.2" conf.KubernetesVersion = versions.SupportedK8sVersions()[0] return conf @@ -120,7 +120,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "upgrade in progress": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.3" conf.KubernetesVersion = versions.SupportedK8sVersions()[1] return conf @@ -139,7 +139,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "get error": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.3" return conf }(), @@ -151,7 +151,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "image too new valid k8s": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.4.2" conf.KubernetesVersion = versions.SupportedK8sVersions()[1] return conf @@ -173,7 +173,7 @@ func TestUpgradeNodeVersion(t *testing.T) { }, "apply returns bad object": { conf: func() *config.Config { - conf := config.Default() + conf := config.DefaultWithPanic() conf.Image = "v1.2.3" conf.KubernetesVersion = versions.SupportedK8sVersions()[1] return conf diff --git a/internal/attestation/azure/snp/validator_test.go b/internal/attestation/azure/snp/validator_test.go index 8751b0d70..7934ed61b 100644 --- a/internal/attestation/azure/snp/validator_test.go +++ b/internal/attestation/azure/snp/validator_test.go @@ -213,7 +213,7 @@ func TestTrustedKeyFromSNP(t *testing.T) { }, } - cfg := config.DefaultForAzureSEVSNP() + cfg, err := config.DefaultForAzureSEVSNP() cfg.FirmwareSignerConfig = config.SNPFirmwareSignerConfig{ AcceptedKeyDigests: tc.idkeydigests, EnforcementPolicy: tc.enforceIDKeyDigest, @@ -348,7 +348,10 @@ func TestNewSNPReportFromBytes(t *testing.T) { wantErr: true, }, } - + cfg, err := config.DefaultForAzureSEVSNP() + if err != nil { + t.Fatal(err) + } for name, tc := range testCases { t.Run(name, func(t *testing.T) { assert := assert.New(t) @@ -363,7 +366,6 @@ 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)) } }) diff --git a/internal/attestation/measurements/measurement-generator/generate.go b/internal/attestation/measurements/measurement-generator/generate.go index 16ba530d1..6bd9776a0 100644 --- a/internal/attestation/measurements/measurement-generator/generate.go +++ b/internal/attestation/measurements/measurement-generator/generate.go @@ -39,7 +39,10 @@ import ( // TODO(v2.8 | AB#3130): Update tool to use variant.Variant instead of cloudprovider.Provider func main() { - defaultConf := config.Default() + defaultConf, err := config.Default() + if err != nil { + log.Fatal(err) + } log.Printf("Generating measurements for %s\n", defaultConf.Image) const filePath = "./measurements_enterprise.go" diff --git a/internal/attestationapi/BUILD.bazel b/internal/attestationapi/BUILD.bazel new file mode 100644 index 000000000..ab0a6b762 --- /dev/null +++ b/internal/attestationapi/BUILD.bazel @@ -0,0 +1,29 @@ +load("@io_bazel_rules_go//go:def.bzl", "go_library") +load("//bazel/go:go_test.bzl", "go_test") + +go_library( + name = "attestationapi", + srcs = ["attestationapi.go"], + importpath = "github.com/edgelesssys/constellation/v2/internal/attestationapi", + visibility = ["//:__subpackages__"], + deps = [ + "//internal/kms/storage", + "//internal/kms/storage/awss3", + "//internal/kms/uri", + "//internal/variant", + "//internal/versionsapi", + "//internal/versionsapi/fetcher", + ], +) + +go_test( + name = "attestationapi_test", + srcs = ["attestationapi_test.go"], + deps = [ + ":attestationapi", + "//internal/kms/uri", + "//internal/variant", + "@com_github_stretchr_testify//assert", + "@com_github_stretchr_testify//require", + ], +) diff --git a/internal/attestationapi/attestationapi.go b/internal/attestationapi/attestationapi.go new file mode 100644 index 000000000..99971d2b2 --- /dev/null +++ b/internal/attestationapi/attestationapi.go @@ -0,0 +1,149 @@ +package attestationapi + +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" + "github.com/edgelesssys/constellation/v2/internal/versionsapi" + "github.com/edgelesssys/constellation/v2/internal/versionsapi/fetcher" +) + +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. +) + +// AttestationPath is the path to the attestation versions. +const AttestationPath = "constellation/v1/attestation" + +// AzureSEVSNP is the latest version of each component of the Azure SEVSNP. +// used for testing only +var AzureSEVSNP = versionsapi.AzureSEVSNPVersion{ + Bootloader: 2, + TEE: 0, + SNP: 6, + Microcode: 93, +} + +// Type is the type of the version to be requested. +type Type (string) + +// 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 versionsapi.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", AttestationPath, variant.String(), fname), bt) + if err != nil { + return err + } + return a.addVersionToList(ctx, variant, fname) +} + +func (a AttestationVersionRepo) addVersionToList(ctx context.Context, attestation variant.Variant, fname string) error { + versions := []string{} + key := path.Join(AttestationPath, 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) +} + +// 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(AttestationPath, 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(AttestationPath, attestation.String(), "list"), bt) +} + +func GetVersionByType(res versionsapi.AzureSEVSNPVersion, t Type) uint8 { + switch t { + case Bootloader: + return res.Bootloader + case TEE: + return res.TEE + case SNP: + return res.SNP + case Microcode: + return res.Microcode + default: + return 1 + } +} + +// GetAzureSEVSNPVersion returns the requested version of the given type. +func GetAzureSEVSNPVersion(ctx context.Context) (res versionsapi.AzureSEVSNPVersion, err error) { + var versions versionsapi.AzureSEVSNPVersionList + fetcher := fetcher.NewFetcher() + versions, err = fetcher.FetchAttestationList(ctx, versions) + if err != nil { + return res, fmt.Errorf("failed fetching versions list: %w", err) + } + if len(versions) < 1 { + return res, errors.New("no versions found in /list") + } + get := versionsapi.AzureSEVSNPVersionGet{Version: versions[0]} // get latest version (as sorted reversely alphanumerically) + get, err = fetcher.FetchAttestationVersion(ctx, get) + if err != nil { + return res, fmt.Errorf("failed fetching version: %w", err) + } + return get.AzureSEVSNPVersion, nil +} diff --git a/internal/attestationapi/attestationapi_test.go b/internal/attestationapi/attestationapi_test.go new file mode 100644 index 000000000..ac9e05115 --- /dev/null +++ b/internal/attestationapi/attestationapi_test.go @@ -0,0 +1,77 @@ +package attestationapi_test + +import ( + "context" + "flag" + "os" + "testing" + "time" + + "github.com/edgelesssys/constellation/v2/internal/attestationapi" + "github.com/edgelesssys/constellation/v2/internal/kms/uri" + "github.com/edgelesssys/constellation/v2/internal/variant" + "github.com/stretchr/testify/assert" + "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() + panic("Required flags not set: --aws-access-key, --aws-access-key-id, --aws-bucket, --aws-region") + } + os.Exit(m.Run()) +} + +var cfg = uri.AWSS3Config{ + Bucket: *awsBucket, + AccessKeyID: *awsAccessKeyID, + AccessKey: *awsAccessKey, + Region: *awsRegion, +} + +func TestUploadAzureSEVSNPVersions(t *testing.T) { + ctx := context.Background() + sut, err := attestationapi.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, attestationapi.AzureSEVSNP, d)) +} + +func TestListVersions(t *testing.T) { + ctx := context.Background() + + sut, err := attestationapi.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, attestationapi.AzureSEVSNP, 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) +} + +func TestGetVersion(t *testing.T) { + ctx := context.Background() + res, err := attestationapi.GetAzureSEVSNPVersion(ctx) + require.NoError(t, err) + assert.Equal(t, uint8(2), res.Bootloader) +} diff --git a/internal/config/BUILD.bazel b/internal/config/BUILD.bazel index cfd4ed8f1..b4710df0e 100644 --- a/internal/config/BUILD.bazel +++ b/internal/config/BUILD.bazel @@ -20,6 +20,7 @@ go_library( deps = [ "//internal/attestation/idkeydigest", "//internal/attestation/measurements", + "//internal/attestationapi", "//internal/cloud/cloudprovider", "//internal/compatibility", "//internal/config/imageversion", diff --git a/internal/config/attestation_test.go b/internal/config/attestation_test.go index 1a42ee38b..dc1775cb6 100644 --- a/internal/config/attestation_test.go +++ b/internal/config/attestation_test.go @@ -23,6 +23,8 @@ import ( var testCertPEM = `-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n` func TestUnmarshalAttestationConfig(t *testing.T) { + azureSEVSNP, err := DefaultForAzureSEVSNP() + require.NoError(t, err) testCases := map[string]struct { cfg AttestationCfg }{ @@ -30,7 +32,7 @@ func TestUnmarshalAttestationConfig(t *testing.T) { cfg: &AWSNitroTPM{Measurements: measurements.DefaultsFor(cloudprovider.AWS, variant.AWSNitroTPM{})}, }, "AzureSEVSNP": { - cfg: DefaultForAzureSEVSNP(), + cfg: azureSEVSNP, }, "AzureTrustedLaunch": { cfg: &AzureTrustedLaunch{Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureTrustedLaunch{})}, diff --git a/internal/config/azure.go b/internal/config/azure.go index 171b548a1..0a2ccfb3c 100644 --- a/internal/config/azure.go +++ b/internal/config/azure.go @@ -8,16 +8,19 @@ package config import ( "bytes" + "context" "fmt" "strconv" "strings" "github.com/edgelesssys/constellation/v2/internal/attestation/idkeydigest" "github.com/edgelesssys/constellation/v2/internal/attestation/measurements" + "github.com/edgelesssys/constellation/v2/internal/attestationapi" "github.com/edgelesssys/constellation/v2/internal/cloud/cloudprovider" "github.com/edgelesssys/constellation/v2/internal/config/snpversion" "github.com/edgelesssys/constellation/v2/internal/config/version" "github.com/edgelesssys/constellation/v2/internal/variant" + "github.com/edgelesssys/constellation/v2/internal/versionsapi" ) // AzureSEVSNP is the configuration for Azure SEV-SNP attestation. @@ -47,20 +50,26 @@ 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. -func DefaultForAzureSEVSNP() *AzureSEVSNP { +func DefaultForAzureSEVSNP() (*AzureSEVSNP, error) { + ctx := context.Background() + version, err := attestationapi.GetAzureSEVSNPVersion(ctx) + if err != nil { + return nil, err + } + 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: version.Bootloader, + TEEVersion: version.TEE, + SNPVersion: version.SNP, + MicrocodeVersion: version.Microcode, FirmwareSignerConfig: SNPFirmwareSignerConfig{ AcceptedKeyDigests: idkeydigest.DefaultList(), EnforcementPolicy: idkeydigest.MAAFallback, }, // AMD root key. Received from the AMD Key Distribution System API (KDS). AMDRootKey: mustParsePEM(`-----BEGIN CERTIFICATE-----\nMIIGYzCCBBKgAwIBAgIDAQAAMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAIC\nBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBMHsxFDAS\nBgNVBAsMC0VuZ2luZWVyaW5nMQswCQYDVQQGEwJVUzEUMBIGA1UEBwwLU2FudGEg\nQ2xhcmExCzAJBgNVBAgMAkNBMR8wHQYDVQQKDBZBZHZhbmNlZCBNaWNybyBEZXZp\nY2VzMRIwEAYDVQQDDAlBUkstTWlsYW4wHhcNMjAxMDIyMTcyMzA1WhcNNDUxMDIy\nMTcyMzA1WjB7MRQwEgYDVQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDAS\nBgNVBAcMC1NhbnRhIENsYXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5j\nZWQgTWljcm8gRGV2aWNlczESMBAGA1UEAwwJQVJLLU1pbGFuMIICIjANBgkqhkiG\n9w0BAQEFAAOCAg8AMIICCgKCAgEA0Ld52RJOdeiJlqK2JdsVmD7FktuotWwX1fNg\nW41XY9Xz1HEhSUmhLz9Cu9DHRlvgJSNxbeYYsnJfvyjx1MfU0V5tkKiU1EesNFta\n1kTA0szNisdYc9isqk7mXT5+KfGRbfc4V/9zRIcE8jlHN61S1ju8X93+6dxDUrG2\nSzxqJ4BhqyYmUDruPXJSX4vUc01P7j98MpqOS95rORdGHeI52Naz5m2B+O+vjsC0\n60d37jY9LFeuOP4Meri8qgfi2S5kKqg/aF6aPtuAZQVR7u3KFYXP59XmJgtcog05\ngmI0T/OitLhuzVvpZcLph0odh/1IPXqx3+MnjD97A7fXpqGd/y8KxX7jksTEzAOg\nbKAeam3lm+3yKIcTYMlsRMXPcjNbIvmsBykD//xSniusuHBkgnlENEWx1UcbQQrs\n+gVDkuVPhsnzIRNgYvM48Y+7LGiJYnrmE8xcrexekBxrva2V9TJQqnN3Q53kt5vi\nQi3+gCfmkwC0F0tirIZbLkXPrPwzZ0M9eNxhIySb2npJfgnqz55I0u33wh4r0ZNQ\neTGfw03MBUtyuzGesGkcw+loqMaq1qR4tjGbPYxCvpCq7+OgpCCoMNit2uLo9M18\nfHz10lOMT8nWAUvRZFzteXCm+7PHdYPlmQwUw3LvenJ/ILXoQPHfbkH0CyPfhl1j\nWhJFZasCAwEAAaN+MHwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSFrBrRQ/fI\nrFXUxR1BSKvVeErUUzAPBgNVHRMBAf8EBTADAQH/MDoGA1UdHwQzMDEwL6AtoCuG\nKWh0dHBzOi8va2RzaW50Zi5hbWQuY29tL3ZjZWsvdjEvTWlsYW4vY3JsMEYGCSqG\nSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0BAQgwDQYJYIZI\nAWUDBAICBQCiAwIBMKMDAgEBA4ICAQC6m0kDp6zv4Ojfgy+zleehsx6ol0ocgVel\nETobpx+EuCsqVFRPK1jZ1sp/lyd9+0fQ0r66n7kagRk4Ca39g66WGTJMeJdqYriw\nSTjjDCKVPSesWXYPVAyDhmP5n2v+BYipZWhpvqpaiO+EGK5IBP+578QeW/sSokrK\ndHaLAxG2LhZxj9aF73fqC7OAJZ5aPonw4RE299FVarh1Tx2eT3wSgkDgutCTB1Yq\nzT5DuwvAe+co2CIVIzMDamYuSFjPN0BCgojl7V+bTou7dMsqIu/TW/rPCX9/EUcp\nKGKqPQ3P+N9r1hjEFY1plBg93t53OOo49GNI+V1zvXPLI6xIFVsh+mto2RtgEX/e\npmMKTNN6psW88qg7c1hTWtN6MbRuQ0vm+O+/2tKBF2h8THb94OvvHHoFDpbCELlq\nHnIYhxy0YKXGyaW1NjfULxrrmxVW4wcn5E8GddmvNa6yYm8scJagEi13mhGu4Jqh\n3QU3sf8iUSUr09xQDwHtOQUVIqx4maBZPBtSMf+qUDtjXSSq8lfWcd8bLr9mdsUn\nJZJ0+tuPMKmBnSH860llKk+VpVQsgqbzDIvOLvD6W1Umq25boxCYJ+TuBoa4s+HH\nCViAvgT9kf/rBq1d+ivj6skkHxuzcxbk1xv6ZGxrteJxVH7KlX7YRdZ6eARKwLe4\nAFZEAwoKCQ==\n-----END CERTIFICATE-----\n`), - } + }, nil } // GetVariant returns azure-sev-snp as the variant. @@ -97,25 +106,49 @@ func (c AzureSEVSNP) EqualTo(old AttestationCfg) (bool, error) { } // UnmarshalYAML implements a custom unmarshaler to support setting "latest" as version. -func (c *AzureSEVSNP) UnmarshalYAML(unmarshal func(any) error) error { +func (a *AzureSEVSNP) UnmarshalYAML(unmarshal func(interface{}) error) error { aux := &fusedAzureSEVSNP{ - auxAzureSEVSNP: (*auxAzureSEVSNP)(c), + auxAzureSEVSNP: (*auxAzureSEVSNP)(a), } if err := unmarshal(aux); err != nil { return fmt.Errorf("unmarshal AzureSEVSNP: %w", err) } - c = (*AzureSEVSNP)(aux.auxAzureSEVSNP) + a = (*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) + versions, err := attestationapi.GetAzureSEVSNPVersion(context.Background()) + if err != nil { + return fmt.Errorf("failed to get AzureSEVSNP versions: %w", err) + } + for _, versionType := range []attestationapi.Type{attestationapi.Bootloader, attestationapi.TEE, attestationapi.SNP, attestationapi.Microcode} { + if !convertLatestToNumber(a, versions, versionType, aux) { + if err := convertStringToUint(a, versionType, aux); err != nil { + return fmt.Errorf("failed to convert %s version to number: %w", versionType, err) } } } return nil } +func getUintAndStringPtrToVersion(c *AzureSEVSNP, versionType attestationapi.Type, aux *fusedAzureSEVSNP) (*uint8, *string) { + var v *uint8 + var stringV *string + switch versionType { + case attestationapi.Bootloader: + v = &c.BootloaderVersion + stringV = &aux.BootloaderVersion + case attestationapi.TEE: + v = &c.TEEVersion + stringV = &aux.TEEVersion + case attestationapi.SNP: + v = &c.SNPVersion + stringV = &aux.SNPVersion + case attestationapi.Microcode: + v = &c.MicrocodeVersion + stringV = &aux.MicrocodeVersion + } + return v, stringV +} + // AzureTrustedLaunch is the configuration for Azure Trusted Launch attestation. type AzureTrustedLaunch struct { // description: | @@ -180,13 +213,13 @@ type fusedAzureSEVSNP struct { // Lowest acceptable bootloader version. BootloaderVersion string `yaml:"bootloaderVersion"` // description: | - // Lowest acceptable bootloader version. + // Lowest acceptable TEE version. TEEVersion string `yaml:"teeVersion"` // description: | - // Lowest acceptable bootloader version. + // Lowest acceptable SEV-SNP version. SNPVersion string `yaml:"snpVersion"` // description: | - // Lowest acceptable bootloader version. + // Lowest acceptable microcode version. MicrocodeVersion string `yaml:"microcodeVersion"` } @@ -201,29 +234,11 @@ func convertStringToUint(c *AzureSEVSNP, versionType snpversion.Type, aux *fused return nil } -func convertLatestToNumber(c *AzureSEVSNP, versionType snpversion.Type, aux *fusedAzureSEVSNP) bool { +func convertLatestToNumber(c *AzureSEVSNP, versions versionsapi.AzureSEVSNPVersion, versionType version.Type, aux *fusedAzureSEVSNP) bool { v, stringV := getUintAndStringPtrToVersion(c, versionType, aux) if strings.ToLower(*stringV) == "latest" { - *v = snpversion.GetLatest(versionType) + *v = attestationapi.GetVersionByType(versions, versionType) return true } return false } - -func getUintAndStringPtrToVersion(c *AzureSEVSNP, versionType version.Type, aux *fusedAzureSEVSNP) (versionUint *uint8, versionString *string) { - switch versionType { - case version.Bootloader: - versionUint = &c.BootloaderVersion - versionString = &aux.BootloaderVersion - case version.TEE: - versionUint = &c.TEEVersion - versionString = &aux.TEEVersion - case version.SNP: - versionUint = &c.SNPVersion - versionString = &aux.SNPVersion - case version.Microcode: - versionUint = &c.MicrocodeVersion - versionString = &aux.MicrocodeVersion - } - return -} diff --git a/internal/config/config.go b/internal/config/config.go index 67855ab69..e061a97b3 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -297,7 +297,11 @@ type AttestationConfig struct { } // Default returns a struct with the default config. -func Default() *Config { +func Default() (*Config, error) { + azureSEVSNP, err := DefaultForAzureSEVSNP() + if err != nil { + return nil, err + } return &Config{ Version: Version3, Image: defaultImage, @@ -357,12 +361,21 @@ func Default() *Config { // AWS will have aws-sev-snp as attestation variant Attestation: AttestationConfig{ AWSNitroTPM: &AWSNitroTPM{Measurements: measurements.DefaultsFor(cloudprovider.AWS, variant.AWSNitroTPM{})}, - AzureSEVSNP: DefaultForAzureSEVSNP(), + AzureSEVSNP: azureSEVSNP, AzureTrustedLaunch: &AzureTrustedLaunch{Measurements: measurements.DefaultsFor(cloudprovider.Azure, variant.AzureTrustedLaunch{})}, GCPSEVES: &GCPSEVES{Measurements: measurements.DefaultsFor(cloudprovider.GCP, variant.GCPSEVES{})}, QEMUVTPM: &QEMUVTPM{Measurements: measurements.DefaultsFor(cloudprovider.QEMU, variant.QEMUVTPM{})}, }, + }, nil +} + +// DefaultWithPanic returns a struct with the default config. +func DefaultWithPanic() *Config { + conf, err := Default() + if err != nil { + panic(err) } + return conf } // fromFile returns config file with `name` read from `fileHandler` by parsing @@ -404,7 +417,11 @@ func New(fileHandler file.Handler, name string, force bool) (*Config, error) { // Backwards compatibility: configs without the field `microserviceVersion` are valid in version 2.6. // In case the field is not set in an old config we prefill it with the default value. if c.MicroserviceVersion == "" { - c.MicroserviceVersion = Default().MicroserviceVersion + azureSEVSNP, err := Default() + if err != nil { + return nil, err + } + c.MicroserviceVersion = azureSEVSNP.MicroserviceVersion } return c, c.Validate(force) diff --git a/internal/config/config_test.go b/internal/config/config_test.go index ea8f50e6f..78037605a 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -33,7 +33,7 @@ func TestMain(m *testing.M) { func TestDefaultConfig(t *testing.T) { assert := assert.New(t) - def := Default() + def := DefaultWithPanic() assert.NotNil(def) } @@ -46,11 +46,11 @@ func TestSettingLatestAsVersion(t *testing.T) { }{ "mix of latest and uint as version value": { config: func() map[string]interface{} { - conf := Default() + conf := DefaultWithPanic() // 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{})["teeVersion"] = "Latest" m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["snpVersion"] = "latest" m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["bootloaderVersion"] = 1 return m @@ -58,14 +58,15 @@ func TestSettingLatestAsVersion(t *testing.T) { configName: constants.ConfigFilename, wantResult: func() *Config { - conf := Default() + conf := DefaultWithPanic() conf.Attestation.AzureSEVSNP.BootloaderVersion = 1 + conf.Attestation.AzureSEVSNP.MicrocodeVersion = 93 return conf }(), }, "refuse invalid version value": { config: func() map[string]interface{} { - conf := Default() + conf := DefaultWithPanic() m := getConfigAsMap(conf, t) m["attestation"].(map[string]interface{})["azureSEVSNP"].(map[string]interface{})["microcodeVersion"] = "1a" return m @@ -115,14 +116,14 @@ func TestFromFile(t *testing.T) { wantErr bool }{ "default config from default file": { - config: Default(), + config: DefaultWithPanic(), configName: constants.ConfigFilename, - wantResult: Default(), + wantResult: DefaultWithPanic(), }, "default config from different path": { - config: Default(), + config: DefaultWithPanic(), configName: "other-config.yaml", - wantResult: Default(), + wantResult: DefaultWithPanic(), }, "default config when path empty": { config: nil, @@ -145,14 +146,14 @@ func TestFromFile(t *testing.T) { }, "modify default config": { config: func() *Config { - conf := Default() + conf := DefaultWithPanic() conf.Provider.GCP.Region = "eu-north1" conf.Provider.GCP.Zone = "eu-north1-a" return conf }(), configName: constants.ConfigFilename, wantResult: func() *Config { - conf := Default() + conf := DefaultWithPanic() conf.Provider.GCP.Region = "eu-north1" conf.Provider.GCP.Zone = "eu-north1-a" return conf @@ -191,7 +192,7 @@ func TestNewWithDefaultOptions(t *testing.T) { }{ "set env works": { confToWrite: func() *Config { // valid config with all, but clientSecretValue - c := Default() + c := DefaultWithPanic() c.RemoveProviderAndAttestationExcept(cloudprovider.Azure) c.Image = "v" + constants.VersionInfo() c.Provider.Azure.SubscriptionID = "f4278079-288c-4766-a98c-ab9d5dba01a5" @@ -212,7 +213,7 @@ func TestNewWithDefaultOptions(t *testing.T) { }, "set env overwrites": { confToWrite: func() *Config { - c := Default() + c := DefaultWithPanic() c.RemoveProviderAndAttestationExcept(cloudprovider.Azure) c.Image = "v" + constants.VersionInfo() c.Provider.Azure.SubscriptionID = "f4278079-288c-4766-a98c-ab9d5dba01a5" @@ -276,13 +277,13 @@ func TestValidate(t *testing.T) { wantErrCount int }{ "default config is not valid": { - cnf: Default(), + cnf: DefaultWithPanic(), wantErr: true, wantErrCount: defaultErrCount, }, "v0 is one error": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.Version = "v0" return cnf }(), @@ -291,7 +292,7 @@ func TestValidate(t *testing.T) { }, "v0 and negative state disk are two errors": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.Version = "v0" cnf.StateDiskSizeGB = -1 return cnf @@ -301,7 +302,7 @@ func TestValidate(t *testing.T) { }, "default Azure config is not valid": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.RemoveProviderAndAttestationExcept(cloudprovider.Azure) return cnf }(), @@ -310,7 +311,7 @@ func TestValidate(t *testing.T) { }, "Azure config with all required fields is valid": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.RemoveProviderAndAttestationExcept(cloudprovider.Azure) cnf.Image = "v" + constants.VersionInfo() az := cnf.Provider.Azure @@ -331,7 +332,7 @@ func TestValidate(t *testing.T) { }, "default GCP config is not valid": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.RemoveProviderAndAttestationExcept(cloudprovider.GCP) return cnf }(), @@ -340,7 +341,7 @@ func TestValidate(t *testing.T) { }, "GCP config with all required fields is valid": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.RemoveProviderAndAttestationExcept(cloudprovider.GCP) cnf.Image = "v" + constants.VersionInfo() gcp := cnf.Provider.GCP @@ -359,7 +360,7 @@ func TestValidate(t *testing.T) { // TODO: v2.7: remove this test as it should start breaking after v2.6 is released. "k8s vMAJOR.MINOR is valid in v2.7": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.KubernetesVersion = "v1.25" return cnf }(), @@ -369,7 +370,7 @@ func TestValidate(t *testing.T) { // TODO: v2.7: remove this test as it should start breaking after v2.6 is released. "k8s MAJOR.MINOR is valid in v2.7": { cnf: func() *Config { - cnf := Default() + cnf := DefaultWithPanic() cnf.KubernetesVersion = "1.25" return cnf }(), @@ -403,9 +404,9 @@ func TestHasProvider(t *testing.T) { assert.False((&Config{}).HasProvider(cloudprovider.Azure)) assert.False((&Config{}).HasProvider(cloudprovider.GCP)) assert.False((&Config{}).HasProvider(cloudprovider.QEMU)) - assert.False(Default().HasProvider(cloudprovider.Unknown)) - assert.True(Default().HasProvider(cloudprovider.Azure)) - assert.True(Default().HasProvider(cloudprovider.GCP)) + assert.False(DefaultWithPanic().HasProvider(cloudprovider.Unknown)) + assert.True(DefaultWithPanic().HasProvider(cloudprovider.Azure)) + assert.True(DefaultWithPanic().HasProvider(cloudprovider.GCP)) cnfWithAzure := Config{Provider: ProviderConfig{Azure: &AzureConfig{}}} assert.False(cnfWithAzure.HasProvider(cloudprovider.Unknown)) assert.True(cnfWithAzure.HasProvider(cloudprovider.Azure)) @@ -422,26 +423,26 @@ func TestConfigRemoveProviderExcept(t *testing.T) { }{ "except aws": { removeExcept: cloudprovider.AWS, - wantAWS: Default().Provider.AWS, + wantAWS: DefaultWithPanic().Provider.AWS, }, "except azure": { removeExcept: cloudprovider.Azure, - wantAzure: Default().Provider.Azure, + wantAzure: DefaultWithPanic().Provider.Azure, }, "except gcp": { removeExcept: cloudprovider.GCP, - wantGCP: Default().Provider.GCP, + wantGCP: DefaultWithPanic().Provider.GCP, }, "except qemu": { removeExcept: cloudprovider.QEMU, - wantQEMU: Default().Provider.QEMU, + wantQEMU: DefaultWithPanic().Provider.QEMU, }, "unknown provider": { removeExcept: cloudprovider.Unknown, - wantAWS: Default().Provider.AWS, - wantAzure: Default().Provider.Azure, - wantGCP: Default().Provider.GCP, - wantQEMU: Default().Provider.QEMU, + wantAWS: DefaultWithPanic().Provider.AWS, + wantAzure: DefaultWithPanic().Provider.Azure, + wantGCP: DefaultWithPanic().Provider.GCP, + wantQEMU: DefaultWithPanic().Provider.QEMU, }, } @@ -449,7 +450,7 @@ func TestConfigRemoveProviderExcept(t *testing.T) { t.Run(name, func(t *testing.T) { assert := assert.New(t) - conf := Default() + conf := DefaultWithPanic() conf.RemoveProviderAndAttestationExcept(tc.removeExcept) assert.Equal(tc.wantAWS, conf.Provider.AWS) @@ -481,7 +482,7 @@ func TestConfig_UpdateMeasurements(t *testing.T) { } { // AWS - conf := Default() + conf := DefaultWithPanic() conf.RemoveProviderAndAttestationExcept(cloudprovider.AWS) for k := range conf.Attestation.AWSNitroTPM.Measurements { delete(conf.Attestation.AWSNitroTPM.Measurements, k) @@ -490,7 +491,7 @@ func TestConfig_UpdateMeasurements(t *testing.T) { assert.Equal(newMeasurements, conf.Attestation.AWSNitroTPM.Measurements) } { // Azure - conf := Default() + conf := DefaultWithPanic() conf.RemoveProviderAndAttestationExcept(cloudprovider.Azure) for k := range conf.Attestation.AzureSEVSNP.Measurements { delete(conf.Attestation.AzureSEVSNP.Measurements, k) @@ -499,7 +500,7 @@ func TestConfig_UpdateMeasurements(t *testing.T) { assert.Equal(newMeasurements, conf.Attestation.AzureSEVSNP.Measurements) } { // GCP - conf := Default() + conf := DefaultWithPanic() conf.RemoveProviderAndAttestationExcept(cloudprovider.GCP) for k := range conf.Attestation.GCPSEVES.Measurements { delete(conf.Attestation.GCPSEVES.Measurements, k) @@ -508,7 +509,7 @@ func TestConfig_UpdateMeasurements(t *testing.T) { assert.Equal(newMeasurements, conf.Attestation.GCPSEVES.Measurements) } { // QEMU - conf := Default() + conf := DefaultWithPanic() conf.RemoveProviderAndAttestationExcept(cloudprovider.QEMU) for k := range conf.Attestation.QEMUVTPM.Measurements { delete(conf.Attestation.QEMUVTPM.Measurements, k) @@ -525,7 +526,7 @@ func TestConfig_IsReleaseImage(t *testing.T) { }{ "release image v0.0.0": { conf: func() *Config { - conf := Default() + conf := DefaultWithPanic() conf.Image = "v0.0.0" return conf }(), @@ -533,7 +534,7 @@ func TestConfig_IsReleaseImage(t *testing.T) { }, "branch image": { conf: func() *Config { - conf := Default() + conf := DefaultWithPanic() conf.Image = "feat-x-vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef" return conf }(), @@ -541,7 +542,7 @@ func TestConfig_IsReleaseImage(t *testing.T) { }, "debug image": { conf: func() *Config { - conf := Default() + conf := DefaultWithPanic() conf.Image = "debug-vX.Y.Z-pre.0.yyyymmddhhmmss-abcdefabcdef" return conf }(), @@ -687,11 +688,11 @@ func TestIsDebugCluster(t *testing.T) { expectedResult: false, }, "default config": { - config: Default(), + config: DefaultWithPanic(), expectedResult: false, }, "enabled": { - config: Default(), + config: DefaultWithPanic(), prepareConfig: func(conf *Config) { *conf.DebugCluster = true }, @@ -754,7 +755,7 @@ func TestValidateProvider(t *testing.T) { v := validator.New() trans := ut.New(en.New()).GetFallback() - conf := Default() + conf := DefaultWithPanic() conf.Provider = tc.provider v.RegisterStructValidation(validateProvider, ProviderConfig{}) diff --git a/internal/config/migration/migration.go b/internal/config/migration/migration.go index a7dca266f..51795a23f 100644 --- a/internal/config/migration/migration.go +++ b/internal/config/migration/migration.go @@ -242,7 +242,11 @@ func V2ToV3(path string, fileHandler file.Handler) error { Measurements: cfgV2.Provider.Azure.Measurements, } } else { - cfgV3.Attestation.AzureSEVSNP = config.DefaultForAzureSEVSNP() + azureSEVSNP, err := config.DefaultForAzureSEVSNP() + if err != nil { + return err + } + cfgV3.Attestation.AzureSEVSNP = azureSEVSNP cfgV3.Attestation.AzureSEVSNP.Measurements = cfgV2.Provider.Azure.Measurements cfgV3.Attestation.AzureSEVSNP.FirmwareSignerConfig = config.SNPFirmwareSignerConfig{ AcceptedKeyDigests: cfgV2.Provider.Azure.IDKeyDigest, diff --git a/internal/config/version/BUILD.bazel b/internal/config/version/BUILD.bazel deleted file mode 100644 index 92221bd3c..000000000 --- a/internal/config/version/BUILD.bazel +++ /dev/null @@ -1,8 +0,0 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library") - -go_library( - name = "version", - srcs = ["version.go"], - importpath = "github.com/edgelesssys/constellation/v2/internal/config/version", - visibility = ["//:__subpackages__"], -) diff --git a/internal/config/version/version.go b/internal/config/version/version.go deleted file mode 100644 index 0f13ce222..000000000 --- a/internal/config/version/version.go +++ /dev/null @@ -1,33 +0,0 @@ -/* -Copyright (c) Edgeless Systems GmbH - -SPDX-License-Identifier: AGPL-3.0-only -*/ - -package version - -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) - -// GetVersion returns the version of the given type. -func GetVersion(t Type) uint8 { - switch t { - case Bootloader: - return 2 - case TEE: - return 0 - case SNP: - return 6 - case Microcode: - return 93 - default: - return 1 - } -} 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 diff --git a/internal/versionsapi/BUILD.bazel b/internal/versionsapi/BUILD.bazel index a65965ee5..f2b20fb5b 100644 --- a/internal/versionsapi/BUILD.bazel +++ b/internal/versionsapi/BUILD.bazel @@ -4,6 +4,7 @@ load("//bazel/go:go_test.bzl", "go_test") go_library( name = "versionsapi", srcs = [ + "attestation.go", "cliinfo.go", "imageinfo.go", "latest.go", @@ -16,6 +17,7 @@ go_library( deps = [ "//internal/cloud/cloudprovider", "//internal/constants", + "//internal/variant", "@org_golang_x_mod//semver", ], ) diff --git a/internal/versionsapi/attestation.go b/internal/versionsapi/attestation.go new file mode 100644 index 000000000..43be71403 --- /dev/null +++ b/internal/versionsapi/attestation.go @@ -0,0 +1,74 @@ +package versionsapi + +import ( + "fmt" + "net/url" + "path" + + "github.com/edgelesssys/constellation/v2/internal/constants" + "github.com/edgelesssys/constellation/v2/internal/variant" +) + +// AttestationPath is the path to the attestation versions. +const AttestationPath = "constellation/v1/attestation" // TODO already in attestationonapi but import cycle otherwise + +// 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"` +} + +type AzureSEVSNPVersionGet struct { + Version string `json:"-"` + AzureSEVSNPVersion +} + +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 +} + +func (i AzureSEVSNPVersionGet) JSONPath() string { + return path.Join(AttestationPath, variant.AzureSEVSNP{}.String(), i.Version) +} + +func (i AzureSEVSNPVersionGet) ValidateRequest() error { + return nil +} + +func (i AzureSEVSNPVersionGet) Validate() error { + return nil +} + +type AzureSEVSNPVersionList ([]string) + +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 +} + +func (i AzureSEVSNPVersionList) JSONPath() string { + return path.Join(AttestationPath, variant.AzureSEVSNP{}.String(), "list") +} + +func (i AzureSEVSNPVersionList) ValidateRequest() error { + return nil +} + +func (i AzureSEVSNPVersionList) Validate() error { + return nil +} diff --git a/internal/versionsapi/fetcher/fetcher.go b/internal/versionsapi/fetcher/fetcher.go index 930e4eebc..051f22ff1 100644 --- a/internal/versionsapi/fetcher/fetcher.go +++ b/internal/versionsapi/fetcher/fetcher.go @@ -54,6 +54,14 @@ func (f *Fetcher) FetchCLIInfo(ctx context.Context, cliInfo versionsapi.CLIInfo) return fetch(ctx, f.httpc, cliInfo) } +func (f *Fetcher) FetchAttestationList(ctx context.Context, attestation versionsapi.AzureSEVSNPVersionList) (versionsapi.AzureSEVSNPVersionList, error) { + return fetch(ctx, f.httpc, attestation) +} + +func (f *Fetcher) FetchAttestationVersion(ctx context.Context, attestation versionsapi.AzureSEVSNPVersionGet) (versionsapi.AzureSEVSNPVersionGet, error) { + return fetch(ctx, f.httpc, attestation) +} + type apiObject interface { ValidateRequest() error Validate() error diff --git a/internal/watcher/validator_test.go b/internal/watcher/validator_test.go index 044d295b1..e37e769a2 100644 --- a/internal/watcher/validator_test.go +++ b/internal/watcher/validator_test.go @@ -38,6 +38,8 @@ func TestMain(m *testing.M) { } func TestNewUpdateableValidator(t *testing.T) { + azureSEVSNP, err := config.DefaultForAzureSEVSNP() + require.NoError(t, err) testCases := map[string]struct { variant variant.Variant config config.AttestationCfg @@ -45,7 +47,7 @@ func TestNewUpdateableValidator(t *testing.T) { }{ "azure": { variant: variant.AzureSEVSNP{}, - config: config.DefaultForAzureSEVSNP(), + config: azureSEVSNP, }, "gcp": { variant: variant.GCPSEVES{},