diff --git a/cli/internal/cloudcmd/validators.go b/cli/internal/cloudcmd/validators.go index c43216194..04f45d76b 100644 --- a/cli/internal/cloudcmd/validators.go +++ b/cli/internal/cloudcmd/validators.go @@ -52,7 +52,7 @@ func NewValidator(provider cloudprovider.Provider, conf *config.Config) (*Valida v.azureCVM = *conf.Provider.Azure.ConfidentialVM if v.azureCVM { v.enforceIDKeyDigest = *conf.Provider.Azure.EnforceIDKeyDigest - v.idkeydigests = conf.Provider.Azure.IDKeyDigests + v.idkeydigests = conf.Provider.Azure.IDKeyDigest } } diff --git a/cli/internal/cloudcmd/validators_test.go b/cli/internal/cloudcmd/validators_test.go index 540e882e3..fbcd2d74a 100644 --- a/cli/internal/cloudcmd/validators_test.go +++ b/cli/internal/cloudcmd/validators_test.go @@ -89,7 +89,7 @@ func TestNewValidator(t *testing.T) { conf.Provider.GCP = &config.GCPConfig{Measurements: tc.pcrs} } if tc.provider == cloudprovider.Azure { - conf.Provider.Azure = &config.AzureConfig{Measurements: tc.pcrs, EnforceIDKeyDigest: &tc.enforceIDKeyDigest, IDKeyDigests: tc.digest, ConfidentialVM: &tc.azureCVM} + conf.Provider.Azure = &config.AzureConfig{Measurements: tc.pcrs, EnforceIDKeyDigest: &tc.enforceIDKeyDigest, IDKeyDigest: tc.digest, ConfidentialVM: &tc.azureCVM} } if tc.provider == cloudprovider.QEMU { conf.Provider.QEMU = &config.QEMUConfig{Measurements: tc.pcrs} diff --git a/internal/config/config.go b/internal/config/config.go index c8bbdd7b5..0f04e9d64 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -175,7 +175,7 @@ type AzureConfig struct { SecureBoot *bool `yaml:"secureBoot" validate:"required"` // description: | // List of accepted values for the field 'idkeydigest' in the AMD SEV-SNP attestation report. Only usable with ConfidentialVMs. See 4.6 and 7.3 in: https://www.amd.com/system/files/TechDocs/56860.pdf - IDKeyDigests Digests `yaml:"idKeyDigests" validate:"required_if=EnforceIdKeyDigest true,omitempty"` + IDKeyDigest Digests `yaml:"idKeyDigest" validate:"required_if=EnforceIdKeyDigest true,omitempty"` // description: | // Enforce the specified idKeyDigest value during remote attestation. EnforceIDKeyDigest *bool `yaml:"enforceIdKeyDigest" validate:"required"` @@ -268,7 +268,7 @@ func Default() *Config { InstanceType: "Standard_DC4as_v5", StateDiskType: "Premium_LRS", DeployCSIDriver: func() *bool { b := true; return &b }(), - IDKeyDigests: idkeydigest.DefaultsFor(cloudprovider.Azure), + IDKeyDigest: idkeydigest.DefaultsFor(cloudprovider.Azure), EnforceIDKeyDigest: func() *bool { b := true; return &b }(), ConfidentialVM: func() *bool { b := true; return &b }(), SecureBoot: func() *bool { b := false; return &b }(), @@ -444,7 +444,7 @@ func (c *Config) EnforcedPCRs() []uint32 { // IDKeyDigests returns the ID Key Digests for the configured cloud provider. func (c *Config) IDKeyDigests() idkeydigest.IDKeyDigests { if c.Provider.Azure != nil { - return c.Provider.Azure.IDKeyDigests + return c.Provider.Azure.IDKeyDigest } return nil } diff --git a/internal/config/config_doc.go b/internal/config/config_doc.go index 50be1b94e..4ab6c3b10 100644 --- a/internal/config/config_doc.go +++ b/internal/config/config_doc.go @@ -238,7 +238,7 @@ func init() { AzureConfigDoc.Fields[11].Note = "" AzureConfigDoc.Fields[11].Description = "Enable secure boot for VMs. If enabled, the OS image has to include a virtual machine guest state (VMGS) blob." AzureConfigDoc.Fields[11].Comments[encoder.LineComment] = "Enable secure boot for VMs. If enabled, the OS image has to include a virtual machine guest state (VMGS) blob." - AzureConfigDoc.Fields[12].Name = "idKeyDigests" + AzureConfigDoc.Fields[12].Name = "idKeyDigest" AzureConfigDoc.Fields[12].Type = "Digests" AzureConfigDoc.Fields[12].Note = "" AzureConfigDoc.Fields[12].Description = "List of accepted values for the field 'idkeydigest' in the AMD SEV-SNP attestation report. Only usable with ConfidentialVMs. See 4.6 and 7.3 in: https://www.amd.com/system/files/TechDocs/56860.pdf" diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 1b8ad12ff..ac94ed454 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -10,6 +10,7 @@ import ( "reflect" "testing" + "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/instancetypes" @@ -684,3 +685,131 @@ func TestValidateProvider(t *testing.T) { }) } } + +func TestConfigVersionCompatibility(t *testing.T) { + testCases := map[string]struct { + config string + expectedConfig *Config + }{ + "config v2 azure with singular idkeydigest": { + config: "testdata/configAzureV2SingleIDKeyDigest.yaml", + expectedConfig: &Config{ + Version: "v2", + Image: "v2.5.0", + StateDiskSizeGB: 16, + KubernetesVersion: "1.23", + DebugCluster: toPtr(false), + Provider: ProviderConfig{ + Azure: &AzureConfig{ + SubscriptionID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + TenantID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + Location: "West Europe", + ResourceGroup: "resourceGroup", + UserAssignedIdentity: "/subscriptions/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/resourceGroups/resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ConstellationUAMI", + AppClientID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + ClientSecretValue: "aaaaaaaaaaaaaaaaaaaa", + StateDiskType: "Premium_LRS", + ConfidentialVM: toPtr(true), + InstanceType: "Standard_DC4as_v5", + IDKeyDigest: idkeydigest.IDKeyDigests{{0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3}}, + EnforceIDKeyDigest: toPtr(false), + SecureBoot: toPtr(false), + DeployCSIDriver: toPtr(true), + Measurements: measurements.DefaultsFor(cloudprovider.Azure), + }, + }, + }, + }, + "config v2 azure with multiple idkeydigest": { + config: "testdata/configAzureV2MultipleIDKeyDigest.yaml", + expectedConfig: &Config{ + Version: "v2", + Image: "v2.5.0", + StateDiskSizeGB: 16, + KubernetesVersion: "1.23", + DebugCluster: toPtr(false), + Provider: ProviderConfig{ + Azure: &AzureConfig{ + SubscriptionID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + TenantID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + Location: "West Europe", + ResourceGroup: "resourceGroup", + UserAssignedIdentity: "/subscriptions/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/resourceGroups/resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ConstellationUAMI", + AppClientID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa", + ClientSecretValue: "aaaaaaaaaaaaaaaaaaaa", + StateDiskType: "Premium_LRS", + ConfidentialVM: toPtr(true), + InstanceType: "Standard_DC4as_v5", + IDKeyDigest: idkeydigest.IDKeyDigests{ + {0x57, 0x48, 0x6a, 0x44, 0x7e, 0xc0, 0xf1, 0x95, 0x80, 0x02, 0xa2, 0x2a, 0x06, 0xb7, 0x67, 0x3b, 0x9f, 0xd2, 0x7d, 0x11, 0xe1, 0xc6, 0x52, 0x74, 0x98, 0x05, 0x60, 0x54, 0xc5, 0xfa, 0x92, 0xd2, 0x3c, 0x50, 0xf9, 0xde, 0x44, 0x07, 0x27, 0x60, 0xfe, 0x2b, 0x6f, 0xb8, 0x97, 0x40, 0xb6, 0x96}, + {0x03, 0x56, 0x21, 0x58, 0x82, 0xa8, 0x25, 0x27, 0x9a, 0x85, 0xb3, 0x00, 0xb0, 0xb7, 0x42, 0x93, 0x1d, 0x11, 0x3b, 0xf7, 0xe3, 0x2d, 0xde, 0x2e, 0x50, 0xff, 0xde, 0x7e, 0xc7, 0x43, 0xca, 0x49, 0x1e, 0xcd, 0xd7, 0xf3, 0x36, 0xdc, 0x28, 0xa6, 0xe0, 0xb2, 0xbb, 0x57, 0xaf, 0x7a, 0x44, 0xa3}, + }, + EnforceIDKeyDigest: toPtr(false), + SecureBoot: toPtr(false), + DeployCSIDriver: toPtr(true), + Measurements: measurements.DefaultsFor(cloudprovider.Azure), + }, + }, + }, + }, + "config v2 gcp": { + config: "testdata/configGCPV2.yaml", + expectedConfig: &Config{ + Version: "v2", + Image: "v2.5.0", + StateDiskSizeGB: 16, + KubernetesVersion: "1.23", + DebugCluster: toPtr(false), + Provider: ProviderConfig{ + GCP: &GCPConfig{ + Project: "project-12345", + Region: "europe-west3", + Zone: "europe-west3-b", + ServiceAccountKeyPath: "serviceAccountKey.json", + InstanceType: "n2d-standard-4", + StateDiskType: "pd-ssd", + DeployCSIDriver: toPtr(true), + Measurements: measurements.DefaultsFor(cloudprovider.GCP), + }, + }, + }, + }, + "config v2 aws": { + config: "testdata/configAWSV2.yaml", + expectedConfig: &Config{ + Version: "v2", + Image: "v2.5.0", + StateDiskSizeGB: 16, + KubernetesVersion: "1.23", + DebugCluster: toPtr(false), + Provider: ProviderConfig{ + AWS: &AWSConfig{ + Region: "us-east-2", + Zone: "us-east-2a", + InstanceType: "c5.xlarge", + StateDiskType: "gp2", + IAMProfileControlPlane: "control_plane_instance_profile", + IAMProfileWorkerNodes: "node_instance_profile", + Measurements: measurements.DefaultsFor(cloudprovider.AWS), + }, + }, + }, + }, + } + for name, tc := range testCases { + t.Run(name, func(t *testing.T) { + assert := assert.New(t) + + fileHandler := file.NewHandler(afero.NewOsFs()) + + config, err := FromFile(fileHandler, tc.config) + + assert.NoError(err) + assert.Equal(tc.expectedConfig, config) + }) + } +} + +func toPtr[T any](v T) *T { + return &v +} diff --git a/internal/config/testdata/configAWSV2.yaml b/internal/config/testdata/configAWSV2.yaml new file mode 100644 index 000000000..d23d0b175 --- /dev/null +++ b/internal/config/testdata/configAWSV2.yaml @@ -0,0 +1,35 @@ +version: v2 +stateDiskSizeGB: 16 +kubernetesVersion: "1.23" +debugCluster: false +image: v2.5.0 +provider: + aws: + region: "us-east-2" + zone: "us-east-2a" + instanceType: c5.xlarge + stateDiskType: gp2 + iamProfileControlPlane: "control_plane_instance_profile" + iamProfileWorkerNodes: "node_instance_profile" + measurements: + 4: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 8: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 9: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 11: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 12: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 13: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 15: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false diff --git a/internal/config/testdata/configAzureV2MultipleIDKeyDigest.yaml b/internal/config/testdata/configAzureV2MultipleIDKeyDigest.yaml new file mode 100644 index 000000000..2c933f440 --- /dev/null +++ b/internal/config/testdata/configAzureV2MultipleIDKeyDigest.yaml @@ -0,0 +1,45 @@ +version: v2 +stateDiskSizeGB: 16 +debugCluster: false +image: v2.5.0 +kubernetesVersion: "1.23" +provider: + azure: + tenant: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + subscription: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + location: "West Europe" + resourceGroup: "resourceGroup" + userAssignedIdentity: /subscriptions/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/resourceGroups/resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ConstellationUAMI + appClientID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + clientSecretValue: "aaaaaaaaaaaaaaaaaaaa" + stateDiskType: Premium_LRS + confidentialVM: true + instanceType: Standard_DC4as_v5 + idKeyDigest: + - 57486a447ec0f1958002a22a06b7673b9fd27d11e1c6527498056054c5fa92d23c50f9de44072760fe2b6fb89740b696 + - 0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3 + enforceIdKeyDigest: false + secureBoot: false + deployCSIDriver: true + measurements: + 4: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 8: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 9: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 11: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 12: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 13: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 15: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false diff --git a/internal/config/testdata/configAzureV2SingleIDKeyDigest.yaml b/internal/config/testdata/configAzureV2SingleIDKeyDigest.yaml new file mode 100644 index 000000000..0a1acaf87 --- /dev/null +++ b/internal/config/testdata/configAzureV2SingleIDKeyDigest.yaml @@ -0,0 +1,43 @@ +version: v2 +stateDiskSizeGB: 16 +debugCluster: false +image: v2.5.0 +kubernetesVersion: "1.23" +provider: + azure: + subscription: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + tenant: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + location: "West Europe" + resourceGroup: "resourceGroup" + userAssignedIdentity: /subscriptions/aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa/resourceGroups/resourceGroup/providers/Microsoft.ManagedIdentity/userAssignedIdentities/ConstellationUAMI + appClientID: "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa" + clientSecretValue: "aaaaaaaaaaaaaaaaaaaa" + stateDiskType: Premium_LRS + confidentialVM: true + instanceType: Standard_DC4as_v5 + idKeyDigest: "0356215882a825279a85b300b0b742931d113bf7e32dde2e50ffde7ec743ca491ecdd7f336dc28a6e0b2bb57af7a44a3" + enforceIdKeyDigest: false + secureBoot: false + deployCSIDriver: true + measurements: + 4: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 8: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 9: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 11: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 12: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 13: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 15: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false diff --git a/internal/config/testdata/configGCPV2.yaml b/internal/config/testdata/configGCPV2.yaml new file mode 100644 index 000000000..95731e826 --- /dev/null +++ b/internal/config/testdata/configGCPV2.yaml @@ -0,0 +1,39 @@ +version: v2 +image: "v2.5.0" +stateDiskSizeGB: 16 +kubernetesVersion: "1.23" +debugCluster: false +provider: + gcp: + project: "project-12345" + region: "europe-west3" + zone: "europe-west3-b" + serviceAccountKeyPath: "serviceAccountKey.json" + instanceType: n2d-standard-4 + stateDiskType: pd-ssd + deployCSIDriver: true + measurements: + 0: + expected: 0f35c214608d93c7a6e68ae7359b4a8be5a0e99eea9107ece427c4dea4e439cf + warnOnly: false + 4: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 8: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 9: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 11: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 12: + expected: "1234123412341234123412341234123412341234123412341234123412341234" + warnOnly: false + 13: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false + 15: + expected: "0000000000000000000000000000000000000000000000000000000000000000" + warnOnly: false