mirror of
https://github.com/edgelesssys/constellation.git
synced 2025-02-25 09:11:24 -05:00
config: validate instance type for aws SNP based on attestation variant (#1963)
* config: validate instance type for aws SNP * apply suggestions
This commit is contained in:
parent
46e144d19b
commit
0a36ce6171
@ -26,7 +26,9 @@ func newConfigInstanceTypesCmd() *cobra.Command {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func printSupportedInstanceTypes(cmd *cobra.Command, _ []string) {
|
func printSupportedInstanceTypes(cmd *cobra.Command, _ []string) {
|
||||||
cmd.Printf(`AWS instance families:
|
cmd.Printf(`AWS SNP-enabled instance types:
|
||||||
|
%v
|
||||||
|
AWS NitroTPM-enabled instance types:
|
||||||
%v
|
%v
|
||||||
Azure Confidential VM instance types:
|
Azure Confidential VM instance types:
|
||||||
%v
|
%v
|
||||||
@ -34,7 +36,7 @@ Azure Trusted Launch instance types:
|
|||||||
%v
|
%v
|
||||||
GCP instance types:
|
GCP instance types:
|
||||||
%v
|
%v
|
||||||
`, formatInstanceTypes(instancetypes.AWSSupportedInstanceFamilies), formatInstanceTypes(instancetypes.AzureCVMInstanceTypes), formatInstanceTypes(instancetypes.AzureTrustedLaunchInstanceTypes), formatInstanceTypes(instancetypes.GCPInstanceTypes))
|
`, formatInstanceTypes(instancetypes.AWSSNPSupportedInstanceFamilies), formatInstanceTypes(instancetypes.AWSSupportedInstanceFamilies), formatInstanceTypes(instancetypes.AzureCVMInstanceTypes), formatInstanceTypes(instancetypes.AzureTrustedLaunchInstanceTypes), formatInstanceTypes(instancetypes.GCPInstanceTypes))
|
||||||
}
|
}
|
||||||
|
|
||||||
func formatInstanceTypes(types []string) string {
|
func formatInstanceTypes(types []string) string {
|
||||||
|
@ -650,7 +650,7 @@ func (c *Config) Validate(force bool) error {
|
|||||||
})
|
})
|
||||||
|
|
||||||
// Register AWS, Azure & GCP InstanceType validation error types
|
// Register AWS, Azure & GCP InstanceType validation error types
|
||||||
if err := validate.RegisterTranslation("aws_instance_type", trans, registerTranslateAWSInstanceTypeError, translateAWSInstanceTypeError); err != nil {
|
if err := validate.RegisterTranslation("aws_instance_type", trans, registerTranslateAWSInstanceTypeError, c.translateAWSInstanceTypeError); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -709,7 +709,7 @@ func (c *Config) Validate(force bool) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// register custom validator with label aws_instance_type to validate the AWS instance type from config input.
|
// register custom validator with label aws_instance_type to validate the AWS instance type from config input.
|
||||||
if err := validate.RegisterValidation("aws_instance_type", validateAWSInstanceType); err != nil {
|
if err := validate.RegisterValidation("aws_instance_type", c.validateAWSInstanceType); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -649,21 +649,47 @@ func TestValidInstanceTypeForProvider(t *testing.T) {
|
|||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
instanceTypes: []string{"c5.xlarge", "c5a.2xlarge", "c5a.16xlarge", "u-12tb1.112xlarge"},
|
instanceTypes: []string{"c5.xlarge", "c5a.2xlarge", "c5a.16xlarge", "u-12tb1.112xlarge"},
|
||||||
expectedResult: true,
|
expectedResult: true,
|
||||||
|
nonCVMsAllowed: true,
|
||||||
},
|
},
|
||||||
"aws one valid instance one with too little vCPUs": {
|
"aws one valid instance one with too little vCPUs": {
|
||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
instanceTypes: []string{"c5.medium"},
|
instanceTypes: []string{"c5.medium"},
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
|
nonCVMsAllowed: true,
|
||||||
},
|
},
|
||||||
"aws graviton sub-family unsupported": {
|
"aws graviton sub-family unsupported": {
|
||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
instanceTypes: []string{"m6g.xlarge", "r6g.2xlarge", "x2gd.xlarge", "g5g.8xlarge"},
|
instanceTypes: []string{"m6g.xlarge", "r6g.2xlarge", "x2gd.xlarge", "g5g.8xlarge"},
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
|
nonCVMsAllowed: true,
|
||||||
},
|
},
|
||||||
"aws combined two valid instances as one string": {
|
"aws combined two valid instances as one string": {
|
||||||
provider: cloudprovider.AWS,
|
provider: cloudprovider.AWS,
|
||||||
instanceTypes: []string{"c5.xlarge, c5a.2xlarge"},
|
instanceTypes: []string{"c5.xlarge, c5a.2xlarge"},
|
||||||
expectedResult: false,
|
expectedResult: false,
|
||||||
|
nonCVMsAllowed: true,
|
||||||
|
},
|
||||||
|
"aws only CVMs": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"c6a.xlarge", "m6a.xlarge", "r6a.xlarge"},
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
"aws CVMs but CVMs disabled": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"m6a.xlarge", "c6a.xlarge", "r6a.xlarge"},
|
||||||
|
nonCVMsAllowed: true,
|
||||||
|
expectedResult: true,
|
||||||
|
},
|
||||||
|
"aws nitroTPM VMs with CVMs enabled": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"c5.xlarge", "c5a.2xlarge", "c5a.16xlarge", "u-12tb1.112xlarge"},
|
||||||
|
expectedResult: false,
|
||||||
|
},
|
||||||
|
"aws nitroTPM VMs with CVMs disabled": {
|
||||||
|
provider: cloudprovider.AWS,
|
||||||
|
instanceTypes: []string{"c5.xlarge", "c5a.2xlarge", "c5a.16xlarge", "u-12tb1.112xlarge"},
|
||||||
|
nonCVMsAllowed: true,
|
||||||
|
expectedResult: true,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for name, tc := range testCases {
|
for name, tc := range testCases {
|
||||||
|
@ -14,6 +14,7 @@ var AWSSupportedInstanceFamilies = []string{
|
|||||||
"C5ad",
|
"C5ad",
|
||||||
"C5d",
|
"C5d",
|
||||||
"C5n",
|
"C5n",
|
||||||
|
"C6a",
|
||||||
"C6i",
|
"C6i",
|
||||||
"D3",
|
"D3",
|
||||||
"D3en",
|
"D3en",
|
||||||
@ -39,6 +40,7 @@ var AWSSupportedInstanceFamilies = []string{
|
|||||||
"R5d",
|
"R5d",
|
||||||
"R5dn",
|
"R5dn",
|
||||||
"R5n",
|
"R5n",
|
||||||
|
"R6a",
|
||||||
"R6i",
|
"R6i",
|
||||||
"U-3tb1",
|
"U-3tb1",
|
||||||
"U-6tb1",
|
"U-6tb1",
|
||||||
@ -49,3 +51,11 @@ var AWSSupportedInstanceFamilies = []string{
|
|||||||
"X2iezn",
|
"X2iezn",
|
||||||
"z1d",
|
"z1d",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AWSSNPSupportedInstanceFamilies is derived from:
|
||||||
|
// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/snp-requirements.html
|
||||||
|
var AWSSNPSupportedInstanceFamilies = []string{
|
||||||
|
"C6a",
|
||||||
|
"M6a",
|
||||||
|
"R6a",
|
||||||
|
}
|
||||||
|
@ -99,8 +99,9 @@ func translateInvalidK8sVersionError(ut ut.Translator, fe validator.FieldError)
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateAWSInstanceType(fl validator.FieldLevel) bool {
|
func (c *Config) validateAWSInstanceType(fl validator.FieldLevel) bool {
|
||||||
return validInstanceTypeForProvider(fl.Field().String(), false, cloudprovider.AWS)
|
acceptNonCVM := c.GetAttestationConfig().GetVariant().Equal(variant.AWSNitroTPM{})
|
||||||
|
return validInstanceTypeForProvider(fl.Field().String(), acceptNonCVM, cloudprovider.AWS)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Config) validateAzureInstanceType(fl validator.FieldLevel) bool {
|
func (c *Config) validateAzureInstanceType(fl validator.FieldLevel) bool {
|
||||||
@ -212,11 +213,20 @@ func (c *Config) translateMoreThanOneAttestationError(ut ut.Translator, fe valid
|
|||||||
}
|
}
|
||||||
|
|
||||||
func registerTranslateAWSInstanceTypeError(ut ut.Translator) error {
|
func registerTranslateAWSInstanceTypeError(ut ut.Translator) error {
|
||||||
return ut.Add("aws_instance_type", fmt.Sprintf("{0} must be an instance from one of the following families types with size xlarge or higher: %v", instancetypes.AWSSupportedInstanceFamilies), true)
|
return ut.Add("aws_instance_type", "{0} must be an instance from one of the following families types with size xlarge or higher: {1}", true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func translateAWSInstanceTypeError(ut ut.Translator, fe validator.FieldError) string {
|
func (c *Config) translateAWSInstanceTypeError(ut ut.Translator, fe validator.FieldError) string {
|
||||||
t, _ := ut.T("aws_instance_type", fe.Field())
|
var t string
|
||||||
|
|
||||||
|
attestVariant := c.GetAttestationConfig().GetVariant()
|
||||||
|
|
||||||
|
instances := instancetypes.AWSSNPSupportedInstanceFamilies
|
||||||
|
if attestVariant.Equal(variant.AWSNitroTPM{}) {
|
||||||
|
instances = instancetypes.AWSSupportedInstanceFamilies
|
||||||
|
}
|
||||||
|
|
||||||
|
t, _ = ut.T("aws_instance_type", fe.Field(), fmt.Sprintf("%v", instances))
|
||||||
|
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
@ -231,6 +241,27 @@ func translateGCPInstanceTypeError(ut ut.Translator, fe validator.FieldError) st
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validation translation functions for Azure & GCP instance type errors.
|
||||||
|
func registerTranslateAzureInstanceTypeError(ut ut.Translator) error {
|
||||||
|
return ut.Add("azure_instance_type", "{0} must be one of {1}", true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Config) translateAzureInstanceTypeError(ut ut.Translator, fe validator.FieldError) string {
|
||||||
|
// Suggest trusted launch VMs if confidential VMs have been specifically disabled
|
||||||
|
var t string
|
||||||
|
|
||||||
|
attestVariant := c.GetAttestationConfig().GetVariant()
|
||||||
|
|
||||||
|
instances := instancetypes.AzureCVMInstanceTypes
|
||||||
|
if attestVariant.Equal(variant.AzureTrustedLaunch{}) {
|
||||||
|
instances = instancetypes.AzureTrustedLaunchInstanceTypes
|
||||||
|
}
|
||||||
|
|
||||||
|
t, _ = ut.T("azure_instance_type", fe.Field(), fmt.Sprintf("%v", instances))
|
||||||
|
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
// Validation translation functions for Provider errors.
|
// Validation translation functions for Provider errors.
|
||||||
func registerNoProviderError(ut ut.Translator) error {
|
func registerNoProviderError(ut ut.Translator) error {
|
||||||
return ut.Add("no_provider", "{0}: No provider has been defined (requires either Azure, GCP, OpenStack or QEMU)", true)
|
return ut.Add("no_provider", "{0}: No provider has been defined (requires either Azure, GCP, OpenStack or QEMU)", true)
|
||||||
@ -275,7 +306,7 @@ func (c *Config) translateMoreThanOneProviderError(ut ut.Translator, fe validato
|
|||||||
func validInstanceTypeForProvider(insType string, acceptNonCVM bool, provider cloudprovider.Provider) bool {
|
func validInstanceTypeForProvider(insType string, acceptNonCVM bool, provider cloudprovider.Provider) bool {
|
||||||
switch provider {
|
switch provider {
|
||||||
case cloudprovider.AWS:
|
case cloudprovider.AWS:
|
||||||
return checkIfAWSInstanceTypeIsValid(insType)
|
return isSupportedAWSInstanceType(insType, acceptNonCVM)
|
||||||
case cloudprovider.Azure:
|
case cloudprovider.Azure:
|
||||||
if acceptNonCVM {
|
if acceptNonCVM {
|
||||||
for _, instanceType := range instancetypes.AzureTrustedLaunchInstanceTypes {
|
for _, instanceType := range instancetypes.AzureTrustedLaunchInstanceTypes {
|
||||||
@ -303,8 +334,8 @@ func validInstanceTypeForProvider(insType string, acceptNonCVM bool, provider cl
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkIfAWSInstanceTypeIsValid checks if an AWS instance type passed as user input is in one of the instance families supporting NitroTPM.
|
// isSupportedAWSInstanceType checks if an AWS instance type passed as user input is in one of the supported instance types.
|
||||||
func checkIfAWSInstanceTypeIsValid(userInput string) bool {
|
func isSupportedAWSInstanceType(userInput string, acceptNonCVM bool) bool {
|
||||||
// Check if user or code does anything weird and tries to pass multiple strings as one
|
// Check if user or code does anything weird and tries to pass multiple strings as one
|
||||||
if strings.Contains(userInput, " ") {
|
if strings.Contains(userInput, " ") {
|
||||||
return false
|
return false
|
||||||
@ -331,9 +362,14 @@ func checkIfAWSInstanceTypeIsValid(userInput string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
instances := instancetypes.AWSSNPSupportedInstanceFamilies
|
||||||
|
if acceptNonCVM {
|
||||||
|
instances = instancetypes.AWSSupportedInstanceFamilies
|
||||||
|
}
|
||||||
|
|
||||||
// Now check if the user input is a supported family
|
// Now check if the user input is a supported family
|
||||||
// Note that we cannot directly use the family split from the Graviton check above, as some instances are directly specified by their full name and not just the family in general
|
// Note that we cannot directly use the family split from the Graviton check above, as some instances are directly specified by their full name and not just the family in general
|
||||||
for _, supportedFamily := range instancetypes.AWSSupportedInstanceFamilies {
|
for _, supportedFamily := range instances {
|
||||||
supportedFamilyLowercase := strings.ToLower(supportedFamily)
|
supportedFamilyLowercase := strings.ToLower(supportedFamily)
|
||||||
if userDefinedFamily == supportedFamilyLowercase {
|
if userDefinedFamily == supportedFamilyLowercase {
|
||||||
return true
|
return true
|
||||||
@ -343,25 +379,6 @@ func checkIfAWSInstanceTypeIsValid(userInput string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validation translation functions for Azure & GCP instance type errors.
|
|
||||||
func registerTranslateAzureInstanceTypeError(ut ut.Translator) error {
|
|
||||||
return ut.Add("azure_instance_type", "{0} must be one of {1}", true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *Config) translateAzureInstanceTypeError(ut ut.Translator, fe validator.FieldError) string {
|
|
||||||
// Suggest trusted launch VMs if confidential VMs have been specifically disabled
|
|
||||||
var t string
|
|
||||||
|
|
||||||
attestVariant := c.GetAttestationConfig().GetVariant()
|
|
||||||
if attestVariant.Equal(variant.AzureTrustedLaunch{}) {
|
|
||||||
t, _ = ut.T("azure_instance_type", fe.Field(), fmt.Sprintf("%v", instancetypes.AzureTrustedLaunchInstanceTypes))
|
|
||||||
} else {
|
|
||||||
t, _ = ut.T("azure_instance_type", fe.Field(), fmt.Sprintf("%v", instancetypes.AzureCVMInstanceTypes))
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateNoPlaceholder(fl validator.FieldLevel) bool {
|
func validateNoPlaceholder(fl validator.FieldLevel) bool {
|
||||||
return len(getPlaceholderEntries(fl.Field().Interface().(measurements.M))) == 0
|
return len(getPlaceholderEntries(fl.Field().Interface().(measurements.M))) == 0
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user