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