1
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()) }()
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
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
87
88
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])
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
147
148
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])
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 })
176
View as plain text