open-cluster-management.io/governance-policy-propagator@v0.13.0/test/e2e/case12_encryptionkeys_controller_test.go (about)

     1  // Copyright (c) 2022 Red Hat, Inc.
     2  // Copyright Contributors to the Open Cluster Management project
     3  
     4  package e2e
     5  
     6  import (
     7  	"bytes"
     8  	"context"
     9  	"encoding/base64"
    10  	"strings"
    11  
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  	corev1 "k8s.io/api/core/v1"
    15  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    16  	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
    17  
    18  	"open-cluster-management.io/governance-policy-propagator/controllers/common"
    19  	"open-cluster-management.io/governance-policy-propagator/test/utils"
    20  )
    21  
    22  var _ = Describe("Test policy encryption key rotation", func() {
    23  	key := bytes.Repeat([]byte{byte('A')}, 256/8)
    24  	keyB64 := base64.StdEncoding.EncodeToString(key)
    25  	previousKey := bytes.Repeat([]byte{byte('B')}, 256/8)
    26  
    27  	rsrcPath := "../resources/case12_encryptionkeys_controller/"
    28  	policyOneYaml := rsrcPath + "policy-one.yaml"
    29  	policyTwoYaml := rsrcPath + "policy-two.yaml"
    30  	policyOneName := "policy-one"
    31  	policyTwoName := "policy-two"
    32  	replicatedPolicyOneYaml := rsrcPath + "replicated-policy-one.yaml"
    33  	replicatedPolicyOneName := "policy-propagator-test.policy-one"
    34  
    35  	It("should create some sample policies", func() {
    36  		By("Creating the root policies with placement rules and bindings")
    37  		utils.Kubectl("apply", "-f", policyOneYaml,
    38  			"-n", testNamespace, "--kubeconfig="+kubeconfigHub)
    39  		rootOne := utils.GetWithTimeout(
    40  			clientHubDynamic, gvrPolicy, policyOneName, testNamespace, true, defaultTimeoutSeconds,
    41  		)
    42  		Expect(rootOne).NotTo(BeNil())
    43  
    44  		utils.Kubectl("apply", "-f", policyTwoYaml,
    45  			"-n", testNamespace, "--kubeconfig="+kubeconfigHub)
    46  		rootTwo := utils.GetWithTimeout(
    47  			clientHubDynamic, gvrPolicy, policyTwoName, testNamespace, true, defaultTimeoutSeconds,
    48  		)
    49  		Expect(rootTwo).NotTo(BeNil())
    50  
    51  		By("Patching in the decision for policy-one")
    52  		plrOne := utils.GetWithTimeout(
    53  			clientHubDynamic, gvrPlacementRule, policyOneName+"-plr", testNamespace, true, defaultTimeoutSeconds,
    54  		)
    55  		plrOne.Object["status"] = utils.GeneratePlrStatus("managed1")
    56  		_, err := clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus(
    57  			context.TODO(), plrOne, metav1.UpdateOptions{},
    58  		)
    59  		Expect(err).ToNot(HaveOccurred())
    60  		replicatedOne := utils.GetWithTimeout(
    61  			clientHubDynamic, gvrPolicy, testNamespace+"."+policyOneName, "managed1", true, defaultTimeoutSeconds,
    62  		)
    63  		Expect(replicatedOne).ToNot(BeNil())
    64  		opt := metav1.ListOptions{
    65  			LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + policyOneName,
    66  		}
    67  		utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
    68  
    69  		By("Patching in the decision for policy-two")
    70  		plrTwo := utils.GetWithTimeout(
    71  			clientHubDynamic, gvrPlacementRule, policyTwoName+"-plr", testNamespace, true, defaultTimeoutSeconds,
    72  		)
    73  		plrTwo.Object["status"] = utils.GeneratePlrStatus("managed1")
    74  		_, err = clientHubDynamic.Resource(gvrPlacementRule).Namespace(testNamespace).UpdateStatus(
    75  			context.TODO(), plrTwo, metav1.UpdateOptions{},
    76  		)
    77  		Expect(err).ToNot(HaveOccurred())
    78  		replicatedTwo := utils.GetWithTimeout(
    79  			clientHubDynamic, gvrPolicy, testNamespace+"."+policyTwoName, "managed1", true, defaultTimeoutSeconds,
    80  		)
    81  		Expect(replicatedTwo).ToNot(BeNil())
    82  		opt = metav1.ListOptions{
    83  			LabelSelector: common.RootPolicyLabel + "=" + testNamespace + "." + policyTwoName,
    84  		}
    85  		utils.ListWithTimeout(clientHubDynamic, gvrPolicy, opt, 1, true, defaultTimeoutSeconds)
    86  
    87  		By("Adding the IV Annotation to the replicated policy-one")
    88  		utils.Kubectl("apply", "-n", "managed1",
    89  			"-f", replicatedPolicyOneYaml, "--kubeconfig="+kubeconfigHub)
    90  
    91  		Eventually(func() interface{} {
    92  			replicatedPolicy := utils.GetWithTimeout(
    93  				clientHubDynamic, gvrPolicy, replicatedPolicyOneName, "managed1", true, defaultTimeoutSeconds,
    94  			)
    95  
    96  			return replicatedPolicy.GetAnnotations()
    97  		}, defaultTimeoutSeconds, 1).Should(HaveKey(IVAnnotation))
    98  	})
    99  
   100  	It("should create a "+EncryptionKeySecret+" secret that needs a rotation", func() {
   101  		secret := &corev1.Secret{
   102  			ObjectMeta: metav1.ObjectMeta{
   103  				Name:        EncryptionKeySecret,
   104  				Namespace:   "managed1",
   105  				Annotations: map[string]string{LastRotatedAnnotation: "2020-04-15T01:02:03Z"},
   106  			},
   107  			Data: map[string][]byte{"key": key, "previousKey": previousKey},
   108  		}
   109  		_, err := clientHub.CoreV1().Secrets("managed1").Create(context.TODO(), secret, metav1.CreateOptions{})
   110  		Expect(err).ShouldNot(HaveOccurred())
   111  	})
   112  
   113  	It("should have rotated the key in the "+EncryptionKeySecret+" secret", func() {
   114  		var secret *unstructured.Unstructured
   115  		Eventually(func() interface{} {
   116  			secret = utils.GetWithTimeout(
   117  				clientHubDynamic,
   118  				gvrSecret,
   119  				EncryptionKeySecret,
   120  				"managed1",
   121  				true,
   122  				defaultTimeoutSeconds,
   123  			)
   124  
   125  			data, ok := secret.Object["data"].(map[string]interface{})
   126  			if !ok {
   127  				return ""
   128  			}
   129  
   130  			currentKey, ok := data["key"].(string)
   131  			if !ok {
   132  				return ""
   133  			}
   134  
   135  			return currentKey
   136  		}, defaultTimeoutSeconds, 1).ShouldNot(Equal(keyB64))
   137  
   138  		currentPrevKey, ok := secret.Object["data"].(map[string]interface{})["previousKey"].(string)
   139  		Expect(ok).Should(BeTrue())
   140  		Expect(currentPrevKey).Should(Equal(keyB64))
   141  	})
   142  
   143  	It("should have triggered policies to be reprocessed", func() {
   144  		Eventually(func() interface{} {
   145  			policy := utils.GetWithTimeout(
   146  				clientHubDynamic,
   147  				gvrPolicy,
   148  				"policy-one",
   149  				testNamespace,
   150  				true,
   151  				defaultTimeoutSeconds,
   152  			)
   153  
   154  			return strings.HasPrefix(policy.GetAnnotations()[TriggerUpdateAnnotation], "rotate-key-")
   155  		}, defaultTimeoutSeconds, 1).Should(BeTrue())
   156  
   157  		policy, err := clientHubDynamic.Resource(gvrPolicy).Namespace(testNamespace).Get(
   158  			context.TODO(), "policy-two", metav1.GetOptions{},
   159  		)
   160  		Expect(err).ShouldNot(HaveOccurred())
   161  		Expect(policy.GetAnnotations()[TriggerUpdateAnnotation]).Should(Equal(""))
   162  	})
   163  
   164  	It("clean up", func() {
   165  		err := clientHub.CoreV1().Secrets("managed1").Delete(
   166  			context.TODO(), EncryptionKeySecret, metav1.DeleteOptions{},
   167  		)
   168  		Expect(err).ShouldNot(HaveOccurred())
   169  
   170  		for _, policyName := range []string{"policy-one", "policy-two"} {
   171  			err = clientHubDynamic.Resource(gvrPolicy).Namespace(testNamespace).Delete(
   172  				context.TODO(), policyName, metav1.DeleteOptions{},
   173  			)
   174  			Expect(err).ShouldNot(HaveOccurred())
   175  		}
   176  	})
   177  })