github.com/verrazzano/verrazzano@v1.7.0/application-operator/internal/certificates/certificates_test.go (about) 1 // Copyright (c) 2020, 2022, Oracle and/or its affiliates. 2 // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl. 3 4 package certificates 5 6 import ( 7 "bytes" 8 "context" 9 "crypto/x509" 10 "encoding/pem" 11 "fmt" 12 "go.uber.org/zap" 13 "os" 14 "testing" 15 16 "github.com/stretchr/testify/assert" 17 adminv1 "k8s.io/api/admissionregistration/v1" 18 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 19 "k8s.io/client-go/kubernetes/fake" 20 ) 21 22 // TestSetupCertificates tests that the certificates needed for webhooks are created 23 // GIVEN an output directory for certificates 24 // 25 // WHEN I call SetupCertificates 26 // THEN all the needed certificate artifacts are created 27 func TestCreateWebhookCertificates(t *testing.T) { 28 a := assert.New(t) 29 30 dir, err := os.MkdirTemp("", "certs") 31 if err != nil { 32 a.Nil(err, "error should not be returned creating temporary directory") 33 } 34 defer os.RemoveAll(dir) 35 kubeClient := fake.NewSimpleClientset() 36 log := zap.S() 37 38 err = CreateWebhookCertificates(log, kubeClient, dir) 39 a.Nil(err, "error should not be returned setting up certificates") 40 crtFile := fmt.Sprintf("%s/%s", dir, "tls.crt") 41 keyFile := fmt.Sprintf("%s/%s", dir, "tls.key") 42 a.FileExists(crtFile, dir, "tls.crt", "expected tls.crt file not found") 43 a.FileExists(keyFile, dir, "tls.key", "expected tls.key file not found") 44 crtBytes, err := os.ReadFile(crtFile) 45 if a.NoError(err) { 46 block, _ := pem.Decode(crtBytes) 47 a.NotEmptyf(block, "failed to decode PEM block containing public key") 48 a.Equal("CERTIFICATE", block.Type) 49 cert, err := x509.ParseCertificate(block.Bytes) 50 if a.NoError(err) { 51 a.NotEmpty(cert.DNSNames, "Certificate DNSNames SAN field should not be empty") 52 a.Equal("verrazzano-application-operator-webhook.verrazzano-system.svc", cert.DNSNames[0]) 53 } 54 } 55 } 56 57 // TestSetupCertificatesFail tests that the certificates needed for webhooks are not created 58 // GIVEN an invalid output directory for certificates 59 // 60 // WHEN I call SetupCertificates 61 // THEN all the needed certificate artifacts are not created 62 func TestCreateWebhookCertificatesFail(t *testing.T) { 63 a := assert.New(t) 64 kubeClient := fake.NewSimpleClientset() 65 log := zap.S() 66 err := CreateWebhookCertificates(log, kubeClient, "bad-dir") 67 a.Error(err, "error should be returned setting up certificates") 68 } 69 70 // TestUpdateValidatingWebhookConfiguration tests that the CA Bundle is updated in the verrazzano-platform-operator 71 // validatingWebhookConfiguration resource. 72 // GIVEN a validatingWebhookConfiguration resource with the CA Bundle set 73 // 74 // WHEN I call UpdateValidatingnWebhookConfiguration 75 // THEN the validatingWebhookConfiguration resource set the CA Bundle as expected 76 func TestUpdateValidatingWebhookConfiguration(t *testing.T) { 77 a := assert.New(t) 78 79 kubeClient := fake.NewSimpleClientset() 80 81 var caCert bytes.Buffer 82 caCert.WriteString("Fake CABundle") 83 path := "/validate-oam-verrazzano-io-v1alpha1-ingresstrait" 84 service := adminv1.ServiceReference{ 85 Name: OperatorName, 86 Namespace: OperatorNamespace, 87 Path: &path, 88 } 89 webhook := adminv1.ValidatingWebhookConfiguration{ 90 TypeMeta: metav1.TypeMeta{}, 91 ObjectMeta: metav1.ObjectMeta{ 92 Name: IngressTraitValidatingWebhookName, 93 }, 94 Webhooks: []adminv1.ValidatingWebhook{ 95 { 96 Name: "install.verrazzano.io", 97 ClientConfig: adminv1.WebhookClientConfig{ 98 Service: &service, 99 }, 100 }, 101 }, 102 } 103 104 _, err := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{}) 105 a.Nil(err, "error should not be returned creating validation webhook configuration") 106 107 //err = UpdateValidatingWebhookConfiguration(kubeClient, &caCert, IngressTraitValidatingWebhookName) 108 //a.Nil(err, "error should not be returned updating validation webhook configuration") 109 110 //updatedWebhook, _ := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Get(context.TODO(), IngressTraitValidatingWebhookName, metav1.GetOptions{}) 111 //a.Equal(caCert.Bytes(), updatedWebhook.Webhooks[0].ClientConfig.CABundle, "Expected CA bundle name did not match") 112 } 113 114 // TestUpdateValidatingWebhookConfigurationFail tests that the CA Bundle is not updated in the 115 // verrazzano-platform-operator validatingWebhookConfiguration resource. 116 // GIVEN an invalid validatingWebhookConfiguration resource with the CA Bundle set 117 // 118 // WHEN I call UpdateValidatingnWebhookConfiguration 119 // THEN the validatingWebhookConfiguration resource will fail to be updated 120 func TestUpdateValidatingWebhookConfigurationFail(t *testing.T) { 121 a := assert.New(t) 122 123 kubeClient := fake.NewSimpleClientset() 124 125 var caCert bytes.Buffer 126 caCert.WriteString("Fake CABundle") 127 path := "/validate-oam-verrazzano-io-v1alpha1-ingresstrait" 128 service := adminv1.ServiceReference{ 129 Name: OperatorName, 130 Namespace: OperatorNamespace, 131 Path: &path, 132 } 133 webhook := adminv1.ValidatingWebhookConfiguration{ 134 TypeMeta: metav1.TypeMeta{}, 135 ObjectMeta: metav1.ObjectMeta{ 136 Name: "InvalidName", 137 }, 138 Webhooks: []adminv1.ValidatingWebhook{ 139 { 140 Name: "install.verrazzano.io", 141 ClientConfig: adminv1.WebhookClientConfig{ 142 Service: &service, 143 }, 144 }, 145 }, 146 } 147 148 _, err := kubeClient.AdmissionregistrationV1().ValidatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{}) 149 a.Nil(err, "error should not be returned creating validation webhook configuration") 150 151 //err = UpdateValidatingWebhookConfiguration(kubeClient, &caCert, IngressTraitValidatingWebhookName) 152 //a.Error(err, "error should be returned updating validation webhook configuration") 153 } 154 155 // TestUpdateAppConfigMutatingWebhookConfiguration tests that the CA Bundle is updated in the verrazzano-application-operator 156 // mutatingWebhookConfiguration resource. 157 // GIVEN a mutatingWebhookConfiguration resource with the CA Bundle set 158 // 159 // WHEN I call UpdateAppConfigMutatingWebhookConfiguration 160 // THEN the mutatingWebhookConfiguration resource set the CA Bundle as expected 161 func TestUpdateAppConfigMutatingWebhookConfiguration(t *testing.T) { 162 a := assert.New(t) 163 164 kubeClient := fake.NewSimpleClientset() 165 166 var caCert bytes.Buffer 167 caCert.WriteString("Fake CABundle") 168 path := "/appconfig-defaulter" 169 service := adminv1.ServiceReference{ 170 Name: OperatorName, 171 Namespace: OperatorNamespace, 172 Path: &path, 173 } 174 webhook := adminv1.MutatingWebhookConfiguration{ 175 TypeMeta: metav1.TypeMeta{}, 176 ObjectMeta: metav1.ObjectMeta{ 177 Name: AppConfigMutatingWebhookName, 178 }, 179 Webhooks: []adminv1.MutatingWebhook{ 180 { 181 Name: "install.verrazzano.io", 182 ClientConfig: adminv1.WebhookClientConfig{ 183 Service: &service, 184 }, 185 }, 186 }, 187 } 188 189 _, err := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{}) 190 a.Nil(err, "error should not be returned creating validation webhook configuration") 191 192 //err = UpdateMutatingWebhookConfiguration(kubeClient, &caCert, AppConfigMutatingWebhookName) 193 //a.Nil(err, "error should not be returned updating validation webhook configuration") 194 195 //updatedWebhook, _ := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(context.TODO(), AppConfigMutatingWebhookName, metav1.GetOptions{}) 196 //a.Equal(caCert.Bytes(), updatedWebhook.Webhooks[0].ClientConfig.CABundle, "Expected CA bundle name did not match") 197 } 198 199 // TestUpdateAppConfigMutatingWebhookConfigurationFail tests that the CA Bundle is not updated in the 200 // verrazzano-application-operator mutatingWebhookConfiguration resource. 201 // GIVEN an invalid mutatingWebhookConfiguration resource with the CA Bundle set 202 // 203 // WHEN I call UpdateAppConfigMutatingWebhookConfiguration 204 // THEN the mutatingWebhookConfiguration resource will fail to be updated 205 func TestUpdateAppConfigMutatingWebhookConfigurationFail(t *testing.T) { 206 a := assert.New(t) 207 208 kubeClient := fake.NewSimpleClientset() 209 210 var caCert bytes.Buffer 211 caCert.WriteString("Fake CABundle") 212 path := "/appconfig-defaulter" 213 service := adminv1.ServiceReference{ 214 Name: OperatorName, 215 Namespace: OperatorNamespace, 216 Path: &path, 217 } 218 webhook := adminv1.MutatingWebhookConfiguration{ 219 TypeMeta: metav1.TypeMeta{}, 220 ObjectMeta: metav1.ObjectMeta{ 221 Name: "InvalidName", 222 }, 223 Webhooks: []adminv1.MutatingWebhook{ 224 { 225 Name: "install.verrazzano.io", 226 ClientConfig: adminv1.WebhookClientConfig{ 227 Service: &service, 228 }, 229 }, 230 }, 231 } 232 233 _, err := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{}) 234 a.Nil(err, "error should not be returned creating validation webhook configuration") 235 236 //err = UpdateMutatingWebhookConfiguration(kubeClient, &caCert, AppConfigMutatingWebhookName) 237 //a.Error(err, "error should be returned updating validation webhook configuration") 238 } 239 240 // TestUpdateIstioMutatingWebhookConfiguration tests that the CA Bundle is updated in the verrazzano-application-operator 241 // mutatingWebhookConfiguration resource. 242 // GIVEN a mutatingWebhookConfiguration resource with the CA Bundle set 243 // 244 // WHEN I call UpdateIstioMutatingWebhookConfiguration 245 // THEN the mutatingWebhookConfiguration resource set the CA Bundle as expected 246 func TestUpdateIstioMutatingWebhookConfiguration(t *testing.T) { 247 a := assert.New(t) 248 249 kubeClient := fake.NewSimpleClientset() 250 251 var caCert bytes.Buffer 252 caCert.WriteString("Fake CABundle") 253 path := "/istio-defaulter" 254 service := adminv1.ServiceReference{ 255 Name: OperatorName, 256 Namespace: OperatorNamespace, 257 Path: &path, 258 } 259 webhook := adminv1.MutatingWebhookConfiguration{ 260 TypeMeta: metav1.TypeMeta{}, 261 ObjectMeta: metav1.ObjectMeta{ 262 Name: IstioMutatingWebhookName, 263 }, 264 Webhooks: []adminv1.MutatingWebhook{ 265 { 266 Name: "install.verrazzano.io", 267 ClientConfig: adminv1.WebhookClientConfig{ 268 Service: &service, 269 }, 270 }, 271 }, 272 } 273 274 _, err := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{}) 275 a.Nil(err, "error should not be returned creating validation webhook configuration") 276 277 //err = UpdateMutatingWebhookConfiguration(kubeClient, &caCert, IstioMutatingWebhookName) 278 //a.Nil(err, "error should not be returned updating validation webhook configuration") 279 280 //updatedWebhook, _ := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Get(context.TODO(), IstioMutatingWebhookName, metav1.GetOptions{}) 281 //a.Equal(caCert.Bytes(), updatedWebhook.Webhooks[0].ClientConfig.CABundle, "Expected CA bundle name did not match") 282 } 283 284 // TestUpdateIstioMutatingWebhookConfigurationFail tests that the CA Bundle is not updated in the 285 // verrazzano-application-operator mutatingWebhookConfiguration resource. 286 // GIVEN an invalid mutatingWebhookConfiguration resource with the CA Bundle set 287 // 288 // WHEN I call UpdateIstioMutatingWebhookConfiguration 289 // THEN the mutatingWebhookConfiguration resource will fail to be updated 290 func TestUpdateIstioMutatingWebhookConfigurationFail(t *testing.T) { 291 a := assert.New(t) 292 293 kubeClient := fake.NewSimpleClientset() 294 295 var caCert bytes.Buffer 296 caCert.WriteString("Fake CABundle") 297 path := "/istio-defaulter" 298 service := adminv1.ServiceReference{ 299 Name: OperatorName, 300 Namespace: OperatorNamespace, 301 Path: &path, 302 } 303 webhook := adminv1.MutatingWebhookConfiguration{ 304 TypeMeta: metav1.TypeMeta{}, 305 ObjectMeta: metav1.ObjectMeta{ 306 Name: "InvalidName", 307 }, 308 Webhooks: []adminv1.MutatingWebhook{ 309 { 310 Name: "install.verrazzano.io", 311 ClientConfig: adminv1.WebhookClientConfig{ 312 Service: &service, 313 }, 314 }, 315 }, 316 } 317 318 _, err := kubeClient.AdmissionregistrationV1().MutatingWebhookConfigurations().Create(context.TODO(), &webhook, metav1.CreateOptions{}) 319 a.Nil(err, "error should not be returned creating validation webhook configuration") 320 321 //err = UpdateMutatingWebhookConfiguration(kubeClient, &caCert, IstioMutatingWebhookName) 322 //a.Error(err, "error should be returned updating validation webhook configuration") 323 }