From 4b6fb61b2be5bf9c52931fbda5202ac223c202b5 Mon Sep 17 00:00:00 2001 From: Sid Shukla <6081171+thunderboltsid@users.noreply.github.com> Date: Fri, 25 Nov 2022 00:04:54 +0530 Subject: [PATCH] Bugfix: Stop base64 decoding ConfigMap.BinaryData (#47) Ensure Kubernetes env provider does not decode binary data as base64. --- CHANGELOG.md | 4 + .../providers/kubernetes/kubernetes.go | 7 +- .../providers/kubernetes/kubernetes_test.go | 88 ++++++++++--------- 3 files changed, 52 insertions(+), 47 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d3aa0ed4..0c9265d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +## [0.3.4] - 2022-11-24 +### Changed +- Bugfix: Stop explicit base64 decoding of BinaryData from ConfigMap in Kubernetes env provider + ## [0.3.3] - 2022-11-24 ### Changed - Kubernetes env provider can now read the trust bundle from both BinaryData and Data diff --git a/environment/providers/kubernetes/kubernetes.go b/environment/providers/kubernetes/kubernetes.go index 48307094..a3d7bf64 100644 --- a/environment/providers/kubernetes/kubernetes.go +++ b/environment/providers/kubernetes/kubernetes.go @@ -5,7 +5,6 @@ package kubernetes import ( - "encoding/base64" "fmt" "net/url" @@ -40,11 +39,7 @@ func (prov *provider) getAdditionalTrustBundle() (string, error) { return cert, nil } if b64Cert, ok := cm.BinaryData[certBundleKey]; ok { - cert, err := base64.StdEncoding.DecodeString(string(b64Cert)) - if err != nil { - return "", err - } - return string(cert), nil + return string(b64Cert), nil } return "", nil } diff --git a/environment/providers/kubernetes/kubernetes_test.go b/environment/providers/kubernetes/kubernetes_test.go index 5c0b24f8..7f972dfb 100644 --- a/environment/providers/kubernetes/kubernetes_test.go +++ b/environment/providers/kubernetes/kubernetes_test.go @@ -11,11 +11,14 @@ import ( . "github.com/onsi/gomega" corev1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/serializer" krand "k8s.io/apimachinery/pkg/util/rand" "k8s.io/client-go/informers" coreinformers "k8s.io/client-go/informers/core/v1" "k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes/fake" + "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/cache" "github.com/nutanix-cloud-native/prism-go-client/environment/credentials" @@ -56,22 +59,21 @@ func runCMInformer(ctx context.Context, clientset kubernetes.Interface) coreinfo var _ = Describe("Kubernetes Environment Provider", Ordered, func() { expectedCACert, expectedB64CACert, err := certutils.GenerateCACertForTesting() Expect(err).ToNot(HaveOccurred()) - var ( - secretName = "nutanix-credentials" - cmName = "user-ca-bundle" - secretNamespace = "kube-system" - secretInformer coreinformers.SecretInformer - cmInformer coreinformers.ConfigMapInformer - prov types.Provider - ip = krand.String(10) - username = krand.String(10) - password = krand.String(10) + cmName = "user-ca-bundle" + namespace = "kube-system" + secretName = "nutanix-credentials" + secretInformer coreinformers.SecretInformer + cmInformer coreinformers.ConfigMapInformer + prov types.Provider + ip = krand.String(10) + username = krand.String(10) + password = krand.String(10) fakeSecret = &corev1.Secret{ ObjectMeta: metav1.ObjectMeta{ Name: secretName, - Namespace: secretNamespace, + Namespace: namespace, }, Data: map[string][]byte{ "credentials": []byte(fmt.Sprintf(` @@ -90,49 +92,53 @@ var _ = Describe("Kubernetes Environment Provider", Ordered, func() { `, username, password)), }, } - fakeCM = &corev1.ConfigMap{ - ObjectMeta: metav1.ObjectMeta{ - Name: cmName, - Namespace: secretNamespace, - }, - BinaryData: map[string][]byte{ - certBundleKey: []byte(expectedB64CACert), - }, - } - - fakeClientset = fake.NewSimpleClientset(fakeSecret, fakeCM) - prismEndpoint = credentials.NutanixPrismEndpoint{ - Address: ip, - Port: 9440, - Insecure: true, - CredentialRef: &credentials.NutanixCredentialReference{ - Kind: credentials.SecretKind, - Name: secretName, - Namespace: secretNamespace, - }, - AdditionalTrustBundle: &credentials.NutanixTrustBundleReference{ - Kind: credentials.NutanixTrustBundleKindConfigMap, - Name: cmName, - Namespace: secretNamespace, - }, - } ) + + const fakeCMTemplate = `apiVersion: v1 +kind: ConfigMap +metadata: + name: %s + namespace: %s +binaryData: + ca.crt: %s` + fakeCMStr := fmt.Sprintf(fakeCMTemplate, cmName, namespace, expectedB64CACert) + decoder := serializer.NewCodecFactory(scheme.Scheme).UniversalDecoder() + fakeCM := &corev1.ConfigMap{} + err = runtime.DecodeInto(decoder, []byte(fakeCMStr), fakeCM) + Expect(err).ToNot(HaveOccurred()) + + fakeClientset := fake.NewSimpleClientset(fakeSecret, fakeCM) + prismEndpoint := credentials.NutanixPrismEndpoint{ + Address: ip, + Port: 9440, + Insecure: true, + CredentialRef: &credentials.NutanixCredentialReference{ + Kind: credentials.SecretKind, + Name: secretName, + Namespace: namespace, + }, + AdditionalTrustBundle: &credentials.NutanixTrustBundleReference{ + Kind: credentials.NutanixTrustBundleKindConfigMap, + Name: cmName, + Namespace: namespace, + }, + } BeforeAll(func() { secretInformer = runSecretInformer(context.TODO(), fakeClientset) cmInformer = runCMInformer(context.TODO(), fakeClientset) prov = NewProvider(prismEndpoint, secretInformer, cmInformer) }) It("must be able to look up secret", func() { - _, err := fakeClientset.CoreV1().Secrets(secretNamespace).Get(context.TODO(), secretName, metav1.GetOptions{}) + _, err := fakeClientset.CoreV1().Secrets(namespace).Get(context.TODO(), secretName, metav1.GetOptions{}) Expect(err).To(Succeed()) - _, err = secretInformer.Lister().Secrets(secretNamespace).Get(secretName) + _, err = secretInformer.Lister().Secrets(namespace).Get(secretName) Expect(err).To(Succeed()) - _, err = fakeClientset.CoreV1().ConfigMaps(secretNamespace).Get(context.TODO(), cmName, metav1.GetOptions{}) + _, err = fakeClientset.CoreV1().ConfigMaps(namespace).Get(context.TODO(), cmName, metav1.GetOptions{}) Expect(err).To(Succeed()) - _, err = cmInformer.Lister().ConfigMaps(secretNamespace).Get(cmName) + _, err = cmInformer.Lister().ConfigMaps(namespace).Get(cmName) Expect(err).To(Succeed()) }) It("must get management endpoint", func() {