Skip to content

Commit 79e1ad2

Browse files
authored
Merge pull request kubernetes#88744 from jackkleeman/kubelet-handle-intermed
Support intermediate certificate in certificate store
2 parents 4838ac9 + 83a223f commit 79e1ad2

File tree

3 files changed

+149
-4
lines changed

3 files changed

+149
-4
lines changed

staging/src/k8s.io/client-go/util/certificate/certificate_manager_test.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,68 @@ iQIgZX08DA8VfvcA5/Xj1Zjdey9FVY6POLXen6RPiabE97UCICp6eUW7ht+2jjar
6060
e35EltCRCjoejRHTuN9TC0uCoVipAiAXaJIx/Q47vGwiw6Y8KXsNU6y54gTbOSxX
6161
54LzHNk/+Q==
6262
-----END RSA PRIVATE KEY-----`)
63+
var storeTwoCertsData = newCertificateData(`-----BEGIN CERTIFICATE-----
64+
MIIDfTCCAyegAwIBAgIUFBl4gUoqZDP/wUJDn37/VJ9upD0wDQYJKoZIhvcNAQEF
65+
BQAwfjELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u
66+
ZG9uMRgwFgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFy
67+
dG1lbnQxGzAZBgNVBAMMEnRlc3QtY2VydGlmaWNhdGUtMDAeFw0yMDAzMDIxOTM3
68+
MDBaFw0yMTAzMDIxOTM3MDBaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs
69+
aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEdMBsGA1UEChMURXhhbXBs
70+
ZSBDb21wYW55LCBMTEMxEzARBgNVBAsTCk9wZXJhdGlvbnMxGDAWBgNVBAMTD3d3
71+
dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMiR
72+
DNpmwTICFr+P16fKDVjbNCzSjWq+MTu8vAfS6GrLpBTUEe+6zVqxUza/fZenxo8O
73+
ucV2JTUv5J4nkT/vG6Qm/mToVJ4vQzLQ5jR2w7v/7cf3oWCwTAKUafgo6/Ga95gn
74+
lQB3+Fd8sy96zfFr/7wDSMPPueR5kSFax+cEd30wwv5O7tWj0ro1mrxLssBlwPaR
75+
ZlzkkvxBYTzWCqKZsWktQlXciqlFSos0ua7uvwqKN5CTxfC/xoyMxx9kfZm7BzPN
76+
ZDqYMFw2HiWdEiLzI4jj+Gh0D5t47tnvlpUMihcX9x0jP6/+hnfcQ8GAP2jR/BXY
77+
5YZRRY70LiCXPevlRAECAwEAAaOBqTCBpjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
78+
BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYE
79+
FOoiE+kh7gGDpyx0KZuCc1lrlTRKMB8GA1UdIwQYMBaAFNtosvGlpDUsb9JwcRcX
80+
q37L52VTMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb20w
81+
DQYJKoZIhvcNAQEFBQADQQAw6mxQONAD2sivfzIf1eDFd6LU7aE+MnkdlEQjjPCi
82+
tlUITFIuO3XavISupP6V9wE0b1wTF1pTlVWArf/0YQXs
83+
-----END CERTIFICATE-----
84+
-----BEGIN CERTIFICATE-----
85+
MIICRzCCAfGgAwIBAgIJALMb7ecMIk3MMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
86+
BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
87+
CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
88+
VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwIBcNMTcwNDI2MjMyNjUyWhgPMjExNzA0
89+
MDIyMzI2NTJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
90+
BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
91+
VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwXDANBgkq
92+
hkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTCPGO/LEsguKqWHBtKzweMY2CV
93+
tAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5MzP2H5QIDAQABo1AwTjAdBgNV
94+
HQ4EFgQU22iy8aWkNSxv0nBxFxerfsvnZVMwHwYDVR0jBBgwFoAU22iy8aWkNSxv
95+
0nBxFxerfsvnZVMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAEOefGbV
96+
NcHxklaW06w6OBYJPwpIhCVozC1qdxGX1dg8VkEKzjOzjgqVD30m59OFmSlBmHsl
97+
nkVA6wyOSDYBf3o=
98+
-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
99+
MIIEowIBAAKCAQEAyJEM2mbBMgIWv4/Xp8oNWNs0LNKNar4xO7y8B9LoasukFNQR
100+
77rNWrFTNr99l6fGjw65xXYlNS/knieRP+8bpCb+ZOhUni9DMtDmNHbDu//tx/eh
101+
YLBMApRp+Cjr8Zr3mCeVAHf4V3yzL3rN8Wv/vANIw8+55HmRIVrH5wR3fTDC/k7u
102+
1aPSujWavEuywGXA9pFmXOSS/EFhPNYKopmxaS1CVdyKqUVKizS5ru6/Coo3kJPF
103+
8L/GjIzHH2R9mbsHM81kOpgwXDYeJZ0SIvMjiOP4aHQPm3ju2e+WlQyKFxf3HSM/
104+
r/6Gd9xDwYA/aNH8FdjlhlFFjvQuIJc96+VEAQIDAQABAoIBAQCc6R3tH8a1oPy7
105+
EYXeNy0J/zRqfK82e2V5HsbcOByssHTF9sOxkatm8KPxiQ5wv0mQUiz0VuH1Imrx
106+
cHMqWZ5+ZiNQPpM0zjT8ZII1OVUYl7knYIxYYJSW0BW3mAw/EMXzu8POgg1AJMbq
107+
tmC4J44DQW6EAtej75ejSKpsCgqRXVoi3iEk9eMLHUFIHqkzl/aKEc7k/P+eKo2h
108+
PHsDoKZdmOmZA3OKzw61xAqJICYyplRHatQcEiWJgnLer+9qvUGc4k8eqAYeDGm7
109+
T78XcUvsXOug2GClVWGZu1quFhf7MxjzFfOjz4q9HwPex7X6nQL0IX2hzMECkaMC
110+
iUMZGGEhAoGBAOLY1KSNOjvt54MkKznI8stHkx8V73c0Nxbz5Rj8gM0Gwk1FWVas
111+
jgoAbKPQ2UL/RglLX1JZvztKvNuWSEeZGqggDvhzB38leiEH+OY7DZ7a0c5sWwdF
112+
CpcT1mJb91ww5xEC09WO8Oq3i5olVBBivOl5EjwKHOQn2TUh2OSLhqf/AoGBAOJX
113+
mxqdTEUwFU9ecsAOK9labjI7mA5so0vIq8eq1Q670NFszChfSMKJAqQ90N1LEu9z
114+
L0f6CBXYCn7sMmOlF4CKE+u2/ieJfD1OkKq7RwEd3pi4X3xtAlcPK8F/QprmQWo0
115+
wi33BDBb4zYkuQB6Q5RYIV2di7k+HBpoQPottBP/AoGAIB4xJUc1qoyJjeDOGfVg
116+
ovV0WB9j8026Sw6nLj16Aw1k70nVV1dBGRtsRllomXrJMMGyMleworV3PePuQezk
117+
gE9hrz2iHxdwTkLxs69Cw24Z7I8c6E+XK0LMxMpeoHfwD1GGKqN9as4n/uAwIc3J
118+
D4lr0oJgCtG1iDdNnTZAD4MCgYAkOpWPCwJ8SJgAnkOLzjjij4D39WX/WRBCPxqP
119+
2R5FP3bLLrj29Vl2GewcUfCumyeqwCsfQDwvEueLLU9bd79tSayqnB3OQklqnrq1
120+
OUjCOv+4Pjq6ddBcEweT70S/+n8Z+tvh85nuC6cwsWwTUX6jrf+ZNnB49CIXb/yG
121+
ju42DQKBgAPtbB/ON3+GtnSTHBSY6HwZvGJrBDicrXmr1U9zuA8yYxv8qaRXZkpn
122+
2cpLLvO2MJutwXMYf+T3x1ZCFMkE56pOswSTGrCQWRl3hOiJayLHQyAOYHPnYeZB
123+
78iRJPUZ0biEQUZQ62GBxWkcB0qkxa9m759h/TvLwvV0RrO5Uzd0
124+
-----END RSA PRIVATE KEY-----`)
63125
var expiredStoreCertData = newCertificateData(`-----BEGIN CERTIFICATE-----
64126
MIIBFzCBwgIJALhygXnxXmN1MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCGhv
65127
c3QtMTIzMB4XDTE4MTEwNDIzNTc1NFoXDTE4MTEwNTIzNTc1NFowEzERMA8GA1UE

