Skip to content

Commit b184b35

Browse files
Vadim Rutkovskyvrutkovs
authored andcommitted
nodekubeconfig: set not-before/not-after annotations
Copy not-before and not-after annotations from the system:admin secret
1 parent f1f9a76 commit b184b35

File tree

2 files changed

+245
-81
lines changed

2 files changed

+245
-81
lines changed

pkg/operator/nodekubeconfigcontroller/nodekubeconfigcontroller.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"github.com/openshift/cluster-kube-apiserver-operator/bindata"
1515
"github.com/openshift/cluster-kube-apiserver-operator/pkg/operator/operatorclient"
1616
"github.com/openshift/library-go/pkg/controller/factory"
17+
"github.com/openshift/library-go/pkg/operator/certrotation"
1718
"github.com/openshift/library-go/pkg/operator/events"
1819
"github.com/openshift/library-go/pkg/operator/resource/resourceapply"
1920
"github.com/openshift/library-go/pkg/operator/resource/resourceread"
@@ -152,6 +153,13 @@ func ensureNodeKubeconfigs(ctx context.Context, client coreclientv1.CoreV1Interf
152153
requiredSecret.Annotations = map[string]string{}
153154
}
154155
requiredSecret.Annotations[annotations.OpenShiftComponent] = "kube-apiserver"
156+
// Copy not-before/not-after annotations from systemAdminClientCert
157+
if len(systemAdminCredsSecret.Annotations[certrotation.CertificateNotBeforeAnnotation]) > 0 {
158+
requiredSecret.Annotations[certrotation.CertificateNotBeforeAnnotation] = systemAdminCredsSecret.Annotations[certrotation.CertificateNotBeforeAnnotation]
159+
}
160+
if len(systemAdminCredsSecret.Annotations[certrotation.CertificateNotAfterAnnotation]) > 0 {
161+
requiredSecret.Annotations[certrotation.CertificateNotAfterAnnotation] = systemAdminCredsSecret.Annotations[certrotation.CertificateNotAfterAnnotation]
162+
}
155163

