sigs.k8s.io/controller-runtime@v0.18.2/pkg/internal/testing/controlplane/auth_test.go (about) 1 /* 2 Copyright 2021 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package controlplane_test 18 19 import ( 20 "crypto/tls" 21 "crypto/x509" 22 "os" 23 "path/filepath" 24 25 . "github.com/onsi/ginkgo/v2" 26 . "github.com/onsi/gomega" 27 "k8s.io/client-go/rest" 28 kcert "k8s.io/client-go/util/cert" 29 30 cp "sigs.k8s.io/controller-runtime/pkg/internal/testing/controlplane" 31 "sigs.k8s.io/controller-runtime/pkg/internal/testing/process" 32 ) 33 34 var _ = Describe("Cert Authentication", func() { 35 var authn *cp.CertAuthn 36 BeforeEach(func() { 37 var err error 38 authn, err = cp.NewCertAuthn() 39 Expect(err).NotTo(HaveOccurred(), "should be able to create the cert authn") 40 }) 41 Context("when starting", func() { 42 It("should write the verifying CA to the configured directory", func() { 43 By("setting up a temp dir") 44 dir, err := os.MkdirTemp("", "envtest_controlplane_*") 45 Expect(err).NotTo(HaveOccurred(), "should be able to provision a temp dir") 46 if dir != "" { 47 defer os.RemoveAll(dir) 48 } 49 50 By("configuring to use that dir") 51 Expect(authn.Configure(dir, process.EmptyArguments())).To(Succeed()) 52 53 By("starting and checking the dir") 54 Expect(authn.Start()).To(Succeed()) 55 defer func() { Expect(authn.Stop()).To(Succeed()) }() // not strictly necessary, but future-proof 56 57 _, err = os.Stat(filepath.Join(dir, "client-cert-auth-ca.crt")) 58 Expect(err).NotTo(HaveOccurred()) 59 }) 60 61 It("should error out if we haven't been configured yet", func() { 62 // NB(directxman12): no configure here intentionally 63 Expect(authn.Start()).NotTo(Succeed()) 64 }) 65 }) 66 Context("when configuring", func() { 67 It("should have set up the API server to use the written file for client cert auth", func() { 68 args := process.EmptyArguments() 69 Expect(authn.Configure("/tmp/____doesnotexist", args)).To(Succeed()) 70 Expect(args.Get("client-ca-file").Get(nil)).To(ConsistOf("/tmp/____doesnotexist/client-cert-auth-ca.crt")) 71 }) 72 }) 73 74 Describe("creating users", func() { 75 user := cp.User{Name: "someuser", Groups: []string{"group1", "group2"}} 76 77 Context("before starting", func() { 78 It("should yield a REST config that contains certs valid for the to-be-written CA", func() { 79 cfg, err := authn.AddUser(user, &rest.Config{}) 80 Expect(err).NotTo(HaveOccurred()) 81 Expect(cfg).NotTo(BeNil()) 82 83 Expect(cfg.CertData).NotTo(BeEmpty()) 84 Expect(cfg.KeyData).NotTo(BeEmpty()) 85 86 // double-check the cert (assume the key is fine if it's present 87 // and the cert is also present, cause it's more annoying to verify 88 // and we have separate tinyca & integration tests. 89 By("parsing the config's cert & key data") 90 certs, err := tls.X509KeyPair(cfg.CertData, cfg.KeyData) 91 Expect(err).NotTo(HaveOccurred(), "config cert/key data should be valid key pair") 92 cert, err := x509.ParseCertificate(certs.Certificate[0]) // re-parse cause .Leaf isn't saved 93 Expect(err).NotTo(HaveOccurred()) 94 95 By("starting and loading the CA cert") 96 dir, err := os.MkdirTemp("", "envtest_controlplane_*") 97 Expect(err).NotTo(HaveOccurred(), "should be able to provision a temp dir") 98 if dir != "" { 99 defer os.RemoveAll(dir) 100 } 101 Expect(authn.Configure(dir, process.EmptyArguments())).To(Succeed()) 102 Expect(authn.Start()).To(Succeed()) 103 caCerts, err := kcert.CertsFromFile(filepath.Join(dir, "client-cert-auth-ca.crt")) 104 Expect(err).NotTo(HaveOccurred(), "should be able to read the CA cert file))))") 105 Expect(cert.CheckSignatureFrom(caCerts[0])).To(Succeed(), "the config's cert should be signed by the written CA") 106 }) 107 108 It("should copy the configuration from the base CA without modifying it", func() { 109 By("creating a user and checking the output config") 110 base := &rest.Config{Burst: 30} 111 cfg, err := authn.AddUser(user, base) 112 Expect(err).NotTo(HaveOccurred()) 113 Expect(cfg).NotTo(BeNil()) 114 Expect(cfg.Burst).To(Equal(30)) 115 116 By("mutating the base and verifying the cfg doesn't change") 117 base.Burst = 8675 118 Expect(cfg.Burst).To(Equal(30)) 119 }) 120 }) 121 122 Context("after starting", func() { 123 var dir string 124 BeforeEach(func() { 125 By("setting up a temp dir & starting with it") 126 var err error 127 dir, err = os.MkdirTemp("", "envtest_controlplane_*") 128 Expect(err).NotTo(HaveOccurred(), "should be able to provision a temp dir") 129 Expect(authn.Configure(dir, process.EmptyArguments())).To(Succeed()) 130 Expect(authn.Start()).To(Succeed()) 131 }) 132 AfterEach(func() { 133 if dir != "" { 134 defer os.RemoveAll(dir) 135 } 136 }) 137 138 It("should yield a REST config that contains certs valid for the written CA", func() { 139 cfg, err := authn.AddUser(user, &rest.Config{}) 140 Expect(err).NotTo(HaveOccurred()) 141 Expect(cfg).NotTo(BeNil()) 142 143 Expect(cfg.CertData).NotTo(BeEmpty()) 144 Expect(cfg.KeyData).NotTo(BeEmpty()) 145 146 // double-check the cert (assume the key is fine if it's present 147 // and the cert is also present, cause it's more annoying to verify 148 // and we have separate tinyca & integration tests. 149 By("parsing the config's cert & key data") 150 certs, err := tls.X509KeyPair(cfg.CertData, cfg.KeyData) 151 Expect(err).NotTo(HaveOccurred(), "config cert/key data should be valid key pair") 152 cert, err := x509.ParseCertificate(certs.Certificate[0]) // re-parse cause .Leaf isn't saved 153 Expect(err).NotTo(HaveOccurred()) 154 155 By("loading the CA cert") 156 caCerts, err := kcert.CertsFromFile(filepath.Join(dir, "client-cert-auth-ca.crt")) 157 Expect(err).NotTo(HaveOccurred(), "should be able to read the CA cert file))))") 158 Expect(cert.CheckSignatureFrom(caCerts[0])).To(Succeed(), "the config's cert should be signed by the written CA") 159 }) 160 161 It("should copy the configuration from the base CA without modifying it", func() { 162 By("creating a user and checking the output config") 163 base := &rest.Config{Burst: 30} 164 cfg, err := authn.AddUser(user, base) 165 Expect(err).NotTo(HaveOccurred()) 166 Expect(cfg).NotTo(BeNil()) 167 Expect(cfg.Burst).To(Equal(30)) 168 169 By("mutating the base and verifying the cfg doesn't change") 170 base.Burst = 8675 171 Expect(cfg.Burst).To(Equal(30)) 172 }) 173 }) 174 }) 175 })