staging/src/k8s.io/client-go/util/certificate/certificate_store.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import (
2525
"path/filepath"
2626
"time"
2727

28+
certutil "k8s.io/client-go/util/cert"
2829
"k8s.io/klog"
2930
)
3031

@@ -197,11 +198,16 @@ func (s *fileStore) Update(certData, keyData []byte) (*tls.Certificate, error) {
197198
return nil, fmt.Errorf("could not open %q: %v", certPath, err)
198199
}
199200
defer f.Close()
200-
certBlock, _ := pem.Decode(certData)
201-
if certBlock == nil {
202-
return nil, fmt.Errorf("invalid certificate data")
201+
202+
// First cert is leaf, remainder are intermediates
203+
certs, err := certutil.ParseCertsPEM(certData)
204+
if err != nil {
205+
return nil, fmt.Errorf("invalid certificate data: %v", err)
203206
}
204-
pem.Encode(f, certBlock)
207+
for _, c := range certs {
208+
pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: c.Raw})
209+
}
210+
205211
keyBlock, _ := pem.Decode(keyData)
206212
if keyBlock == nil {
207213
return nil, fmt.Errorf("invalid key data")

staging/src/k8s.io/client-go/util/certificate/certificate_store_test.go

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,43 @@ func TestUpdateRotation(t *testing.T) {
284284
}
285285
}
286286

