diff --git a/internal/webhooks/common.go b/internal/webhooks/common.go index f80f35b67..4f8bf5f0a 100644 --- a/internal/webhooks/common.go +++ b/internal/webhooks/common.go @@ -18,6 +18,7 @@ package webhooks import ( "fmt" + "regexp" "strconv" "k8s.io/apimachinery/pkg/util/intstr" @@ -26,6 +27,9 @@ import ( infrav1 "sigs.k8s.io/cluster-api-provider-ibmcloud/api/v1beta2" ) +// IBM Cloud CRN validation regex. +var crnRegex = regexp.MustCompile(`^crn:v[0-9]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]+:[a-z0-9-]*:([a-z]\/[a-z0-9-]+)?:[a-z0-9-]*:[a-z0-9-]*:[a-zA-Z0-9-_\.\/]*$`) + func defaultIBMPowerVSMachineSpec(spec *infrav1.IBMPowerVSMachineSpec) { if spec.MemoryGiB == 0 { spec.MemoryGiB = 2 @@ -99,6 +103,9 @@ func validateVolumes(spec infrav1.IBMVPCMachineSpec) field.ErrorList { if spec.AdditionalVolumes[i].Iops != 0 && spec.AdditionalVolumes[i].Profile != customProfile { allErrs = append(allErrs, field.Invalid(field.NewPath(fmt.Sprintf("spec.AdditionalVolumes[%d]", i)), spec, "iops applicable only to volumes using a profile of type `custom`")) } + if spec.AdditionalVolumes[i].EncryptionKeyCRN != "" && !isValidCRN(spec.AdditionalVolumes[i].EncryptionKeyCRN) { + allErrs = append(allErrs, field.Invalid(field.NewPath(fmt.Sprintf("spec.AdditionalVolumes[%d]", i)), spec, "encryptionKeyCRN not in proper IBM Cloud CRN format")) + } } if spec.BootVolume == nil { @@ -113,7 +120,15 @@ func validateVolumes(spec infrav1.IBMVPCMachineSpec) field.ErrorList { allErrs = append(allErrs, field.Invalid(field.NewPath("spec.bootVolume.iops"), spec, "iops applicable only to volumes using a profile of type `custom`")) } - //TODO: Add validation for the spec.BootVolume.EncryptionKeyCRN to ensure its in proper IBM Cloud CRN format + // Validate spec.BootVolume.EncryptionKeyCRN to ensure its in proper IBM Cloud CRN format + if spec.BootVolume.EncryptionKeyCRN != "" && !isValidCRN(spec.BootVolume.EncryptionKeyCRN) { + allErrs = append(allErrs, field.Invalid(field.NewPath("spec.bootVolume.encryptionKeyCRN"), spec, "encryptionKeyCRN not in proper IBM Cloud CRN format")) + } return allErrs } + +// isValidCRN checks whether the provided string is a valid IBM Cloud CRN. +func isValidCRN(crn string) bool { + return crnRegex.MatchString(crn) +} diff --git a/internal/webhooks/common_test.go b/internal/webhooks/common_test.go index 96c74b2ef..a364b641e 100644 --- a/internal/webhooks/common_test.go +++ b/internal/webhooks/common_test.go @@ -160,6 +160,20 @@ func Test_validateVolumes(t *testing.T) { }, wantError: false, }, + { + name: "Valid encryptionKeyCRN", + spec: infrav1.IBMVPCMachineSpec{ + BootVolume: &infrav1.VPCVolume{SizeGiB: 20, EncryptionKeyCRN: "crn:v1:bluemix:public:kms:us-south:a/aa2432b1fa4d4ace891e9b80fc104e34:e4a29d1a-2ef0-42a6-8fd2-350deb1c647e:key:5437653b-c4b1-447f-9646-b2a2a4cd6179"}, + }, + wantError: false, + }, + { + name: "Invalid encryptionKeyCRN", + spec: infrav1.IBMVPCMachineSpec{ + BootVolume: &infrav1.VPCVolume{EncryptionKeyCRN: "invalid-crn-format"}, + }, + wantError: true, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) {