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  }