156164
_, _, err = resourceapply.ApplySecret(ctx, client, recorder, requiredSecret)
157165
if err != nil {

pkg/operator/nodekubeconfigcontroller/nodekubeconfigcontroller_test.go

Lines changed: 237 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ package nodekubeconfigcontroller
22

33
import (
44
"context"
5+
"encoding/base64"
6+
"fmt"
57
"testing"
68

79
"github.com/google/go-cmp/cmp"
810
"github.com/openshift/api/annotations"
911
configv1 "github.com/openshift/api/config/v1"
1012
configlistersv1 "github.com/openshift/client-go/config/listers/config/v1"
13+
"github.com/openshift/library-go/pkg/operator/certrotation"
1114
"github.com/openshift/library-go/pkg/operator/events"
1215
corev1 "k8s.io/api/core/v1"
1316
apiequality "k8s.io/apimachinery/pkg/api/equality"
@@ -85,6 +88,64 @@ func (l *secretLister) Get(name string) (*corev1.Secret, error) {
8588
return l.client.CoreV1().Secrets(l.namespace).Get(context.Background(), name, metav1.GetOptions{})
8689
}
8790

91+
const privateKey = `
92+
-----BEGIN PRIVATE KEY-----
93+
MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEArvkpSCWaStPfbYr4
94+
cCJyv8pXWnJ4K22emSrYDNcp7Dm6qjtN/lsVNuGDyWyR4cUaJYXkaD2OrZiXDzzk
95+
BZlS3QIDAQABAkA9BZhoGPUec5XQVk8ejGUIjkC4woM2YhyVvmNq1v8/6q6V+uPw
96+
yDEfBMapuLVY+QhyVELXFOCHA5iKxrlFHZThAiEA1XA5mlbHtrJqEZ7yI5m6+Szj
97+
7YVzSkdSgfDZ//heAh8CIQDR3VbN9QmJRIM1yhIkP9BoWSxvXdH6QMXdC2X7Tkwj
98+
gwIgcpbSxjLK/CIjYhx0oXpacIaSRCX+dKV//XVChPNh/T8CIQCSFscXZez2fhfs
99+
eLb6PuXfzbuN5ryFvVM/VXDvaIi96wIgcHjUpONghaoA51XejMAxWanDiwAgRV5H
100+
XNdFkBi4q7o=
101+
-----END PRIVATE KEY-----` // notsecret
102+
const publicKey = `-----BEGIN CERTIFICATE-----
103+
MIIBfzCCASmgAwIBAgIUEEUHu1PzqJCGQ63vxVokwBxGPYwwDQYJKoZIhvcNAQEL
104+
BQAwFDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTI0MTEyNjA4NTA0NloXDTM0MTEy
105+
NDA4NTA0NlowFDESMBAGA1UEAwwJbG9jYWxob3N0MFwwDQYJKoZIhvcNAQEBBQAD
106+
SwAwSAJBAK75KUglmkrT322K+HAicr/KV1pyeCttnpkq2AzXKew5uqo7Tf5bFTbh
107+
g8lskeHFGiWF5Gg9jq2Ylw885AWZUt0CAwEAAaNTMFEwHQYDVR0OBBYEFJna5Io+
108+
idLKO73zypGl2itp92JUMB8GA1UdIwQYMBaAFJna5Io+idLKO73zypGl2itp92JU
109+
MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADQQB71tlkWNFDvMRxtz+a
110+
NYMU1thAVfVFciNXPS07tUduFSwVvYORUxx2w+5JfUdKu69hLpBFVPqvHQjPoQgc
111+
vUBI
112+
-----END CERTIFICATE-----`
113+
const certNotBefore = "2024-11-26T08:50:46Z"
114+
const certNotAfter = "2034-11-24T08:50:46Z"
115+
const lbExtServer = "https://lb-ext.test:6443"
116+
const lbIntServer = "https://lb-int.test:6443"
117+
118+
var publicKeyBase64 = base64.StdEncoding.EncodeToString([]byte(publicKey))
119+
var privateKeyBase64 = base64.StdEncoding.EncodeToString([]byte(privateKey))
120+
121+
func generateKubeConfig(name, server string) []byte {
122+
// localhost-recovery is a special case, it also has tls-server-name set
123+
tlsServerName := ""
124+
if name == "localhost-recovery" {
125+
tlsServerName = `
126+
tls-server-name: localhost-recovery`
127+
}
128+
return []byte(fmt.Sprintf(`apiVersion: v1
129+
kind: Config
130+
clusters:
131+
- cluster:
132+
certificate-authority-data: a3ViZS1hcGlzZXJ2ZXItc2VydmVyLWNhIGNlcnRpZmljYXRl
133+
server: %s%s
134+
name: %s
135+
contexts:
136+
- context:
137+
cluster: %s
138+
user: system:admin
139+
name: system:admin
140+
current-context: system:admin
141+
users:
142+
- name: system:admin
143+
user:
144+
client-certificate-data: %s
145+
client-key-data: %s
146+
`, server, tlsServerName, name, name, publicKeyBase64, privateKeyBase64))
147+
}
148+
88149
func TestEnsureNodeKubeconfigs(t *testing.T) {
89150
tt := []struct {
90151
name string
@@ -109,10 +170,14 @@ func TestEnsureNodeKubeconfigs(t *testing.T) {
109170
ObjectMeta: metav1.ObjectMeta{
110171
Namespace: "openshift-kube-apiserver-operator",
111172
Name: "node-system-admin-client",
173+
Annotations: map[string]string{
174+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
175+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
176+
},
112177
},
113178
Data: map[string][]byte{
114-
"tls.crt": []byte("system:admin certificate"),
115-
"tls.key": []byte("system:admin key"),
179+
"tls.crt": []byte(publicKey),
180+
"tls.key": []byte(privateKey),
116181
},
117182
},
118183
},
@@ -122,8 +187,72 @@ func TestEnsureNodeKubeconfigs(t *testing.T) {
122187
Name: "cluster",
123188
},
124189
Status: configv1.InfrastructureStatus{
125-
APIServerURL: "https://lb-ext.test:6443",
126-
APIServerInternalURL: "https://lb-int.test:6443",
190+
APIServerURL: lbExtServer,
191+
APIServerInternalURL: lbIntServer,
192+
},
193+
},
194+
expectedErr: nil,
195+
expectedActions: []clienttesting.Action{
196+
clienttesting.CreateActionImpl{
197+
ActionImpl: clienttesting.ActionImpl{
198+
Namespace: "openshift-kube-apiserver",
199+
Verb: "create",
200+
Resource: corev1.SchemeGroupVersion.WithResource("secrets"),
201+
},
202+
Object: &corev1.Secret{
203+
TypeMeta: metav1.TypeMeta{
204+
APIVersion: "v1",
205+
Kind: "Secret",
206+
},
207+
ObjectMeta: metav1.ObjectMeta{
208+
Namespace: "openshift-kube-apiserver",
209+
Name: "node-kubeconfigs",
210+
Annotations: map[string]string{
211+
annotations.OpenShiftComponent: "kube-apiserver",
212+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
213+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
214+
},
215+
},
216+
Data: map[string][]byte{
217+
"localhost.kubeconfig": generateKubeConfig("localhost", "https://localhost:6443"),
218+
"localhost-recovery.kubeconfig": generateKubeConfig("localhost-recovery", "https://localhost:6443"),
219+
"lb-ext.kubeconfig": generateKubeConfig("lb-ext", lbExtServer),
220+
"lb-int.kubeconfig": generateKubeConfig("lb-int", lbIntServer),
221+
},
222+
},
223+
},
224+
},
225+
}, {
226+
name: "no annotations set",
227+
existingObjects: []runtime.Object{
228+
&corev1.ConfigMap{
229+
ObjectMeta: metav1.ObjectMeta{
230+
Namespace: "openshift-kube-apiserver",
231+
Name: "kube-apiserver-server-ca",
232+
},
233+
Data: map[string]string{
234+
"ca-bundle.crt": "kube-apiserver-server-ca certificate",
235+
},
236+
},
237+
&corev1.Secret{
238+
ObjectMeta: metav1.ObjectMeta{
239+
Namespace: "openshift-kube-apiserver-operator",
240+
Name: "node-system-admin-client",
241+
},
242+
Data: map[string][]byte{
243+
"tls.crt": []byte(publicKey),
244+
"tls.key": []byte(privateKey),
245+
},
246+
},
247+
},
248+
infrastructure: &configv1.Infrastructure{
249+
ObjectMeta: metav1.ObjectMeta{
250+
Namespace: "",
251+
Name: "cluster",
252+
},
253+
Status: configv1.InfrastructureStatus{
254+
APIServerURL: lbExtServer,
255+
APIServerInternalURL: lbIntServer,
127256
},
128257
},
129258
expectedErr: nil,
@@ -147,84 +276,111 @@ func TestEnsureNodeKubeconfigs(t *testing.T) {
147276
},
148277
},
149278
Data: map[string][]byte{
150-
"localhost.kubeconfig": []byte(`apiVersion: v1
151-
kind: Config
152-
clusters:
153-
- cluster:
154-
certificate-authority-data: a3ViZS1hcGlzZXJ2ZXItc2VydmVyLWNhIGNlcnRpZmljYXRl
155-
server: https://localhost:6443
156-
name: localhost
157-
contexts:
158-
- context:
159-
cluster: localhost
160-
user: system:admin
161-
name: system:admin
162-
current-context: system:admin
163-
users:
164-
- name: system:admin
165-
user:
166-
client-certificate-data: c3lzdGVtOmFkbWluIGNlcnRpZmljYXRl
167-
client-key-data: c3lzdGVtOmFkbWluIGtleQ==
168-
`),
169-
"localhost-recovery.kubeconfig": []byte(`apiVersion: v1
170-
kind: Config
171-
clusters:
172-
- cluster:
173-
certificate-authority-data: a3ViZS1hcGlzZXJ2ZXItc2VydmVyLWNhIGNlcnRpZmljYXRl
174-
server: https://localhost:6443
175-
tls-server-name: localhost-recovery
176-
name: localhost-recovery
177-
contexts:
178-
- context:
179-
cluster: localhost-recovery
180-
user: system:admin
181-
name: system:admin
182-
current-context: system:admin
183-
users:
184-
- name: system:admin
185-
user:
186-
client-certificate-data: c3lzdGVtOmFkbWluIGNlcnRpZmljYXRl
187-
client-key-data: c3lzdGVtOmFkbWluIGtleQ==
188-
`),
189-
"lb-ext.kubeconfig": []byte(`apiVersion: v1
190-
kind: Config
191-
clusters:
192-
- cluster:
193-
certificate-authority-data: a3ViZS1hcGlzZXJ2ZXItc2VydmVyLWNhIGNlcnRpZmljYXRl
194-
server: https://lb-ext.test:6443
195-
name: lb-ext
196-
contexts:
197-
- context:
198-
cluster: lb-ext
199-
user: system:admin
200-
name: system:admin
201-
current-context: system:admin
202-
users:
203-
- name: system:admin
204-
user:
205-
client-certificate-data: c3lzdGVtOmFkbWluIGNlcnRpZmljYXRl
206-
client-key-data: c3lzdGVtOmFkbWluIGtleQ==
207-
`),
208-
"lb-int.kubeconfig": []byte(`apiVersion: v1
209-
kind: Config
210-
clusters:
211-
- cluster:
212-
certificate-authority-data: a3ViZS1hcGlzZXJ2ZXItc2VydmVyLWNhIGNlcnRpZmljYXRl
213-
server: https://lb-int.test:6443
214-
name: lb-int
215-
contexts:
216-
- context:
217-
cluster: lb-int
218-
user: system:admin
219-
name: system:admin
220-
current-context: system:admin
221-
users:
222-
- name: system:admin
223-
user:
224-
client-certificate-data: c3lzdGVtOmFkbWluIGNlcnRpZmljYXRl
225-
client-key-data: c3lzdGVtOmFkbWluIGtleQ==
226-
`),
279+
"localhost.kubeconfig": generateKubeConfig("localhost", "https://localhost:6443"),
280+
"localhost-recovery.kubeconfig": generateKubeConfig("localhost-recovery", "https://localhost:6443"),
281+
"lb-ext.kubeconfig": generateKubeConfig("lb-ext", lbExtServer),
282+
"lb-int.kubeconfig": generateKubeConfig("lb-int", lbIntServer),
283+
},
284+
},
285+
},
286+
},
287+
}, {
288+
name: "update",
289+
existingObjects: []runtime.Object{
290+
&corev1.ConfigMap{
291+
ObjectMeta: metav1.ObjectMeta{
292+
Namespace: "openshift-kube-apiserver",
293+
Name: "kube-apiserver-server-ca",
294+
},
295+
Data: map[string]string{
296+
"ca-bundle.crt": "kube-apiserver-server-ca certificate",
297+
},
298+
},
299+
&corev1.Secret{
300+
ObjectMeta: metav1.ObjectMeta{
301+
Namespace: "openshift-kube-apiserver-operator",
302+
Name: "node-system-admin-client",
303+
Annotations: map[string]string{
304+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
305+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
306+
},
307+
},
308+
Data: map[string][]byte{
309+
"tls.crt": []byte(publicKey),
310+
"tls.key": []byte(privateKey),
311+
},
312+
},
313+
&corev1.Secret{
314+
TypeMeta: metav1.TypeMeta{
315+
APIVersion: "v1",
316+
Kind: "Secret",
317+
},
318+
ObjectMeta: metav1.ObjectMeta{
319+
Namespace: "openshift-kube-apiserver",
320+
Name: "node-kubeconfigs",
321+
Annotations: map[string]string{
322+
annotations.OpenShiftComponent: "kube-apiserver",
323+
certrotation.CertificateNotBeforeAnnotation: "some-old-not-before",
324+
certrotation.CertificateNotAfterAnnotation: "some-old-not-after",
325+
},
326+
},
327+
Data: map[string][]byte{
328+
"localhost.kubeconfig": []byte("invalid kubeconfig"),
329+
"localhost-recovery.kubeconfig": []byte("another invalid kubeconfig"),
330+
"lb-ext.kubeconfig": []byte("more invalid kubeconfig"),
331+
"lb-int.kubeconfig": []byte("even more invalid kubeconfig"),
332+
},
333+
},
334+
},
335+
infrastructure: &configv1.Infrastructure{
336+
ObjectMeta: metav1.ObjectMeta{
337+
Namespace: "",
338+
Name: "cluster",
339+
},
340+
Status: configv1.InfrastructureStatus{
341+
APIServerURL: lbExtServer,
342+
APIServerInternalURL: lbIntServer,
343+
},
344+
},
345+
expectedErr: nil,
346+
expectedActions: []clienttesting.Action{
347+
clienttesting.DeleteActionImpl{
348+
ActionImpl: clienttesting.ActionImpl{
349+
Namespace: "openshift-kube-apiserver",
350+
Verb: "delete",
351+
Resource: corev1.SchemeGroupVersion.WithResource("secrets"),
352+
},
353+
Name: "node-kubeconfigs",
354+
},
355+
clienttesting.CreateActionImpl{
356+
ActionImpl: clienttesting.ActionImpl{
357+
Namespace: "openshift-kube-apiserver",
358+
Verb: "create",
359+
Resource: corev1.SchemeGroupVersion.WithResource("secrets"),
360+
},
361+
Object: &corev1.Secret{
362+
TypeMeta: metav1.TypeMeta{
363+
APIVersion: "v1",
364+
Kind: "Secret",
365+
},
366+
ObjectMeta: metav1.ObjectMeta{
367+
Namespace: "openshift-kube-apiserver",
368+
Name: "node-kubeconfigs",
369+
Labels: map[string]string{},
370+
OwnerReferences: []metav1.OwnerReference{},
371+
Annotations: map[string]string{
372+
annotations.OpenShiftComponent: "kube-apiserver",
373+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
374+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
375+
},
376+
},
377+
Data: map[string][]byte{
378+
"localhost.kubeconfig": generateKubeConfig("localhost", "https://localhost:6443"),
379+
"localhost-recovery.kubeconfig": generateKubeConfig("localhost-recovery", "https://localhost:6443"),
380+
"lb-ext.kubeconfig": generateKubeConfig("lb-ext", lbExtServer),
381+
"lb-int.kubeconfig": generateKubeConfig("lb-int", lbIntServer),
227382
},
383+
Type: corev1.SecretTypeOpaque,
228384
},
229385
},
230386
},

0 commit comments

Comments
 (0)