287+
func TestUpdateTwoCerts(t *testing.T) {
288+
prefix := "kubelet-server"
289+
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
290+
if err != nil {
291+
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
292+
}
293+
defer func() {
294+
if err := os.RemoveAll(dir); err != nil {
295+
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
296+
}
297+
}()
298+
keyFile := filepath.Join(dir, "kubelet.key")
299+
if err := ioutil.WriteFile(keyFile, storeTwoCertsData.keyPEM, 0600); err != nil {
300+
t.Fatalf("Unable to create the file %q: %v", keyFile, err)
301+
}
302+
certFile := filepath.Join(dir, "kubelet.crt")
303+
if err := ioutil.WriteFile(certFile, storeTwoCertsData.certificatePEM, 0600); err != nil {
304+
t.Fatalf("Unable to create the file %q: %v", certFile, err)
305+
}
306+
307+
s, err := NewFileStore(prefix, dir, dir, certFile, keyFile)
308+
if err != nil {
309+
t.Fatalf("Got %v while creating a new store.", err)
310+
}
311+
312+
cert, err := s.Update(storeTwoCertsData.certificatePEM, storeTwoCertsData.keyPEM)
313+
if err != nil {
314+
t.Errorf("Got %v while updating certificate store.", err)
315+
}
316+
if cert == nil {
317+
t.Errorf("Got nil certificate, expected something real.")
318+
}
319+
if len(cert.Certificate) != 2 {
320+
t.Fatalf("Unexpected number of certificates, expected 2, got %v", len(cert.Certificate))
321+
}
322+
}
323+
287324
func TestUpdateWithBadCertKeyData(t *testing.T) {
288325
prefix := "kubelet-server"
289326
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
@@ -394,6 +431,46 @@ func TestCurrentCertKeyFiles(t *testing.T) {
394431
}
395432
}
396433

434+
func TestCurrentTwoCerts(t *testing.T) {
435+
prefix := "kubelet-server"
436+
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
437+
if err != nil {
438+
t.Fatalf("Unable to create the test directory %q: %v", dir, err)
439+
}
440+
defer func() {
441+
if err := os.RemoveAll(dir); err != nil {
442+
t.Errorf("Unable to clean up test directory %q: %v", dir, err)
443+
}
444+
}()
445+
certFile := filepath.Join(dir, "kubelet.crt")
446+
if err := ioutil.WriteFile(certFile, storeTwoCertsData.certificatePEM, 0600); err != nil {
447+
t.Fatalf("Unable to create the file %q: %v", certFile, err)
448+
}
449+
keyFile := filepath.Join(dir, "kubelet.key")
450+
if err := ioutil.WriteFile(keyFile, storeTwoCertsData.keyPEM, 0600); err != nil {
451+
t.Fatalf("Unable to create the file %q: %v", keyFile, err)
452+
}
453+
454+
store, err := NewFileStore(prefix, dir, dir, certFile, keyFile)
455+
if err != nil {
456+
t.Fatalf("Failed to initialize certificate store: %v", err)
457+
}
458+
459+
cert, err := store.Current()
460+
if err != nil {
461+
t.Fatalf("Could not load certificate from disk: %v", err)
462+
}
463+
if cert == nil {
464+
t.Fatalf("There was no error, but no certificate data was returned.")
465+
}
466+
if cert.Leaf == nil {
467+
t.Fatalf("Got an empty leaf, expected private data.")
468+
}
469+
if len(cert.Certificate) != 2 {
470+
t.Fatalf("Unexpected number of certificates, expected 2, got %v", len(cert.Certificate))
471+
}
472+
}
473+
397474
func TestCurrentNoFiles(t *testing.T) {
398475
dir, err := ioutil.TempDir("", "k8s-test-certstore-current")
399476
if err != nil {

0 commit comments

Comments
 (0)