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