1
16
17 package certificate
18
19 import (
20 "bytes"
21 "crypto/tls"
22 "crypto/x509"
23 "crypto/x509/pkix"
24 "fmt"
25 "net"
26 "strings"
27 "testing"
28 "time"
29
30 certificatesv1 "k8s.io/api/certificates/v1"
31 certificatesv1beta1 "k8s.io/api/certificates/v1beta1"
32 apierrors "k8s.io/apimachinery/pkg/api/errors"
33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 "k8s.io/apimachinery/pkg/runtime"
35 "k8s.io/apimachinery/pkg/runtime/schema"
36 watch "k8s.io/apimachinery/pkg/watch"
37 clientset "k8s.io/client-go/kubernetes"
38 "k8s.io/client-go/kubernetes/fake"
39 certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1"
40 clienttesting "k8s.io/client-go/testing"
41 netutils "k8s.io/utils/net"
42 )
43
44 var storeCertData = newCertificateData(`-----BEGIN CERTIFICATE-----
45 MIICRzCCAfGgAwIBAgIJALMb7ecMIk3MMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
46 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
47 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
48 VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwIBcNMTcwNDI2MjMyNjUyWhgPMjExNzA0
49 MDIyMzI2NTJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
50 BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
51 VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwXDANBgkq
52 hkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTCPGO/LEsguKqWHBtKzweMY2CV
53 tAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5MzP2H5QIDAQABo1AwTjAdBgNV
54 HQ4EFgQU22iy8aWkNSxv0nBxFxerfsvnZVMwHwYDVR0jBBgwFoAU22iy8aWkNSxv
55 0nBxFxerfsvnZVMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAEOefGbV
56 NcHxklaW06w6OBYJPwpIhCVozC1qdxGX1dg8VkEKzjOzjgqVD30m59OFmSlBmHsl
57 nkVA6wyOSDYBf3o=
58 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
59 MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAtBMa7NWpv3BVlKTC
60 PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M
61 zP2H5QIDAQABAkAS9BfXab3OKpK3bIgNNyp+DQJKrZnTJ4Q+OjsqkpXvNltPJosf
62 G8GsiKu/vAt4HGqI3eU77NvRI+mL4MnHRmXBAiEA3qM4FAtKSRBbcJzPxxLEUSwg
63 XSCcosCktbkXvpYrS30CIQDPDxgqlwDEJQ0uKuHkZI38/SPWWqfUmkecwlbpXABK
64 iQIgZX08DA8VfvcA5/Xj1Zjdey9FVY6POLXen6RPiabE97UCICp6eUW7ht+2jjar
65 e35EltCRCjoejRHTuN9TC0uCoVipAiAXaJIx/Q47vGwiw6Y8KXsNU6y54gTbOSxX
66 54LzHNk/+Q==
67 -----END RSA PRIVATE KEY-----`)
68 var storeTwoCertsData = newCertificateData(`-----BEGIN CERTIFICATE-----
69 MIIDfTCCAyegAwIBAgIUFBl4gUoqZDP/wUJDn37/VJ9upD0wDQYJKoZIhvcNAQEF
70 BQAwfjELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u
71 ZG9uMRgwFgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFy
72 dG1lbnQxGzAZBgNVBAMMEnRlc3QtY2VydGlmaWNhdGUtMDAeFw0yMDAzMDIxOTM3
73 MDBaFw0yMTAzMDIxOTM3MDBaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs
74 aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEdMBsGA1UEChMURXhhbXBs
75 ZSBDb21wYW55LCBMTEMxEzARBgNVBAsTCk9wZXJhdGlvbnMxGDAWBgNVBAMTD3d3
76 dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMiR
77 DNpmwTICFr+P16fKDVjbNCzSjWq+MTu8vAfS6GrLpBTUEe+6zVqxUza/fZenxo8O
78 ucV2JTUv5J4nkT/vG6Qm/mToVJ4vQzLQ5jR2w7v/7cf3oWCwTAKUafgo6/Ga95gn
79 lQB3+Fd8sy96zfFr/7wDSMPPueR5kSFax+cEd30wwv5O7tWj0ro1mrxLssBlwPaR
80 ZlzkkvxBYTzWCqKZsWktQlXciqlFSos0ua7uvwqKN5CTxfC/xoyMxx9kfZm7BzPN
81 ZDqYMFw2HiWdEiLzI4jj+Gh0D5t47tnvlpUMihcX9x0jP6/+hnfcQ8GAP2jR/BXY
82 5YZRRY70LiCXPevlRAECAwEAAaOBqTCBpjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l
83 BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYE
84 FOoiE+kh7gGDpyx0KZuCc1lrlTRKMB8GA1UdIwQYMBaAFNtosvGlpDUsb9JwcRcX
85 q37L52VTMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb20w
86 DQYJKoZIhvcNAQEFBQADQQAw6mxQONAD2sivfzIf1eDFd6LU7aE+MnkdlEQjjPCi
87 tlUITFIuO3XavISupP6V9wE0b1wTF1pTlVWArf/0YQXs
88 -----END CERTIFICATE-----
89 -----BEGIN CERTIFICATE-----
90 MIICRzCCAfGgAwIBAgIJALMb7ecMIk3MMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
91 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
92 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
93 VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwIBcNMTcwNDI2MjMyNjUyWhgPMjExNzA0
94 MDIyMzI2NTJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
95 BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
96 VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwXDANBgkq
97 hkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTCPGO/LEsguKqWHBtKzweMY2CV
98 tAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5MzP2H5QIDAQABo1AwTjAdBgNV
99 HQ4EFgQU22iy8aWkNSxv0nBxFxerfsvnZVMwHwYDVR0jBBgwFoAU22iy8aWkNSxv
100 0nBxFxerfsvnZVMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAEOefGbV
101 NcHxklaW06w6OBYJPwpIhCVozC1qdxGX1dg8VkEKzjOzjgqVD30m59OFmSlBmHsl
102 nkVA6wyOSDYBf3o=
103 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
104 MIIEowIBAAKCAQEAyJEM2mbBMgIWv4/Xp8oNWNs0LNKNar4xO7y8B9LoasukFNQR
105 77rNWrFTNr99l6fGjw65xXYlNS/knieRP+8bpCb+ZOhUni9DMtDmNHbDu//tx/eh
106 YLBMApRp+Cjr8Zr3mCeVAHf4V3yzL3rN8Wv/vANIw8+55HmRIVrH5wR3fTDC/k7u
107 1aPSujWavEuywGXA9pFmXOSS/EFhPNYKopmxaS1CVdyKqUVKizS5ru6/Coo3kJPF
108 8L/GjIzHH2R9mbsHM81kOpgwXDYeJZ0SIvMjiOP4aHQPm3ju2e+WlQyKFxf3HSM/
109 r/6Gd9xDwYA/aNH8FdjlhlFFjvQuIJc96+VEAQIDAQABAoIBAQCc6R3tH8a1oPy7
110 EYXeNy0J/zRqfK82e2V5HsbcOByssHTF9sOxkatm8KPxiQ5wv0mQUiz0VuH1Imrx
111 cHMqWZ5+ZiNQPpM0zjT8ZII1OVUYl7knYIxYYJSW0BW3mAw/EMXzu8POgg1AJMbq
112 tmC4J44DQW6EAtej75ejSKpsCgqRXVoi3iEk9eMLHUFIHqkzl/aKEc7k/P+eKo2h
113 PHsDoKZdmOmZA3OKzw61xAqJICYyplRHatQcEiWJgnLer+9qvUGc4k8eqAYeDGm7
114 T78XcUvsXOug2GClVWGZu1quFhf7MxjzFfOjz4q9HwPex7X6nQL0IX2hzMECkaMC
115 iUMZGGEhAoGBAOLY1KSNOjvt54MkKznI8stHkx8V73c0Nxbz5Rj8gM0Gwk1FWVas
116 jgoAbKPQ2UL/RglLX1JZvztKvNuWSEeZGqggDvhzB38leiEH+OY7DZ7a0c5sWwdF
117 CpcT1mJb91ww5xEC09WO8Oq3i5olVBBivOl5EjwKHOQn2TUh2OSLhqf/AoGBAOJX
118 mxqdTEUwFU9ecsAOK9labjI7mA5so0vIq8eq1Q670NFszChfSMKJAqQ90N1LEu9z
119 L0f6CBXYCn7sMmOlF4CKE+u2/ieJfD1OkKq7RwEd3pi4X3xtAlcPK8F/QprmQWo0
120 wi33BDBb4zYkuQB6Q5RYIV2di7k+HBpoQPottBP/AoGAIB4xJUc1qoyJjeDOGfVg
121 ovV0WB9j8026Sw6nLj16Aw1k70nVV1dBGRtsRllomXrJMMGyMleworV3PePuQezk
122 gE9hrz2iHxdwTkLxs69Cw24Z7I8c6E+XK0LMxMpeoHfwD1GGKqN9as4n/uAwIc3J
123 D4lr0oJgCtG1iDdNnTZAD4MCgYAkOpWPCwJ8SJgAnkOLzjjij4D39WX/WRBCPxqP
124 2R5FP3bLLrj29Vl2GewcUfCumyeqwCsfQDwvEueLLU9bd79tSayqnB3OQklqnrq1
125 OUjCOv+4Pjq6ddBcEweT70S/+n8Z+tvh85nuC6cwsWwTUX6jrf+ZNnB49CIXb/yG
126 ju42DQKBgAPtbB/ON3+GtnSTHBSY6HwZvGJrBDicrXmr1U9zuA8yYxv8qaRXZkpn
127 2cpLLvO2MJutwXMYf+T3x1ZCFMkE56pOswSTGrCQWRl3hOiJayLHQyAOYHPnYeZB
128 78iRJPUZ0biEQUZQ62GBxWkcB0qkxa9m759h/TvLwvV0RrO5Uzd0
129 -----END RSA PRIVATE KEY-----`)
130 var expiredStoreCertData = newCertificateData(`-----BEGIN CERTIFICATE-----
131 MIIBFzCBwgIJALhygXnxXmN1MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCGhv
132 c3QtMTIzMB4XDTE4MTEwNDIzNTc1NFoXDTE4MTEwNTIzNTc1NFowEzERMA8GA1UE
133 AwwIaG9zdC0xMjMwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTC
134 PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M
135 zP2H5QIDAQABMA0GCSqGSIb3DQEBCwUAA0EAN2DPFUtCzqnidL+5nh+46Sk6dkMI
136 T5DD11UuuIjZusKvThsHKVCIsyJ2bDo7cTbI+/nklLRP+FcC2wESFUgXbA==
137 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
138 MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAtBMa7NWpv3BVlKTC
139 PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M
140 zP2H5QIDAQABAkAS9BfXab3OKpK3bIgNNyp+DQJKrZnTJ4Q+OjsqkpXvNltPJosf
141 G8GsiKu/vAt4HGqI3eU77NvRI+mL4MnHRmXBAiEA3qM4FAtKSRBbcJzPxxLEUSwg
142 XSCcosCktbkXvpYrS30CIQDPDxgqlwDEJQ0uKuHkZI38/SPWWqfUmkecwlbpXABK
143 iQIgZX08DA8VfvcA5/Xj1Zjdey9FVY6POLXen6RPiabE97UCICp6eUW7ht+2jjar
144 e35EltCRCjoejRHTuN9TC0uCoVipAiAXaJIx/Q47vGwiw6Y8KXsNU6y54gTbOSxX
145 54LzHNk/+Q==
146 -----END RSA PRIVATE KEY-----`)
147 var bootstrapCertData = newCertificateData(
148 `-----BEGIN CERTIFICATE-----
149 MIICRzCCAfGgAwIBAgIJANXr+UzRFq4TMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
150 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
151 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
152 VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTEwIBcNMTcwNDI2MjMyNzMyWhgPMjExNzA0
153 MDIyMzI3MzJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
154 BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
155 VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTEwXDANBgkq
156 hkiG9w0BAQEFAANLADBIAkEAqvbkN4RShH1rL37JFp4fZPnn0JUhVWWsrP8NOomJ
157 pXdBDUMGWuEQIsZ1Gf9JrCQLu6ooRyHSKRFpAVbMQ3ABJwIDAQABo1AwTjAdBgNV
158 HQ4EFgQUEGBc6YYheEZ/5MhwqSUYYPYRj2MwHwYDVR0jBBgwFoAUEGBc6YYheEZ/
159 5MhwqSUYYPYRj2MwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAIyNmznk
160 5dgJY52FppEEcfQRdS5k4XFPc22SHPcz77AHf5oWZ1WG9VezOZZPp8NCiFDDlDL8
161 yma33a5eMyTjLD8=
162 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
163 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqvbkN4RShH1rL37J
164 Fp4fZPnn0JUhVWWsrP8NOomJpXdBDUMGWuEQIsZ1Gf9JrCQLu6ooRyHSKRFpAVbM
165 Q3ABJwIDAQABAkBC2OBpGLMPHN8BJijIUDFkURakBvuOoX+/8MYiYk7QxEmfLCk6
166 L6r+GLNFMfXwXcBmXtMKfZKAIKutKf098JaBAiEA10azfqt3G/5owrNA00plSyT6
167 ZmHPzY9Uq1p/QTR/uOcCIQDLTkfBkLHm0UKeobbO/fSm6ZflhyBRDINy4FvwmZMt
168 wQIgYV/tmQJeIh91q3wBepFQOClFykG8CTMoDUol/YyNqUkCIHfp6Rr7fGL3JIMq
169 QQgf9DCK8SPZqq8DYXjdan0kKBJBAiEAyDb+07o2gpggo8BYUKSaiRCiyXfaq87f
170 eVqgpBq/QN4=
171 -----END RSA PRIVATE KEY-----`)
172 var apiServerCertData = newCertificateData(
173 `-----BEGIN CERTIFICATE-----
174 MIICRzCCAfGgAwIBAgIJAIydTIADd+yqMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
175 BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE
176 CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD
177 VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTIwIBcNMTcwNDI2MjMyNDU4WhgPMjExNzA0
178 MDIyMzI0NThaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV
179 BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J
180 VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTIwXDANBgkq
181 hkiG9w0BAQEFAANLADBIAkEAuiRet28DV68Dk4A8eqCaqgXmymamUEjW/DxvIQqH
182 3lbhtm8BwSnS9wUAajSLSWiq3fci2RbRgaSPjUrnbOHCLQIDAQABo1AwTjAdBgNV
183 HQ4EFgQU0vhI4OPGEOqT+VAWwxdhVvcmgdIwHwYDVR0jBBgwFoAU0vhI4OPGEOqT
184 +VAWwxdhVvcmgdIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBALNeJGDe
185 nV5cXbp9W1bC12Tc8nnNXn4ypLE2JTQAvyp51zoZ8hQoSnRVx/VCY55Yu+br8gQZ
186 +tW+O/PoE7B3tuY=
187 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY-----
188 MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAuiRet28DV68Dk4A8
189 eqCaqgXmymamUEjW/DxvIQqH3lbhtm8BwSnS9wUAajSLSWiq3fci2RbRgaSPjUrn
190 bOHCLQIDAQABAkEArDR1g9IqD3aUImNikDgAngbzqpAokOGyMoxeavzpEaFOgCzi
191 gi7HF7yHRmZkUt8CzdEvnHSqRjFuaaB0gGA+AQIhAOc8Z1h8ElLRSqaZGgI3jCTp
192 Izx9HNY//U5NGrXD2+ttAiEAzhOqkqI4+nDab7FpiD7MXI6fO549mEXeVBPvPtsS
193 OcECIQCIfkpOm+ZBBpO3JXaJynoqK4gGI6ALA/ik6LSUiIlfPQIhAISjd9hlfZME
194 bDQT1r8Q3Gx+h9LRqQeHgPBQ3F5ylqqBAiBaJ0hkYvrIdWxNlcLqD3065bJpHQ4S
195 WQkuZUQN1M/Xvg==
196 -----END RSA PRIVATE KEY-----`)
197
198 type certificateData struct {
199 keyPEM []byte
200 certificatePEM []byte
201 certificate *tls.Certificate
202 }
203
204 func newCertificateData(certificatePEM string, keyPEM string) *certificateData {
205 certificate, err := tls.X509KeyPair([]byte(certificatePEM), []byte(keyPEM))
206 if err != nil {
207 panic(fmt.Sprintf("Unable to initialize certificate: %v", err))
208 }
209 certs, err := x509.ParseCertificates(certificate.Certificate[0])
210 if err != nil {
211 panic(fmt.Sprintf("Unable to initialize certificate leaf: %v", err))
212 }
213 certificate.Leaf = certs[0]
214 return &certificateData{
215 keyPEM: []byte(keyPEM),
216 certificatePEM: []byte(certificatePEM),
217 certificate: &certificate,
218 }
219 }
220
221 func TestNewManagerNoRotation(t *testing.T) {
222 store := &fakeStore{
223 cert: storeCertData.certificate,
224 }
225 if _, err := NewManager(&Config{
226 Template: &x509.CertificateRequest{},
227 Usages: []certificatesv1.KeyUsage{},
228 CertificateStore: store,
229 }); err != nil {
230 t.Fatalf("Failed to initialize the certificate manager: %v", err)
231 }
232 }
233
234 type metricMock struct {
235 calls int
236 lastValue float64
237 }
238
239 func (g *metricMock) Set(v float64) {
240 g.calls++
241 g.lastValue = v
242 }
243
244 func (g *metricMock) Observe(v float64) {
245 g.calls++
246 g.lastValue = v
247 }
248
249 func TestSetRotationDeadline(t *testing.T) {
250 defer func(original func(float64) time.Duration) { jitteryDuration = original }(jitteryDuration)
251
252 now := time.Now()
253 testCases := []struct {
254 name string
255 notBefore time.Time
256 notAfter time.Time
257 shouldRotate bool
258 }{
259 {"just issued, still good", now.Add(-1 * time.Hour), now.Add(99 * time.Hour), false},
260 {"half way expired, still good", now.Add(-24 * time.Hour), now.Add(24 * time.Hour), false},
261 {"mostly expired, still good", now.Add(-69 * time.Hour), now.Add(31 * time.Hour), false},
262 {"just about expired, should rotate", now.Add(-91 * time.Hour), now.Add(9 * time.Hour), true},
263 {"nearly expired, should rotate", now.Add(-99 * time.Hour), now.Add(1 * time.Hour), true},
264 {"already expired, should rotate", now.Add(-10 * time.Hour), now.Add(-1 * time.Hour), true},
265 {"long duration", now.Add(-6 * 30 * 24 * time.Hour), now.Add(6 * 30 * 24 * time.Hour), true},
266 {"short duration", now.Add(-30 * time.Second), now.Add(30 * time.Second), true},
267 }
268
269 for _, tc := range testCases {
270 t.Run(tc.name, func(t *testing.T) {
271 m := manager{
272 cert: &tls.Certificate{
273 Leaf: &x509.Certificate{
274 NotBefore: tc.notBefore,
275 NotAfter: tc.notAfter,
276 },
277 },
278 getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
279 now: func() time.Time { return now },
280 logf: t.Logf,
281 }
282 jitteryDuration = func(float64) time.Duration { return time.Duration(float64(tc.notAfter.Sub(tc.notBefore)) * 0.7) }
283 lowerBound := tc.notBefore.Add(time.Duration(float64(tc.notAfter.Sub(tc.notBefore)) * 0.7))
284
285 deadline := m.nextRotationDeadline()
286
287 if !deadline.Equal(lowerBound) {
288 t.Errorf("For notBefore %v, notAfter %v, the rotationDeadline %v should be %v.",
289 tc.notBefore,
290 tc.notAfter,
291 deadline,
292 lowerBound)
293 }
294 })
295 }
296 }
297
298 func TestCertSatisfiesTemplate(t *testing.T) {
299 testCases := []struct {
300 name string
301 cert *x509.Certificate
302 template *x509.CertificateRequest
303 shouldSatisfy bool
304 }{
305 {
306 name: "No certificate, no template",
307 cert: nil,
308 template: nil,
309 shouldSatisfy: false,
310 },
311 {
312 name: "No certificate",
313 cert: nil,
314 template: &x509.CertificateRequest{},
315 shouldSatisfy: false,
316 },
317 {
318 name: "No template",
319 cert: &x509.Certificate{
320 Subject: pkix.Name{
321 CommonName: "system:node:fake-node-name",
322 },
323 },
324 template: nil,
325 shouldSatisfy: true,
326 },
327 {
328 name: "Mismatched common name",
329 cert: &x509.Certificate{
330 Subject: pkix.Name{
331 CommonName: "system:node:fake-node-name-2",
332 },
333 },
334 template: &x509.CertificateRequest{
335 Subject: pkix.Name{
336 CommonName: "system:node:fake-node-name",
337 },
338 },
339 shouldSatisfy: false,
340 },
341 {
342 name: "Missing orgs in certificate",
343 cert: &x509.Certificate{
344 Subject: pkix.Name{
345 Organization: []string{"system:nodes"},
346 },
347 },
348 template: &x509.CertificateRequest{
349 Subject: pkix.Name{
350 Organization: []string{"system:nodes", "foobar"},
351 },
352 },
353 shouldSatisfy: false,
354 },
355 {
356 name: "Extra orgs in certificate",
357 cert: &x509.Certificate{
358 Subject: pkix.Name{
359 Organization: []string{"system:nodes", "foobar"},
360 },
361 },
362 template: &x509.CertificateRequest{
363 Subject: pkix.Name{
364 Organization: []string{"system:nodes"},
365 },
366 },
367 shouldSatisfy: true,
368 },
369 {
370 name: "Missing DNS names in certificate",
371 cert: &x509.Certificate{
372 Subject: pkix.Name{},
373 DNSNames: []string{"foo.example.com"},
374 },
375 template: &x509.CertificateRequest{
376 Subject: pkix.Name{},
377 DNSNames: []string{"foo.example.com", "bar.example.com"},
378 },
379 shouldSatisfy: false,
380 },
381 {
382 name: "Extra DNS names in certificate",
383 cert: &x509.Certificate{
384 Subject: pkix.Name{},
385 DNSNames: []string{"foo.example.com", "bar.example.com"},
386 },
387 template: &x509.CertificateRequest{
388 Subject: pkix.Name{},
389 DNSNames: []string{"foo.example.com"},
390 },
391 shouldSatisfy: true,
392 },
393 {
394 name: "Missing IP addresses in certificate",
395 cert: &x509.Certificate{
396 Subject: pkix.Name{},
397 IPAddresses: []net.IP{netutils.ParseIPSloppy("192.168.1.1")},
398 },
399 template: &x509.CertificateRequest{
400 Subject: pkix.Name{},
401 IPAddresses: []net.IP{netutils.ParseIPSloppy("192.168.1.1"), netutils.ParseIPSloppy("192.168.1.2")},
402 },
403 shouldSatisfy: false,
404 },
405 {
406 name: "Extra IP addresses in certificate",
407 cert: &x509.Certificate{
408 Subject: pkix.Name{},
409 IPAddresses: []net.IP{netutils.ParseIPSloppy("192.168.1.1"), netutils.ParseIPSloppy("192.168.1.2")},
410 },
411 template: &x509.CertificateRequest{
412 Subject: pkix.Name{},
413 IPAddresses: []net.IP{netutils.ParseIPSloppy("192.168.1.1")},
414 },
415 shouldSatisfy: true,
416 },
417 {
418 name: "Matching certificate",
419 cert: &x509.Certificate{
420 Subject: pkix.Name{
421 CommonName: "system:node:fake-node-name",
422 Organization: []string{"system:nodes"},
423 },
424 DNSNames: []string{"foo.example.com"},
425 IPAddresses: []net.IP{netutils.ParseIPSloppy("192.168.1.1")},
426 },
427 template: &x509.CertificateRequest{
428 Subject: pkix.Name{
429 CommonName: "system:node:fake-node-name",
430 Organization: []string{"system:nodes"},
431 },
432 DNSNames: []string{"foo.example.com"},
433 IPAddresses: []net.IP{netutils.ParseIPSloppy("192.168.1.1")},
434 },
435 shouldSatisfy: true,
436 },
437 }
438
439 for _, tc := range testCases {
440 t.Run(tc.name, func(t *testing.T) {
441 var tlsCert *tls.Certificate
442
443 if tc.cert != nil {
444 tlsCert = &tls.Certificate{
445 Leaf: tc.cert,
446 }
447 }
448
449 m := manager{
450 cert: tlsCert,
451 getTemplate: func() *x509.CertificateRequest { return tc.template },
452 now: time.Now,
453 logf: t.Logf,
454 }
455
456 result := m.certSatisfiesTemplate()
457 if result != tc.shouldSatisfy {
458 t.Errorf("cert: %+v, template: %+v, certSatisfiesTemplate returned %v, want %v", m.cert, tc.template, result, tc.shouldSatisfy)
459 }
460 })
461 }
462 }
463
464 func TestRotateCertCreateCSRError(t *testing.T) {
465 now := time.Now()
466 m := manager{
467 cert: &tls.Certificate{
468 Leaf: &x509.Certificate{
469 NotBefore: now.Add(-2 * time.Hour),
470 NotAfter: now.Add(-1 * time.Hour),
471 },
472 },
473 getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
474 clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
475 return newClientset(fakeClient{failureType: createError}), nil
476 },
477 now: func() time.Time { return now },
478 logf: t.Logf,
479 }
480
481 if success, err := m.rotateCerts(); success {
482 t.Errorf("Got success from 'rotateCerts', wanted failure")
483 } else if err != nil {
484 t.Errorf("Got error %v from 'rotateCerts', wanted no error.", err)
485 }
486 }
487
488 func TestRotateCertWaitingForResultError(t *testing.T) {
489 now := time.Now()
490 m := manager{
491 cert: &tls.Certificate{
492 Leaf: &x509.Certificate{
493 NotBefore: now.Add(-2 * time.Hour),
494 NotAfter: now.Add(-1 * time.Hour),
495 },
496 },
497 getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
498 clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
499 return newClientset(fakeClient{failureType: watchError}), nil
500 },
501 now: func() time.Time { return now },
502 logf: t.Logf,
503 }
504
505 defer func(t time.Duration) { certificateWaitTimeout = t }(certificateWaitTimeout)
506 certificateWaitTimeout = 1 * time.Millisecond
507 if success, err := m.rotateCerts(); success {
508 t.Errorf("Got success from 'rotateCerts', wanted failure.")
509 } else if err != nil {
510 t.Errorf("Got error %v from 'rotateCerts', wanted no error.", err)
511 }
512 }
513
514 func TestNewManagerBootstrap(t *testing.T) {
515 store := &fakeStore{}
516
517 var cm Manager
518 cm, err := NewManager(&Config{
519 Template: &x509.CertificateRequest{},
520 Usages: []certificatesv1.KeyUsage{},
521 CertificateStore: store,
522 BootstrapCertificatePEM: bootstrapCertData.certificatePEM,
523 BootstrapKeyPEM: bootstrapCertData.keyPEM,
524 })
525 if err != nil {
526 t.Fatalf("Failed to initialize the certificate manager: %v", err)
527 }
528
529 cert := cm.Current()
530
531 if cert == nil {
532 t.Errorf("Certificate was nil, expected something.")
533 }
534 if m, ok := cm.(*manager); !ok {
535 t.Errorf("Expected a '*manager' from 'NewManager'")
536 } else if !m.forceRotation {
537 t.Errorf("Expected rotation should happen during bootstrap, but it won't.")
538 }
539 }
540
541 func TestNewManagerNoBootstrap(t *testing.T) {
542 now := time.Now()
543 cert, err := tls.X509KeyPair(storeCertData.certificatePEM, storeCertData.keyPEM)
544 if err != nil {
545 t.Fatalf("Unable to initialize a certificate: %v", err)
546 }
547 cert.Leaf = &x509.Certificate{
548 NotBefore: now.Add(-24 * time.Hour),
549 NotAfter: now.Add(24 * time.Hour),
550 }
551 store := &fakeStore{
552 cert: &cert,
553 }
554
555 cm, err := NewManager(&Config{
556 Template: &x509.CertificateRequest{},
557 Usages: []certificatesv1.KeyUsage{},
558 CertificateStore: store,
559 BootstrapCertificatePEM: bootstrapCertData.certificatePEM,
560 BootstrapKeyPEM: bootstrapCertData.keyPEM,
561 })
562
563 if err != nil {
564 t.Fatalf("Failed to initialize the certificate manager: %v", err)
565 }
566
567 currentCert := cm.Current()
568
569 if currentCert == nil {
570 t.Errorf("Certificate was nil, expected something.")
571 }
572 if m, ok := cm.(*manager); !ok {
573 t.Errorf("Expected a '*manager' from 'NewManager'")
574 } else {
575 if m.forceRotation {
576 t.Errorf("Expected rotation should not happen during bootstrap, but it won't.")
577 }
578 }
579 }
580
581 func TestGetCurrentCertificateOrBootstrap(t *testing.T) {
582 testCases := []struct {
583 description string
584 storeCert *tls.Certificate
585 bootstrapCertData []byte
586 bootstrapKeyData []byte
587 expectedCert *tls.Certificate
588 expectedShouldRotate bool
589 expectedErrMsg string
590 }{
591 {
592 "return cert from store",
593 storeCertData.certificate,
594 nil,
595 nil,
596 storeCertData.certificate,
597 false,
598 "",
599 },
600 {
601 "no cert in store and no bootstrap cert",
602 nil,
603 nil,
604 nil,
605 nil,
606 true,
607 "",
608 },
609 }
610
611 for _, tc := range testCases {
612 t.Run(tc.description, func(t *testing.T) {
613 store := &fakeStore{
614 cert: tc.storeCert,
615 }
616
617 certResult, shouldRotate, err := getCurrentCertificateOrBootstrap(
618 store,
619 tc.bootstrapCertData,
620 tc.bootstrapKeyData)
621 if certResult == nil || certResult.Certificate == nil || tc.expectedCert == nil {
622 if certResult != nil && tc.expectedCert != nil {
623 t.Errorf("Got certificate %v, wanted %v", certResult, tc.expectedCert)
624 }
625 } else {
626 if !certificatesEqual(certResult, tc.expectedCert) {
627 t.Errorf("Got certificate %v, wanted %v", certResult, tc.expectedCert)
628 }
629 }
630 if shouldRotate != tc.expectedShouldRotate {
631 t.Errorf("Got shouldRotate %t, wanted %t", shouldRotate, tc.expectedShouldRotate)
632 }
633 if err == nil {
634 if tc.expectedErrMsg != "" {
635 t.Errorf("Got err %v, wanted %q", err, tc.expectedErrMsg)
636 }
637 } else {
638 if tc.expectedErrMsg == "" || !strings.Contains(err.Error(), tc.expectedErrMsg) {
639 t.Errorf("Got err %v, wanted %q", err, tc.expectedErrMsg)
640 }
641 }
642 })
643 }
644 }
645
646 func TestInitializeCertificateSigningRequestClient(t *testing.T) {
647 var nilCertificate = &certificateData{}
648 testCases := []struct {
649 description string
650 storeCert *certificateData
651 bootstrapCert *certificateData
652 apiCert *certificateData
653 noV1 bool
654 noV1beta1 bool
655 expectedCertBeforeStart *certificateData
656 expectedCertAfterStart *certificateData
657 }{
658 {
659 description: "No current certificate, no bootstrap certificate",
660 storeCert: nilCertificate,
661 bootstrapCert: nilCertificate,
662 apiCert: apiServerCertData,
663 expectedCertBeforeStart: nilCertificate,
664 expectedCertAfterStart: apiServerCertData,
665 },
666 {
667 description: "No current certificate, no bootstrap certificate, no v1 API",
668 storeCert: nilCertificate,
669 bootstrapCert: nilCertificate,
670 apiCert: apiServerCertData,
671 expectedCertBeforeStart: nilCertificate,
672 expectedCertAfterStart: apiServerCertData,
673 noV1: true,
674 },
675 {
676 description: "No current certificate, no bootstrap certificate, no v1beta1 API",
677 storeCert: nilCertificate,
678 bootstrapCert: nilCertificate,
679 apiCert: apiServerCertData,
680 expectedCertBeforeStart: nilCertificate,
681 expectedCertAfterStart: apiServerCertData,
682 noV1beta1: true,
683 },
684 {
685 description: "No current certificate, bootstrap certificate",
686 storeCert: nilCertificate,
687 bootstrapCert: bootstrapCertData,
688 apiCert: apiServerCertData,
689 expectedCertBeforeStart: bootstrapCertData,
690 expectedCertAfterStart: apiServerCertData,
691 },
692 {
693 description: "Current certificate, no bootstrap certificate",
694 storeCert: storeCertData,
695 bootstrapCert: nilCertificate,
696 apiCert: apiServerCertData,
697 expectedCertBeforeStart: storeCertData,
698 expectedCertAfterStart: storeCertData,
699 },
700 {
701 description: "Current certificate, bootstrap certificate",
702 storeCert: storeCertData,
703 bootstrapCert: bootstrapCertData,
704 apiCert: apiServerCertData,
705 expectedCertBeforeStart: storeCertData,
706 expectedCertAfterStart: storeCertData,
707 },
708 {
709 description: "Current certificate expired, no bootstrap certificate",
710 storeCert: expiredStoreCertData,
711 bootstrapCert: nilCertificate,
712 apiCert: apiServerCertData,
713 expectedCertBeforeStart: nil,
714 expectedCertAfterStart: apiServerCertData,
715 },
716 }
717
718 for _, tc := range testCases {
719 t.Run(tc.description, func(t *testing.T) {
720 certificateStore := &fakeStore{
721 cert: tc.storeCert.certificate,
722 }
723
724 certificateManager, err := NewManager(&Config{
725 Template: &x509.CertificateRequest{
726 Subject: pkix.Name{
727 Organization: []string{"system:nodes"},
728 CommonName: "system:node:fake-node-name",
729 },
730 },
731 SignerName: certificatesv1.KubeAPIServerClientSignerName,
732 Usages: []certificatesv1.KeyUsage{
733 certificatesv1.UsageDigitalSignature,
734 certificatesv1.UsageKeyEncipherment,
735 certificatesv1.UsageClientAuth,
736 },
737 CertificateStore: certificateStore,
738 BootstrapCertificatePEM: tc.bootstrapCert.certificatePEM,
739 BootstrapKeyPEM: tc.bootstrapCert.keyPEM,
740 ClientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
741 return newClientset(fakeClient{
742 noV1: tc.noV1,
743 noV1beta1: tc.noV1beta1,
744 certificatePEM: tc.apiCert.certificatePEM,
745 }), nil
746 },
747 })
748 if err != nil {
749 t.Errorf("Got %v, wanted no error.", err)
750 }
751
752 certificate := certificateManager.Current()
753 if tc.expectedCertBeforeStart == nil {
754 if certificate != nil {
755 t.Errorf("Expected certificate to be nil, was %s", certificate.Leaf.NotAfter)
756 }
757 } else {
758 if !certificatesEqual(certificate, tc.expectedCertBeforeStart.certificate) {
759 t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
760 }
761 }
762
763 if m, ok := certificateManager.(*manager); !ok {
764 t.Errorf("Expected a '*manager' from 'NewManager'")
765 } else {
766 if m.forceRotation {
767 if success, err := m.rotateCerts(); !success {
768 t.Errorf("Got failure from 'rotateCerts', wanted success.")
769 } else if err != nil {
770 t.Errorf("Got error %v, expected none.", err)
771 }
772 }
773 }
774
775 certificate = certificateManager.Current()
776 if tc.expectedCertAfterStart == nil {
777 if certificate != nil {
778 t.Errorf("Expected certificate to be nil, was %s", certificate.Leaf.NotAfter)
779 }
780 return
781 }
782 if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
783 t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertAfterStart.certificate))
784 }
785 })
786 }
787 }
788
789 func TestInitializeOtherRESTClients(t *testing.T) {
790 var nilCertificate = &certificateData{}
791 testCases := []struct {
792 description string
793 storeCert *certificateData
794 bootstrapCert *certificateData
795 apiCert *certificateData
796 expectedCertBeforeStart *certificateData
797 expectedCertAfterStart *certificateData
798 }{
799 {
800 description: "No current certificate, no bootstrap certificate",
801 storeCert: nilCertificate,
802 bootstrapCert: nilCertificate,
803 apiCert: apiServerCertData,
804 expectedCertBeforeStart: nilCertificate,
805 expectedCertAfterStart: apiServerCertData,
806 },
807 {
808 description: "No current certificate, bootstrap certificate",
809 storeCert: nilCertificate,
810 bootstrapCert: bootstrapCertData,
811 apiCert: apiServerCertData,
812 expectedCertBeforeStart: bootstrapCertData,
813 expectedCertAfterStart: apiServerCertData,
814 },
815 {
816 description: "Current certificate, no bootstrap certificate",
817 storeCert: storeCertData,
818 bootstrapCert: nilCertificate,
819 apiCert: apiServerCertData,
820 expectedCertBeforeStart: storeCertData,
821 expectedCertAfterStart: storeCertData,
822 },
823 {
824 description: "Current certificate, bootstrap certificate",
825 storeCert: storeCertData,
826 bootstrapCert: bootstrapCertData,
827 apiCert: apiServerCertData,
828 expectedCertBeforeStart: storeCertData,
829 expectedCertAfterStart: storeCertData,
830 },
831 }
832
833 for _, tc := range testCases {
834 t.Run(tc.description, func(t *testing.T) {
835 certificateStore := &fakeStore{
836 cert: tc.storeCert.certificate,
837 }
838
839 certificateManager, err := NewManager(&Config{
840 Template: &x509.CertificateRequest{
841 Subject: pkix.Name{
842 Organization: []string{"system:nodes"},
843 CommonName: "system:node:fake-node-name",
844 },
845 },
846 Usages: []certificatesv1.KeyUsage{
847 certificatesv1.UsageDigitalSignature,
848 certificatesv1.UsageKeyEncipherment,
849 certificatesv1.UsageClientAuth,
850 },
851 CertificateStore: certificateStore,
852 BootstrapCertificatePEM: tc.bootstrapCert.certificatePEM,
853 BootstrapKeyPEM: tc.bootstrapCert.keyPEM,
854 ClientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
855 return newClientset(fakeClient{
856 certificatePEM: tc.apiCert.certificatePEM,
857 }), nil
858 },
859 })
860 if err != nil {
861 t.Errorf("Got %v, wanted no error.", err)
862 }
863
864 certificate := certificateManager.Current()
865 if !certificatesEqual(certificate, tc.expectedCertBeforeStart.certificate) {
866 t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
867 }
868
869 if m, ok := certificateManager.(*manager); !ok {
870 t.Errorf("Expected a '*manager' from 'NewManager'")
871 } else {
872 if m.forceRotation {
873 success, err := certificateManager.(*manager).rotateCerts()
874 if err != nil {
875 t.Errorf("Got error %v, expected none.", err)
876 return
877 }
878 if !success {
879 t.Errorf("Unexpected response 'rotateCerts': %t", success)
880 return
881 }
882 }
883 }
884
885 certificate = certificateManager.Current()
886 if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
887 t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertAfterStart.certificate))
888 }
889 })
890 }
891 }
892
893 func TestServerHealth(t *testing.T) {
894 type certs struct {
895 storeCert *certificateData
896 bootstrapCert *certificateData
897 apiCert *certificateData
898 expectedCertBeforeStart *certificateData
899 expectedCertAfterStart *certificateData
900 }
901
902 updatedCerts := certs{
903 storeCert: storeCertData,
904 bootstrapCert: bootstrapCertData,
905 apiCert: apiServerCertData,
906 expectedCertBeforeStart: storeCertData,
907 expectedCertAfterStart: apiServerCertData,
908 }
909
910 currentCerts := certs{
911 storeCert: storeCertData,
912 bootstrapCert: bootstrapCertData,
913 apiCert: apiServerCertData,
914 expectedCertBeforeStart: storeCertData,
915 expectedCertAfterStart: storeCertData,
916 }
917
918 testCases := []struct {
919 description string
920 certs
921
922 failureType fakeClientFailureType
923 clientErr error
924
925 expectRotateFail bool
926 expectHealthy bool
927 }{
928 {
929 description: "Current certificate, bootstrap certificate",
930 certs: updatedCerts,
931 expectHealthy: true,
932 },
933 {
934 description: "Generic error on create",
935 certs: currentCerts,
936
937 failureType: createError,
938 expectRotateFail: true,
939 },
940 {
941 description: "Unauthorized error on create",
942 certs: currentCerts,
943
944 failureType: createError,
945 clientErr: apierrors.NewUnauthorized("unauthorized"),
946 expectRotateFail: true,
947 expectHealthy: true,
948 },
949 {
950 description: "Generic unauthorized error on create",
951 certs: currentCerts,
952
953 failureType: createError,
954 clientErr: apierrors.NewGenericServerResponse(401, "POST", schema.GroupResource{}, "", "", 0, true),
955 expectRotateFail: true,
956 expectHealthy: true,
957 },
958 {
959 description: "Generic not found error on create",
960 certs: currentCerts,
961
962 failureType: createError,
963 clientErr: apierrors.NewGenericServerResponse(404, "POST", schema.GroupResource{}, "", "", 0, true),
964 expectRotateFail: true,
965 expectHealthy: false,
966 },
967 {
968 description: "Not found error on create",
969 certs: currentCerts,
970
971 failureType: createError,
972 clientErr: apierrors.NewGenericServerResponse(404, "POST", schema.GroupResource{}, "", "", 0, false),
973 expectRotateFail: true,
974 expectHealthy: true,
975 },
976 }
977
978 for _, tc := range testCases {
979 t.Run(tc.description, func(t *testing.T) {
980 certificateStore := &fakeStore{
981 cert: tc.storeCert.certificate,
982 }
983
984 certificateManager, err := NewManager(&Config{
985 Template: &x509.CertificateRequest{
986 Subject: pkix.Name{
987 Organization: []string{"system:nodes"},
988 CommonName: "system:node:fake-node-name",
989 },
990 },
991 Usages: []certificatesv1.KeyUsage{
992 certificatesv1.UsageDigitalSignature,
993 certificatesv1.UsageKeyEncipherment,
994 certificatesv1.UsageClientAuth,
995 },
996 CertificateStore: certificateStore,
997 BootstrapCertificatePEM: tc.bootstrapCert.certificatePEM,
998 BootstrapKeyPEM: tc.bootstrapCert.keyPEM,
999 ClientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
1000 return newClientset(fakeClient{
1001 certificatePEM: tc.apiCert.certificatePEM,
1002 failureType: tc.failureType,
1003 err: tc.clientErr,
1004 }), nil
1005 },
1006 })
1007 if err != nil {
1008 t.Errorf("Got %v, wanted no error.", err)
1009 }
1010
1011 certificate := certificateManager.Current()
1012 if !certificatesEqual(certificate, tc.expectedCertBeforeStart.certificate) {
1013 t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertBeforeStart.certificate))
1014 }
1015
1016 if _, ok := certificateManager.(*manager); !ok {
1017 t.Errorf("Expected a '*manager' from 'NewManager'")
1018 } else {
1019 success, err := certificateManager.(*manager).rotateCerts()
1020 if err != nil {
1021 t.Errorf("Got error %v, expected none.", err)
1022 return
1023 }
1024 if !success != tc.expectRotateFail {
1025 t.Errorf("Unexpected response 'rotateCerts': %t", success)
1026 return
1027 }
1028 if actual := certificateManager.(*manager).ServerHealthy(); actual != tc.expectHealthy {
1029 t.Errorf("Unexpected manager server health: %t", actual)
1030 }
1031 }
1032
1033 certificate = certificateManager.Current()
1034 if !certificatesEqual(certificate, tc.expectedCertAfterStart.certificate) {
1035 t.Errorf("Got %v, wanted %v", certificateString(certificate), certificateString(tc.expectedCertAfterStart.certificate))
1036 }
1037 })
1038 }
1039 }
1040
1041 func TestRotationLogsDuration(t *testing.T) {
1042 h := metricMock{}
1043 now := time.Now()
1044 certIss := now.Add(-2 * time.Hour)
1045 m := manager{
1046 cert: &tls.Certificate{
1047 Leaf: &x509.Certificate{
1048 NotBefore: certIss,
1049 NotAfter: now.Add(-1 * time.Hour),
1050 },
1051 },
1052 certStore: &fakeStore{cert: expiredStoreCertData.certificate},
1053 getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} },
1054 clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) {
1055 return newClientset(fakeClient{
1056 certificatePEM: apiServerCertData.certificatePEM,
1057 }), nil
1058 },
1059 certificateRotation: &h,
1060 now: func() time.Time { return now },
1061 logf: t.Logf,
1062 }
1063 ok, err := m.rotateCerts()
1064 if err != nil || !ok {
1065 t.Errorf("failed to rotate certs: %v", err)
1066 }
1067 if h.calls != 1 {
1068 t.Errorf("rotation metric was not called")
1069 }
1070 if h.lastValue != now.Sub(certIss).Seconds() {
1071 t.Errorf("rotation metric did not record the right value got: %f; want %f", h.lastValue, now.Sub(certIss).Seconds())
1072 }
1073
1074 }
1075
1076 type fakeClientFailureType int
1077
1078 const (
1079 none fakeClientFailureType = iota
1080 createError
1081 watchError
1082 certificateSigningRequestDenied
1083 )
1084
1085 type fakeClient struct {
1086 noV1 bool
1087 noV1beta1 bool
1088 certificatesclient.CertificateSigningRequestInterface
1089 failureType fakeClientFailureType
1090 certificatePEM []byte
1091 err error
1092 }
1093
1094 func newClientset(opts fakeClient) *fake.Clientset {
1095 f := fake.NewSimpleClientset()
1096 switch opts.failureType {
1097 case createError:
1098 f.PrependReactor("create", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
1099 if opts.err != nil {
1100 return true, nil, opts.err
1101 }
1102 return true, nil, fmt.Errorf("create error")
1103 })
1104 case watchError:
1105 f.PrependReactor("list", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
1106 if opts.err != nil {
1107 return true, nil, opts.err
1108 }
1109 return true, nil, fmt.Errorf("watch error")
1110 })
1111 f.PrependWatchReactor("certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
1112 if opts.err != nil {
1113 return true, nil, opts.err
1114 }
1115 return true, nil, fmt.Errorf("watch error")
1116 })
1117 default:
1118 f.PrependReactor("create", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
1119 switch action.GetResource().Version {
1120 case "v1":
1121 if opts.noV1 {
1122 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
1123 }
1124 return true, &certificatesv1.CertificateSigningRequest{ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}}, nil
1125 case "v1beta1":
1126 if opts.noV1beta1 {
1127 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
1128 }
1129 return true, &certificatesv1beta1.CertificateSigningRequest{ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}}, nil
1130 default:
1131 return false, nil, nil
1132 }
1133 })
1134 f.PrependReactor("list", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) {
1135 switch action.GetResource().Version {
1136 case "v1":
1137 if opts.noV1 {
1138 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
1139 }
1140 return true, &certificatesv1.CertificateSigningRequestList{Items: []certificatesv1.CertificateSigningRequest{{ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}}}}, nil
1141 case "v1beta1":
1142 if opts.noV1beta1 {
1143 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
1144 }
1145 return true, &certificatesv1beta1.CertificateSigningRequestList{Items: []certificatesv1beta1.CertificateSigningRequest{{ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}}}}, nil
1146 default:
1147 return false, nil, nil
1148 }
1149 })
1150 f.PrependWatchReactor("certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) {
1151 switch action.GetResource().Version {
1152 case "v1":
1153 if opts.noV1 {
1154 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
1155 }
1156 return true, &fakeWatch{
1157 version: action.GetResource().Version,
1158 failureType: opts.failureType,
1159 certificatePEM: opts.certificatePEM,
1160 }, nil
1161
1162 case "v1beta1":
1163 if opts.noV1beta1 {
1164 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "")
1165 }
1166 return true, &fakeWatch{
1167 version: action.GetResource().Version,
1168 failureType: opts.failureType,
1169 certificatePEM: opts.certificatePEM,
1170 }, nil
1171 default:
1172 return false, nil, nil
1173 }
1174 })
1175 }
1176 return f
1177 }
1178
1179 type fakeWatch struct {
1180 version string
1181 failureType fakeClientFailureType
1182 certificatePEM []byte
1183 }
1184
1185 func (w *fakeWatch) Stop() {
1186 }
1187
1188 func (w *fakeWatch) ResultChan() <-chan watch.Event {
1189 var csr runtime.Object
1190
1191 switch w.version {
1192 case "v1":
1193 var condition certificatesv1.CertificateSigningRequestCondition
1194 if w.failureType == certificateSigningRequestDenied {
1195 condition = certificatesv1.CertificateSigningRequestCondition{
1196 Type: certificatesv1.CertificateDenied,
1197 }
1198 } else {
1199 condition = certificatesv1.CertificateSigningRequestCondition{
1200 Type: certificatesv1.CertificateApproved,
1201 }
1202 }
1203
1204 csr = &certificatesv1.CertificateSigningRequest{
1205 ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"},
1206 Status: certificatesv1.CertificateSigningRequestStatus{
1207 Conditions: []certificatesv1.CertificateSigningRequestCondition{
1208 condition,
1209 },
1210 Certificate: []byte(w.certificatePEM),
1211 },
1212 }
1213
1214 case "v1beta1":
1215 var condition certificatesv1beta1.CertificateSigningRequestCondition
1216 if w.failureType == certificateSigningRequestDenied {
1217 condition = certificatesv1beta1.CertificateSigningRequestCondition{
1218 Type: certificatesv1beta1.CertificateDenied,
1219 }
1220 } else {
1221 condition = certificatesv1beta1.CertificateSigningRequestCondition{
1222 Type: certificatesv1beta1.CertificateApproved,
1223 }
1224 }
1225
1226 csr = &certificatesv1beta1.CertificateSigningRequest{
1227 ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"},
1228 Status: certificatesv1beta1.CertificateSigningRequestStatus{
1229 Conditions: []certificatesv1beta1.CertificateSigningRequestCondition{
1230 condition,
1231 },
1232 Certificate: []byte(w.certificatePEM),
1233 },
1234 }
1235 }
1236
1237 c := make(chan watch.Event, 1)
1238 c <- watch.Event{
1239 Type: watch.Added,
1240 Object: csr,
1241 }
1242 return c
1243 }
1244
1245 type fakeStore struct {
1246 cert *tls.Certificate
1247 }
1248
1249 func (s *fakeStore) Current() (*tls.Certificate, error) {
1250 if s.cert == nil {
1251 noKeyErr := NoCertKeyError("")
1252 return nil, &noKeyErr
1253 }
1254 return s.cert, nil
1255 }
1256
1257
1258
1259
1260 func (s *fakeStore) Update(certPEM, keyPEM []byte) (*tls.Certificate, error) {
1261
1262
1263
1264
1265
1266
1267
1268
1269 for _, tc := range []*certificateData{storeCertData, bootstrapCertData, apiServerCertData} {
1270 if bytes.Equal(tc.certificatePEM, certPEM) {
1271 keyPEM = tc.keyPEM
1272 }
1273 }
1274 cert, err := tls.X509KeyPair(certPEM, keyPEM)
1275 if err != nil {
1276 return nil, err
1277 }
1278 now := time.Now()
1279 s.cert = &cert
1280 s.cert.Leaf = &x509.Certificate{
1281 NotBefore: now.Add(-24 * time.Hour),
1282 NotAfter: now.Add(24 * time.Hour),
1283 }
1284 return s.cert, nil
1285 }
1286
1287 func certificatesEqual(c1 *tls.Certificate, c2 *tls.Certificate) bool {
1288 if c1 == nil || c2 == nil {
1289 return c1 == c2
1290 }
1291 if len(c1.Certificate) != len(c2.Certificate) {
1292 return false
1293 }
1294 for i := 0; i < len(c1.Certificate); i++ {
1295 if !bytes.Equal(c1.Certificate[i], c2.Certificate[i]) {
1296 return false
1297 }
1298 }
1299 return true
1300 }
1301
1302 func certificateString(c *tls.Certificate) string {
1303 if c == nil {
1304 return "certificate == nil"
1305 }
1306 if c.Leaf == nil {
1307 return "certificate.Leaf == nil"
1308 }
1309 return c.Leaf.Subject.CommonName
1310 }
1311
View as plain text