Skip to content

Commit 80afb73

Browse files
committed
nodekubeconfig: set not-before/not-after annotations
Copy not-before and not-after annotations from the system:admin secret
1 parent f1f9a76 commit 80afb73

File tree

2 files changed

+225
-81
lines changed

2 files changed

+225
-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: 217 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,44 @@ 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 = "fake private key" // notsecret
92+
const publicKey = "fake public key"
93+
const certNotBefore = "2024-11-26T08:50:46Z"
94+
const certNotAfter = "2034-11-24T08:50:46Z"
95+
const lbExtServer = "https://lb-ext.test:6443"
96+
const lbIntServer = "https://lb-int.test:6443"
97+
98+
var publicKeyBase64 = base64.StdEncoding.EncodeToString([]byte(publicKey))
99+
var privateKeyBase64 = base64.StdEncoding.EncodeToString([]byte(privateKey))
100+
101+
func generateKubeConfig(name, server string) []byte {
102+
// localhost-recovery is a special case, it also has tls-server-name set
103+
tlsServerName := ""
104+
if name == "localhost-recovery" {
105+
tlsServerName = `
106+
tls-server-name: localhost-recovery`
107+
}
108+
return []byte(fmt.Sprintf(`apiVersion: v1
109+
kind: Config
110+
clusters:
111+
- cluster:
112+
certificate-authority-data: a3ViZS1hcGlzZXJ2ZXItc2VydmVyLWNhIGNlcnRpZmljYXRl
113+
server: %s%s
114+
name: %s
115+
contexts:
116+
- context:
117+
cluster: %s
118+
user: system:admin
119+
name: system:admin
120+
current-context: system:admin
121+
users:
122+
- name: system:admin
123+
user:
124+
client-certificate-data: %s
125+
client-key-data: %s
126+
`, server, tlsServerName, name, name, publicKeyBase64, privateKeyBase64))
127+
}
128+
88129
func TestEnsureNodeKubeconfigs(t *testing.T) {
89130
tt := []struct {
90131
name string
@@ -109,10 +150,14 @@ func TestEnsureNodeKubeconfigs(t *testing.T) {
109150
ObjectMeta: metav1.ObjectMeta{
110151
Namespace: "openshift-kube-apiserver-operator",
111152
Name: "node-system-admin-client",
153+
Annotations: map[string]string{
154+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
155+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
156+
},
112157
},
113158
Data: map[string][]byte{
114-
"tls.crt": []byte("system:admin certificate"),
115-
"tls.key": []byte("system:admin key"),
159+
"tls.crt": []byte(publicKey),
160+
"tls.key": []byte(privateKey),
116161
},
117162
},
118163
},
@@ -122,8 +167,72 @@ func TestEnsureNodeKubeconfigs(t *testing.T) {
122167
Name: "cluster",
123168
},
124169
Status: configv1.InfrastructureStatus{
125-
APIServerURL: "https://lb-ext.test:6443",
126-
APIServerInternalURL: "https://lb-int.test:6443",
170+
APIServerURL: lbExtServer,
171+
APIServerInternalURL: lbIntServer,
172+
},
173+
},
174+
expectedErr: nil,
175+
expectedActions: []clienttesting.Action{
176+
clienttesting.CreateActionImpl{
177+
ActionImpl: clienttesting.ActionImpl{
178+
Namespace: "openshift-kube-apiserver",
179+
Verb: "create",
180+
Resource: corev1.SchemeGroupVersion.WithResource("secrets"),
181+
},
182+
Object: &corev1.Secret{
183+
TypeMeta: metav1.TypeMeta{
184+
APIVersion: "v1",
185+
Kind: "Secret",
186+
},
187+
ObjectMeta: metav1.ObjectMeta{
188+
Namespace: "openshift-kube-apiserver",
189+
Name: "node-kubeconfigs",
190+
Annotations: map[string]string{
191+
annotations.OpenShiftComponent: "kube-apiserver",
192+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
193+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
194+
},
195+
},
196+
Data: map[string][]byte{
197+
"localhost.kubeconfig": generateKubeConfig("localhost", "https://localhost:6443"),
198+
"localhost-recovery.kubeconfig": generateKubeConfig("localhost-recovery", "https://localhost:6443"),
199+
"lb-ext.kubeconfig": generateKubeConfig("lb-ext", lbExtServer),
200+
"lb-int.kubeconfig": generateKubeConfig("lb-int", lbIntServer),
201+
},
202+
},
203+
},
204+
},
205+
}, {
206+
name: "no annotations set",
207+
existingObjects: []runtime.Object{
208+
&corev1.ConfigMap{
209+
ObjectMeta: metav1.ObjectMeta{
210+
Namespace: "openshift-kube-apiserver",
211+
Name: "kube-apiserver-server-ca",
212+
},
213+
Data: map[string]string{
214+
"ca-bundle.crt": "kube-apiserver-server-ca certificate",
215+
},
216+
},
217+
&corev1.Secret{
218+
ObjectMeta: metav1.ObjectMeta{
219+
Namespace: "openshift-kube-apiserver-operator",
220+
Name: "node-system-admin-client",
221+
},
222+
Data: map[string][]byte{
223+
"tls.crt": []byte(publicKey),
224+
"tls.key": []byte(privateKey),
225+
},
226+
},
227+
},
228+
infrastructure: &configv1.Infrastructure{
229+
ObjectMeta: metav1.ObjectMeta{
230+
Namespace: "",
231+
Name: "cluster",
232+
},
233+
Status: configv1.InfrastructureStatus{
234+
APIServerURL: lbExtServer,
235+
APIServerInternalURL: lbIntServer,
127236
},
128237
},
129238
expectedErr: nil,
@@ -147,84 +256,111 @@ func TestEnsureNodeKubeconfigs(t *testing.T) {
147256
},
148257
},
149258
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-
`),
259+
"localhost.kubeconfig": generateKubeConfig("localhost", "https://localhost:6443"),
260+
"localhost-recovery.kubeconfig": generateKubeConfig("localhost-recovery", "https://localhost:6443"),
261+
"lb-ext.kubeconfig": generateKubeConfig("lb-ext", lbExtServer),
262+
"lb-int.kubeconfig": generateKubeConfig("lb-int", lbIntServer),
263+
},
264+
},
265+
},
266+
},
267+
}, {
268+
name: "update",
269+
existingObjects: []runtime.Object{
270+
&corev1.ConfigMap{
271+
ObjectMeta: metav1.ObjectMeta{
272+
Namespace: "openshift-kube-apiserver",
273+
Name: "kube-apiserver-server-ca",
274+
},
275+
Data: map[string]string{
276+
"ca-bundle.crt": "kube-apiserver-server-ca certificate",
277+
},
278+
},
279+
&corev1.Secret{
280+
ObjectMeta: metav1.ObjectMeta{
281+
Namespace: "openshift-kube-apiserver-operator",
282+
Name: "node-system-admin-client",
283+
Annotations: map[string]string{
284+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
285+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
286+
},
287+
},
288+
Data: map[string][]byte{
289+
"tls.crt": []byte(publicKey),
290+
"tls.key": []byte(privateKey),
291+
},
292+
},
293+
&corev1.Secret{
294+
TypeMeta: metav1.TypeMeta{
295+
APIVersion: "v1",
296+
Kind: "Secret",
297+
},
298+
ObjectMeta: metav1.ObjectMeta{
299+
Namespace: "openshift-kube-apiserver",
300+
Name: "node-kubeconfigs",
301+
Annotations: map[string]string{
302+
annotations.OpenShiftComponent: "kube-apiserver",
303+
certrotation.CertificateNotBeforeAnnotation: "some-old-not-before",
304+
certrotation.CertificateNotAfterAnnotation: "some-old-not-after",
305+
},
306+
},
307+
Data: map[string][]byte{
308+
"localhost.kubeconfig": []byte("invalid kubeconfig"),
309+
"localhost-recovery.kubeconfig": []byte("another invalid kubeconfig"),
310+
"lb-ext.kubeconfig": []byte("more invalid kubeconfig"),
311+
"lb-int.kubeconfig": []byte("even more invalid kubeconfig"),
312+
},
313+
},
314+
},
315+
infrastructure: &configv1.Infrastructure{
316+
ObjectMeta: metav1.ObjectMeta{
317+
Namespace: "",
318+
Name: "cluster",
319+
},
320+
Status: configv1.InfrastructureStatus{
321+
APIServerURL: lbExtServer,
322+
APIServerInternalURL: lbIntServer,
323+
},
324+
},
325+
expectedErr: nil,
326+
expectedActions: []clienttesting.Action{
327+
clienttesting.DeleteActionImpl{
328+
ActionImpl: clienttesting.ActionImpl{
329+
Namespace: "openshift-kube-apiserver",
330+
Verb: "delete",
331+
Resource: corev1.SchemeGroupVersion.WithResource("secrets"),
332+
},
333+
Name: "node-kubeconfigs",
334+
},
335+
clienttesting.CreateActionImpl{
336+
ActionImpl: clienttesting.ActionImpl{
337+
Namespace: "openshift-kube-apiserver",
338+
Verb: "create",
339+
Resource: corev1.SchemeGroupVersion.WithResource("secrets"),
340+
},
341+
Object: &corev1.Secret{
342+
TypeMeta: metav1.TypeMeta{
343+
APIVersion: "v1",
344+
Kind: "Secret",
345+
},
346+
ObjectMeta: metav1.ObjectMeta{
347+
Namespace: "openshift-kube-apiserver",
348+
Name: "node-kubeconfigs",
349+
Labels: map[string]string{},
350+
OwnerReferences: []metav1.OwnerReference{},
351+
Annotations: map[string]string{
352+
annotations.OpenShiftComponent: "kube-apiserver",
353+
certrotation.CertificateNotBeforeAnnotation: certNotBefore,
354+
certrotation.CertificateNotAfterAnnotation: certNotAfter,
355+
},
356+
},
357+
Data: map[string][]byte{
358+
"localhost.kubeconfig": generateKubeConfig("localhost", "https://localhost:6443"),
359+
"localhost-recovery.kubeconfig": generateKubeConfig("localhost-recovery", "https://localhost:6443"),
360+
"lb-ext.kubeconfig": generateKubeConfig("lb-ext", lbExtServer),
361+
"lb-int.kubeconfig": generateKubeConfig("lb-int", lbIntServer),
227362
},
363+
Type: corev1.SecretTypeOpaque,
228364
},
229365
},
230366
},

0 commit comments

Comments
 (0)