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 "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 "k8s.io/apimachinery/pkg/api/errors" 33 apierrors "k8s.io/apimachinery/pkg/api/errors" 34 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 35 v1 "k8s.io/apimachinery/pkg/apis/meta/v1" 36 "k8s.io/apimachinery/pkg/runtime" 37 "k8s.io/apimachinery/pkg/runtime/schema" 38 watch "k8s.io/apimachinery/pkg/watch" 39 clientset "k8s.io/client-go/kubernetes" 40 "k8s.io/client-go/kubernetes/fake" 41 certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" 42 clienttesting "k8s.io/client-go/testing" 43) 44 45var storeCertData = newCertificateData(`-----BEGIN CERTIFICATE----- 46MIICRzCCAfGgAwIBAgIJALMb7ecMIk3MMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV 47BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE 48CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD 49VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwIBcNMTcwNDI2MjMyNjUyWhgPMjExNzA0 50MDIyMzI2NTJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV 51BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J 52VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwXDANBgkq 53hkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTCPGO/LEsguKqWHBtKzweMY2CV 54tAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5MzP2H5QIDAQABo1AwTjAdBgNV 55HQ4EFgQU22iy8aWkNSxv0nBxFxerfsvnZVMwHwYDVR0jBBgwFoAU22iy8aWkNSxv 560nBxFxerfsvnZVMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAEOefGbV 57NcHxklaW06w6OBYJPwpIhCVozC1qdxGX1dg8VkEKzjOzjgqVD30m59OFmSlBmHsl 58nkVA6wyOSDYBf3o= 59-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 60MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAtBMa7NWpv3BVlKTC 61PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M 62zP2H5QIDAQABAkAS9BfXab3OKpK3bIgNNyp+DQJKrZnTJ4Q+OjsqkpXvNltPJosf 63G8GsiKu/vAt4HGqI3eU77NvRI+mL4MnHRmXBAiEA3qM4FAtKSRBbcJzPxxLEUSwg 64XSCcosCktbkXvpYrS30CIQDPDxgqlwDEJQ0uKuHkZI38/SPWWqfUmkecwlbpXABK 65iQIgZX08DA8VfvcA5/Xj1Zjdey9FVY6POLXen6RPiabE97UCICp6eUW7ht+2jjar 66e35EltCRCjoejRHTuN9TC0uCoVipAiAXaJIx/Q47vGwiw6Y8KXsNU6y54gTbOSxX 6754LzHNk/+Q== 68-----END RSA PRIVATE KEY-----`) 69var storeTwoCertsData = newCertificateData(`-----BEGIN CERTIFICATE----- 70MIIDfTCCAyegAwIBAgIUFBl4gUoqZDP/wUJDn37/VJ9upD0wDQYJKoZIhvcNAQEF 71BQAwfjELMAkGA1UEBhMCR0IxDzANBgNVBAgMBkxvbmRvbjEPMA0GA1UEBwwGTG9u 72ZG9uMRgwFgYDVQQKDA9HbG9iYWwgU2VjdXJpdHkxFjAUBgNVBAsMDUlUIERlcGFy 73dG1lbnQxGzAZBgNVBAMMEnRlc3QtY2VydGlmaWNhdGUtMDAeFw0yMDAzMDIxOTM3 74MDBaFw0yMTAzMDIxOTM3MDBaMIGIMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2Fs 75aWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEdMBsGA1UEChMURXhhbXBs 76ZSBDb21wYW55LCBMTEMxEzARBgNVBAsTCk9wZXJhdGlvbnMxGDAWBgNVBAMTD3d3 77dy5leGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMiR 78DNpmwTICFr+P16fKDVjbNCzSjWq+MTu8vAfS6GrLpBTUEe+6zVqxUza/fZenxo8O 79ucV2JTUv5J4nkT/vG6Qm/mToVJ4vQzLQ5jR2w7v/7cf3oWCwTAKUafgo6/Ga95gn 80lQB3+Fd8sy96zfFr/7wDSMPPueR5kSFax+cEd30wwv5O7tWj0ro1mrxLssBlwPaR 81ZlzkkvxBYTzWCqKZsWktQlXciqlFSos0ua7uvwqKN5CTxfC/xoyMxx9kfZm7BzPN 82ZDqYMFw2HiWdEiLzI4jj+Gh0D5t47tnvlpUMihcX9x0jP6/+hnfcQ8GAP2jR/BXY 835YZRRY70LiCXPevlRAECAwEAAaOBqTCBpjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0l 84BBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYE 85FOoiE+kh7gGDpyx0KZuCc1lrlTRKMB8GA1UdIwQYMBaAFNtosvGlpDUsb9JwcRcX 86q37L52VTMCcGA1UdEQQgMB6CC2V4YW1wbGUuY29tgg93d3cuZXhhbXBsZS5jb20w 87DQYJKoZIhvcNAQEFBQADQQAw6mxQONAD2sivfzIf1eDFd6LU7aE+MnkdlEQjjPCi 88tlUITFIuO3XavISupP6V9wE0b1wTF1pTlVWArf/0YQXs 89-----END CERTIFICATE----- 90-----BEGIN CERTIFICATE----- 91MIICRzCCAfGgAwIBAgIJALMb7ecMIk3MMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV 92BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE 93CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD 94VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwIBcNMTcwNDI2MjMyNjUyWhgPMjExNzA0 95MDIyMzI2NTJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV 96BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J 97VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTAwXDANBgkq 98hkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTCPGO/LEsguKqWHBtKzweMY2CV 99tAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5MzP2H5QIDAQABo1AwTjAdBgNV 100HQ4EFgQU22iy8aWkNSxv0nBxFxerfsvnZVMwHwYDVR0jBBgwFoAU22iy8aWkNSxv 1010nBxFxerfsvnZVMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAEOefGbV 102NcHxklaW06w6OBYJPwpIhCVozC1qdxGX1dg8VkEKzjOzjgqVD30m59OFmSlBmHsl 103nkVA6wyOSDYBf3o= 104-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 105MIIEowIBAAKCAQEAyJEM2mbBMgIWv4/Xp8oNWNs0LNKNar4xO7y8B9LoasukFNQR 10677rNWrFTNr99l6fGjw65xXYlNS/knieRP+8bpCb+ZOhUni9DMtDmNHbDu//tx/eh 107YLBMApRp+Cjr8Zr3mCeVAHf4V3yzL3rN8Wv/vANIw8+55HmRIVrH5wR3fTDC/k7u 1081aPSujWavEuywGXA9pFmXOSS/EFhPNYKopmxaS1CVdyKqUVKizS5ru6/Coo3kJPF 1098L/GjIzHH2R9mbsHM81kOpgwXDYeJZ0SIvMjiOP4aHQPm3ju2e+WlQyKFxf3HSM/ 110r/6Gd9xDwYA/aNH8FdjlhlFFjvQuIJc96+VEAQIDAQABAoIBAQCc6R3tH8a1oPy7 111EYXeNy0J/zRqfK82e2V5HsbcOByssHTF9sOxkatm8KPxiQ5wv0mQUiz0VuH1Imrx 112cHMqWZ5+ZiNQPpM0zjT8ZII1OVUYl7knYIxYYJSW0BW3mAw/EMXzu8POgg1AJMbq 113tmC4J44DQW6EAtej75ejSKpsCgqRXVoi3iEk9eMLHUFIHqkzl/aKEc7k/P+eKo2h 114PHsDoKZdmOmZA3OKzw61xAqJICYyplRHatQcEiWJgnLer+9qvUGc4k8eqAYeDGm7 115T78XcUvsXOug2GClVWGZu1quFhf7MxjzFfOjz4q9HwPex7X6nQL0IX2hzMECkaMC 116iUMZGGEhAoGBAOLY1KSNOjvt54MkKznI8stHkx8V73c0Nxbz5Rj8gM0Gwk1FWVas 117jgoAbKPQ2UL/RglLX1JZvztKvNuWSEeZGqggDvhzB38leiEH+OY7DZ7a0c5sWwdF 118CpcT1mJb91ww5xEC09WO8Oq3i5olVBBivOl5EjwKHOQn2TUh2OSLhqf/AoGBAOJX 119mxqdTEUwFU9ecsAOK9labjI7mA5so0vIq8eq1Q670NFszChfSMKJAqQ90N1LEu9z 120L0f6CBXYCn7sMmOlF4CKE+u2/ieJfD1OkKq7RwEd3pi4X3xtAlcPK8F/QprmQWo0 121wi33BDBb4zYkuQB6Q5RYIV2di7k+HBpoQPottBP/AoGAIB4xJUc1qoyJjeDOGfVg 122ovV0WB9j8026Sw6nLj16Aw1k70nVV1dBGRtsRllomXrJMMGyMleworV3PePuQezk 123gE9hrz2iHxdwTkLxs69Cw24Z7I8c6E+XK0LMxMpeoHfwD1GGKqN9as4n/uAwIc3J 124D4lr0oJgCtG1iDdNnTZAD4MCgYAkOpWPCwJ8SJgAnkOLzjjij4D39WX/WRBCPxqP 1252R5FP3bLLrj29Vl2GewcUfCumyeqwCsfQDwvEueLLU9bd79tSayqnB3OQklqnrq1 126OUjCOv+4Pjq6ddBcEweT70S/+n8Z+tvh85nuC6cwsWwTUX6jrf+ZNnB49CIXb/yG 127ju42DQKBgAPtbB/ON3+GtnSTHBSY6HwZvGJrBDicrXmr1U9zuA8yYxv8qaRXZkpn 1282cpLLvO2MJutwXMYf+T3x1ZCFMkE56pOswSTGrCQWRl3hOiJayLHQyAOYHPnYeZB 12978iRJPUZ0biEQUZQ62GBxWkcB0qkxa9m759h/TvLwvV0RrO5Uzd0 130-----END RSA PRIVATE KEY-----`) 131var expiredStoreCertData = newCertificateData(`-----BEGIN CERTIFICATE----- 132MIIBFzCBwgIJALhygXnxXmN1MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCGhv 133c3QtMTIzMB4XDTE4MTEwNDIzNTc1NFoXDTE4MTEwNTIzNTc1NFowEzERMA8GA1UE 134AwwIaG9zdC0xMjMwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAtBMa7NWpv3BVlKTC 135PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M 136zP2H5QIDAQABMA0GCSqGSIb3DQEBCwUAA0EAN2DPFUtCzqnidL+5nh+46Sk6dkMI 137T5DD11UuuIjZusKvThsHKVCIsyJ2bDo7cTbI+/nklLRP+FcC2wESFUgXbA== 138-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 139MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAtBMa7NWpv3BVlKTC 140PGO/LEsguKqWHBtKzweMY2CVtAL1rQm913huhxF9w+ai76KQ3MHK5IVnLJjYYA5M 141zP2H5QIDAQABAkAS9BfXab3OKpK3bIgNNyp+DQJKrZnTJ4Q+OjsqkpXvNltPJosf 142G8GsiKu/vAt4HGqI3eU77NvRI+mL4MnHRmXBAiEA3qM4FAtKSRBbcJzPxxLEUSwg 143XSCcosCktbkXvpYrS30CIQDPDxgqlwDEJQ0uKuHkZI38/SPWWqfUmkecwlbpXABK 144iQIgZX08DA8VfvcA5/Xj1Zjdey9FVY6POLXen6RPiabE97UCICp6eUW7ht+2jjar 145e35EltCRCjoejRHTuN9TC0uCoVipAiAXaJIx/Q47vGwiw6Y8KXsNU6y54gTbOSxX 14654LzHNk/+Q== 147-----END RSA PRIVATE KEY-----`) 148var bootstrapCertData = newCertificateData( 149 `-----BEGIN CERTIFICATE----- 150MIICRzCCAfGgAwIBAgIJANXr+UzRFq4TMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV 151BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE 152CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD 153VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTEwIBcNMTcwNDI2MjMyNzMyWhgPMjExNzA0 154MDIyMzI3MzJaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV 155BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J 156VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTEwXDANBgkq 157hkiG9w0BAQEFAANLADBIAkEAqvbkN4RShH1rL37JFp4fZPnn0JUhVWWsrP8NOomJ 158pXdBDUMGWuEQIsZ1Gf9JrCQLu6ooRyHSKRFpAVbMQ3ABJwIDAQABo1AwTjAdBgNV 159HQ4EFgQUEGBc6YYheEZ/5MhwqSUYYPYRj2MwHwYDVR0jBBgwFoAUEGBc6YYheEZ/ 1605MhwqSUYYPYRj2MwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBAIyNmznk 1615dgJY52FppEEcfQRdS5k4XFPc22SHPcz77AHf5oWZ1WG9VezOZZPp8NCiFDDlDL8 162yma33a5eMyTjLD8= 163-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 164MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqvbkN4RShH1rL37J 165Fp4fZPnn0JUhVWWsrP8NOomJpXdBDUMGWuEQIsZ1Gf9JrCQLu6ooRyHSKRFpAVbM 166Q3ABJwIDAQABAkBC2OBpGLMPHN8BJijIUDFkURakBvuOoX+/8MYiYk7QxEmfLCk6 167L6r+GLNFMfXwXcBmXtMKfZKAIKutKf098JaBAiEA10azfqt3G/5owrNA00plSyT6 168ZmHPzY9Uq1p/QTR/uOcCIQDLTkfBkLHm0UKeobbO/fSm6ZflhyBRDINy4FvwmZMt 169wQIgYV/tmQJeIh91q3wBepFQOClFykG8CTMoDUol/YyNqUkCIHfp6Rr7fGL3JIMq 170QQgf9DCK8SPZqq8DYXjdan0kKBJBAiEAyDb+07o2gpggo8BYUKSaiRCiyXfaq87f 171eVqgpBq/QN4= 172-----END RSA PRIVATE KEY-----`) 173var apiServerCertData = newCertificateData( 174 `-----BEGIN CERTIFICATE----- 175MIICRzCCAfGgAwIBAgIJAIydTIADd+yqMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV 176BAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNVBAcMBkxvbmRvbjEYMBYGA1UE 177CgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1JVCBEZXBhcnRtZW50MRswGQYD 178VQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTIwIBcNMTcwNDI2MjMyNDU4WhgPMjExNzA0 179MDIyMzI0NThaMH4xCzAJBgNVBAYTAkdCMQ8wDQYDVQQIDAZMb25kb24xDzANBgNV 180BAcMBkxvbmRvbjEYMBYGA1UECgwPR2xvYmFsIFNlY3VyaXR5MRYwFAYDVQQLDA1J 181VCBEZXBhcnRtZW50MRswGQYDVQQDDBJ0ZXN0LWNlcnRpZmljYXRlLTIwXDANBgkq 182hkiG9w0BAQEFAANLADBIAkEAuiRet28DV68Dk4A8eqCaqgXmymamUEjW/DxvIQqH 1833lbhtm8BwSnS9wUAajSLSWiq3fci2RbRgaSPjUrnbOHCLQIDAQABo1AwTjAdBgNV 184HQ4EFgQU0vhI4OPGEOqT+VAWwxdhVvcmgdIwHwYDVR0jBBgwFoAU0vhI4OPGEOqT 185+VAWwxdhVvcmgdIwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAANBALNeJGDe 186nV5cXbp9W1bC12Tc8nnNXn4ypLE2JTQAvyp51zoZ8hQoSnRVx/VCY55Yu+br8gQZ 187+tW+O/PoE7B3tuY= 188-----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 189MIIBVgIBADANBgkqhkiG9w0BAQEFAASCAUAwggE8AgEAAkEAuiRet28DV68Dk4A8 190eqCaqgXmymamUEjW/DxvIQqH3lbhtm8BwSnS9wUAajSLSWiq3fci2RbRgaSPjUrn 191bOHCLQIDAQABAkEArDR1g9IqD3aUImNikDgAngbzqpAokOGyMoxeavzpEaFOgCzi 192gi7HF7yHRmZkUt8CzdEvnHSqRjFuaaB0gGA+AQIhAOc8Z1h8ElLRSqaZGgI3jCTp 193Izx9HNY//U5NGrXD2+ttAiEAzhOqkqI4+nDab7FpiD7MXI6fO549mEXeVBPvPtsS 194OcECIQCIfkpOm+ZBBpO3JXaJynoqK4gGI6ALA/ik6LSUiIlfPQIhAISjd9hlfZME 195bDQT1r8Q3Gx+h9LRqQeHgPBQ3F5ylqqBAiBaJ0hkYvrIdWxNlcLqD3065bJpHQ4S 196WQkuZUQN1M/Xvg== 197-----END RSA PRIVATE KEY-----`) 198 199type certificateData struct { 200 keyPEM []byte 201 certificatePEM []byte 202 certificate *tls.Certificate 203} 204 205func newCertificateData(certificatePEM string, keyPEM string) *certificateData { 206 certificate, err := tls.X509KeyPair([]byte(certificatePEM), []byte(keyPEM)) 207 if err != nil { 208 panic(fmt.Sprintf("Unable to initialize certificate: %v", err)) 209 } 210 certs, err := x509.ParseCertificates(certificate.Certificate[0]) 211 if err != nil { 212 panic(fmt.Sprintf("Unable to initialize certificate leaf: %v", err)) 213 } 214 certificate.Leaf = certs[0] 215 return &certificateData{ 216 keyPEM: []byte(keyPEM), 217 certificatePEM: []byte(certificatePEM), 218 certificate: &certificate, 219 } 220} 221 222func TestNewManagerNoRotation(t *testing.T) { 223 store := &fakeStore{ 224 cert: storeCertData.certificate, 225 } 226 if _, err := NewManager(&Config{ 227 Template: &x509.CertificateRequest{}, 228 Usages: []certificatesv1.KeyUsage{}, 229 CertificateStore: store, 230 }); err != nil { 231 t.Fatalf("Failed to initialize the certificate manager: %v", err) 232 } 233} 234 235type metricMock struct { 236 calls int 237 lastValue float64 238} 239 240func (g *metricMock) Set(v float64) { 241 g.calls++ 242 g.lastValue = v 243} 244 245func (g *metricMock) Observe(v float64) { 246 g.calls++ 247 g.lastValue = v 248} 249 250func TestSetRotationDeadline(t *testing.T) { 251 defer func(original func(float64) time.Duration) { jitteryDuration = original }(jitteryDuration) 252 253 now := time.Now() 254 testCases := []struct { 255 name string 256 notBefore time.Time 257 notAfter time.Time 258 shouldRotate bool 259 }{ 260 {"just issued, still good", now.Add(-1 * time.Hour), now.Add(99 * time.Hour), false}, 261 {"half way expired, still good", now.Add(-24 * time.Hour), now.Add(24 * time.Hour), false}, 262 {"mostly expired, still good", now.Add(-69 * time.Hour), now.Add(31 * time.Hour), false}, 263 {"just about expired, should rotate", now.Add(-91 * time.Hour), now.Add(9 * time.Hour), true}, 264 {"nearly expired, should rotate", now.Add(-99 * time.Hour), now.Add(1 * time.Hour), true}, 265 {"already expired, should rotate", now.Add(-10 * time.Hour), now.Add(-1 * time.Hour), true}, 266 {"long duration", now.Add(-6 * 30 * 24 * time.Hour), now.Add(6 * 30 * 24 * time.Hour), true}, 267 {"short duration", now.Add(-30 * time.Second), now.Add(30 * time.Second), true}, 268 } 269 270 for _, tc := range testCases { 271 t.Run(tc.name, func(t *testing.T) { 272 m := manager{ 273 cert: &tls.Certificate{ 274 Leaf: &x509.Certificate{ 275 NotBefore: tc.notBefore, 276 NotAfter: tc.notAfter, 277 }, 278 }, 279 getTemplate: func() *x509.CertificateRequest { return &x509.CertificateRequest{} }, 280 usages: []certificatesv1.KeyUsage{}, 281 now: func() time.Time { return now }, 282 } 283 jitteryDuration = func(float64) time.Duration { return time.Duration(float64(tc.notAfter.Sub(tc.notBefore)) * 0.7) } 284 lowerBound := tc.notBefore.Add(time.Duration(float64(tc.notAfter.Sub(tc.notBefore)) * 0.7)) 285 286 deadline := m.nextRotationDeadline() 287 288 if !deadline.Equal(lowerBound) { 289 t.Errorf("For notBefore %v, notAfter %v, the rotationDeadline %v should be %v.", 290 tc.notBefore, 291 tc.notAfter, 292 deadline, 293 lowerBound) 294 } 295 }) 296 } 297} 298 299func TestCertSatisfiesTemplate(t *testing.T) { 300 testCases := []struct { 301 name string 302 cert *x509.Certificate 303 template *x509.CertificateRequest 304 shouldSatisfy bool 305 }{ 306 { 307 name: "No certificate, no template", 308 cert: nil, 309 template: nil, 310 shouldSatisfy: false, 311 }, 312 { 313 name: "No certificate", 314 cert: nil, 315 template: &x509.CertificateRequest{}, 316 shouldSatisfy: false, 317 }, 318 { 319 name: "No template", 320 cert: &x509.Certificate{ 321 Subject: pkix.Name{ 322 CommonName: "system:node:fake-node-name", 323 }, 324 }, 325 template: nil, 326 shouldSatisfy: true, 327 }, 328 { 329 name: "Mismatched common name", 330 cert: &x509.Certificate{ 331 Subject: pkix.Name{ 332 CommonName: "system:node:fake-node-name-2", 333 }, 334 }, 335 template: &x509.CertificateRequest{ 336 Subject: pkix.Name{ 337 CommonName: "system:node:fake-node-name", 338 }, 339 }, 340 shouldSatisfy: false, 341 }, 342 { 343 name: "Missing orgs in certificate", 344 cert: &x509.Certificate{ 345 Subject: pkix.Name{ 346 Organization: []string{"system:nodes"}, 347 }, 348 }, 349 template: &x509.CertificateRequest{ 350 Subject: pkix.Name{ 351 Organization: []string{"system:nodes", "foobar"}, 352 }, 353 }, 354 shouldSatisfy: false, 355 }, 356 { 357 name: "Extra orgs in certificate", 358 cert: &x509.Certificate{ 359 Subject: pkix.Name{ 360 Organization: []string{"system:nodes", "foobar"}, 361 }, 362 }, 363 template: &x509.CertificateRequest{ 364 Subject: pkix.Name{ 365 Organization: []string{"system:nodes"}, 366 }, 367 }, 368 shouldSatisfy: true, 369 }, 370 { 371 name: "Missing DNS names in certificate", 372 cert: &x509.Certificate{ 373 Subject: pkix.Name{}, 374 DNSNames: []string{"foo.example.com"}, 375 }, 376 template: &x509.CertificateRequest{ 377 Subject: pkix.Name{}, 378 DNSNames: []string{"foo.example.com", "bar.example.com"}, 379 }, 380 shouldSatisfy: false, 381 }, 382 { 383 name: "Extra DNS names in certificate", 384 cert: &x509.Certificate{ 385 Subject: pkix.Name{}, 386 DNSNames: []string{"foo.example.com", "bar.example.com"}, 387 }, 388 template: &x509.CertificateRequest{ 389 Subject: pkix.Name{}, 390 DNSNames: []string{"foo.example.com"}, 391 }, 392 shouldSatisfy: true, 393 }, 394 { 395 name: "Missing IP addresses in certificate", 396 cert: &x509.Certificate{ 397 Subject: pkix.Name{}, 398 IPAddresses: []net.IP{net.ParseIP("192.168.1.1")}, 399 }, 400 template: &x509.CertificateRequest{ 401 Subject: pkix.Name{}, 402 IPAddresses: []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("192.168.1.2")}, 403 }, 404 shouldSatisfy: false, 405 }, 406 { 407 name: "Extra IP addresses in certificate", 408 cert: &x509.Certificate{ 409 Subject: pkix.Name{}, 410 IPAddresses: []net.IP{net.ParseIP("192.168.1.1"), net.ParseIP("192.168.1.2")}, 411 }, 412 template: &x509.CertificateRequest{ 413 Subject: pkix.Name{}, 414 IPAddresses: []net.IP{net.ParseIP("192.168.1.1")}, 415 }, 416 shouldSatisfy: true, 417 }, 418 { 419 name: "Matching certificate", 420 cert: &x509.Certificate{ 421 Subject: pkix.Name{ 422 CommonName: "system:node:fake-node-name", 423 Organization: []string{"system:nodes"}, 424 }, 425 DNSNames: []string{"foo.example.com"}, 426 IPAddresses: []net.IP{net.ParseIP("192.168.1.1")}, 427 }, 428 template: &x509.CertificateRequest{ 429 Subject: pkix.Name{ 430 CommonName: "system:node:fake-node-name", 431 Organization: []string{"system:nodes"}, 432 }, 433 DNSNames: []string{"foo.example.com"}, 434 IPAddresses: []net.IP{net.ParseIP("192.168.1.1")}, 435 }, 436 shouldSatisfy: true, 437 }, 438 } 439 440 for _, tc := range testCases { 441 t.Run(tc.name, func(t *testing.T) { 442 var tlsCert *tls.Certificate 443 444 if tc.cert != nil { 445 tlsCert = &tls.Certificate{ 446 Leaf: tc.cert, 447 } 448 } 449 450 m := manager{ 451 cert: tlsCert, 452 getTemplate: func() *x509.CertificateRequest { return tc.template }, 453 now: time.Now, 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 464func 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 } 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 488func 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 usages: []certificatesv1.KeyUsage{}, 499 clientsetFn: func(_ *tls.Certificate) (clientset.Interface, error) { 500 return newClientset(fakeClient{failureType: watchError}), nil 501 }, 502 now: func() time.Time { return now }, 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 514func 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 541func 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 581func 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 646func 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 789func 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 893func 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: errors.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: errors.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: errors.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: errors.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 1041func 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 } 1062 ok, err := m.rotateCerts() 1063 if err != nil || !ok { 1064 t.Errorf("failed to rotate certs: %v", err) 1065 } 1066 if h.calls != 1 { 1067 t.Errorf("rotation metric was not called") 1068 } 1069 if h.lastValue != now.Sub(certIss).Seconds() { 1070 t.Errorf("rotation metric did not record the right value got: %f; want %f", h.lastValue, now.Sub(certIss).Seconds()) 1071 } 1072 1073} 1074 1075type fakeClientFailureType int 1076 1077const ( 1078 none fakeClientFailureType = iota 1079 createError 1080 watchError 1081 certificateSigningRequestDenied 1082) 1083 1084type fakeClient struct { 1085 noV1 bool 1086 noV1beta1 bool 1087 certificatesclient.CertificateSigningRequestInterface 1088 failureType fakeClientFailureType 1089 certificatePEM []byte 1090 err error 1091} 1092 1093func newClientset(opts fakeClient) *fake.Clientset { 1094 f := fake.NewSimpleClientset() 1095 switch opts.failureType { 1096 case createError: 1097 f.PrependReactor("create", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { 1098 if opts.err != nil { 1099 return true, nil, opts.err 1100 } 1101 return true, nil, fmt.Errorf("create error") 1102 }) 1103 case watchError: 1104 f.PrependReactor("list", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { 1105 if opts.err != nil { 1106 return true, nil, opts.err 1107 } 1108 return true, nil, fmt.Errorf("watch error") 1109 }) 1110 f.PrependWatchReactor("certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) { 1111 if opts.err != nil { 1112 return true, nil, opts.err 1113 } 1114 return true, nil, fmt.Errorf("watch error") 1115 }) 1116 default: 1117 f.PrependReactor("create", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { 1118 switch action.GetResource().Version { 1119 case "v1": 1120 if opts.noV1 { 1121 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "") 1122 } 1123 return true, &certificatesv1.CertificateSigningRequest{ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}}, nil 1124 case "v1beta1": 1125 if opts.noV1beta1 { 1126 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "") 1127 } 1128 return true, &certificatesv1beta1.CertificateSigningRequest{ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}}, nil 1129 default: 1130 return false, nil, nil 1131 } 1132 }) 1133 f.PrependReactor("list", "certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { 1134 switch action.GetResource().Version { 1135 case "v1": 1136 if opts.noV1 { 1137 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "") 1138 } 1139 return true, &certificatesv1.CertificateSigningRequestList{Items: []certificatesv1.CertificateSigningRequest{{ObjectMeta: v1.ObjectMeta{UID: "fake-uid"}}}}, nil 1140 case "v1beta1": 1141 if opts.noV1beta1 { 1142 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "") 1143 } 1144 return true, &certificatesv1beta1.CertificateSigningRequestList{Items: []certificatesv1beta1.CertificateSigningRequest{{ObjectMeta: v1.ObjectMeta{UID: "fake-uid"}}}}, nil 1145 default: 1146 return false, nil, nil 1147 } 1148 }) 1149 f.PrependWatchReactor("certificatesigningrequests", func(action clienttesting.Action) (handled bool, ret watch.Interface, err error) { 1150 switch action.GetResource().Version { 1151 case "v1": 1152 if opts.noV1 { 1153 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "") 1154 } 1155 return true, &fakeWatch{ 1156 version: action.GetResource().Version, 1157 failureType: opts.failureType, 1158 certificatePEM: opts.certificatePEM, 1159 }, nil 1160 1161 case "v1beta1": 1162 if opts.noV1beta1 { 1163 return true, nil, apierrors.NewNotFound(certificatesv1.Resource("certificatesigningrequests"), "") 1164 } 1165 return true, &fakeWatch{ 1166 version: action.GetResource().Version, 1167 failureType: opts.failureType, 1168 certificatePEM: opts.certificatePEM, 1169 }, nil 1170 default: 1171 return false, nil, nil 1172 } 1173 }) 1174 } 1175 return f 1176} 1177 1178type fakeWatch struct { 1179 version string 1180 failureType fakeClientFailureType 1181 certificatePEM []byte 1182} 1183 1184func (w *fakeWatch) Stop() { 1185} 1186 1187func (w *fakeWatch) ResultChan() <-chan watch.Event { 1188 var csr runtime.Object 1189 1190 switch w.version { 1191 case "v1": 1192 var condition certificatesv1.CertificateSigningRequestCondition 1193 if w.failureType == certificateSigningRequestDenied { 1194 condition = certificatesv1.CertificateSigningRequestCondition{ 1195 Type: certificatesv1.CertificateDenied, 1196 } 1197 } else { 1198 condition = certificatesv1.CertificateSigningRequestCondition{ 1199 Type: certificatesv1.CertificateApproved, 1200 } 1201 } 1202 1203 csr = &certificatesv1.CertificateSigningRequest{ 1204 ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}, 1205 Status: certificatesv1.CertificateSigningRequestStatus{ 1206 Conditions: []certificatesv1.CertificateSigningRequestCondition{ 1207 condition, 1208 }, 1209 Certificate: []byte(w.certificatePEM), 1210 }, 1211 } 1212 1213 case "v1beta1": 1214 var condition certificatesv1beta1.CertificateSigningRequestCondition 1215 if w.failureType == certificateSigningRequestDenied { 1216 condition = certificatesv1beta1.CertificateSigningRequestCondition{ 1217 Type: certificatesv1beta1.CertificateDenied, 1218 } 1219 } else { 1220 condition = certificatesv1beta1.CertificateSigningRequestCondition{ 1221 Type: certificatesv1beta1.CertificateApproved, 1222 } 1223 } 1224 1225 csr = &certificatesv1beta1.CertificateSigningRequest{ 1226 ObjectMeta: metav1.ObjectMeta{UID: "fake-uid"}, 1227 Status: certificatesv1beta1.CertificateSigningRequestStatus{ 1228 Conditions: []certificatesv1beta1.CertificateSigningRequestCondition{ 1229 condition, 1230 }, 1231 Certificate: []byte(w.certificatePEM), 1232 }, 1233 } 1234 } 1235 1236 c := make(chan watch.Event, 1) 1237 c <- watch.Event{ 1238 Type: watch.Added, 1239 Object: csr, 1240 } 1241 return c 1242} 1243 1244type fakeStore struct { 1245 cert *tls.Certificate 1246} 1247 1248func (s *fakeStore) Current() (*tls.Certificate, error) { 1249 if s.cert == nil { 1250 noKeyErr := NoCertKeyError("") 1251 return nil, &noKeyErr 1252 } 1253 return s.cert, nil 1254} 1255 1256// Accepts the PEM data for the cert/key pair and makes the new cert/key 1257// pair the 'current' pair, that will be returned by future calls to 1258// Current(). 1259func (s *fakeStore) Update(certPEM, keyPEM []byte) (*tls.Certificate, error) { 1260 // In order to make the mocking work, whenever a cert/key pair is passed in 1261 // to be updated in the mock store, assume that the certificate manager 1262 // generated the key, and then asked the mock CertificateSigningRequest API 1263 // to sign it, then the faked API returned a canned response. The canned 1264 // signing response will not match the generated key. In order to make 1265 // things work out, search here for the correct matching key and use that 1266 // instead of the passed in key. That way this file of test code doesn't 1267 // have to implement an actual certificate signing process. 1268 for _, tc := range []*certificateData{storeCertData, bootstrapCertData, apiServerCertData} { 1269 if bytes.Equal(tc.certificatePEM, certPEM) { 1270 keyPEM = tc.keyPEM 1271 } 1272 } 1273 cert, err := tls.X509KeyPair(certPEM, keyPEM) 1274 if err != nil { 1275 return nil, err 1276 } 1277 now := time.Now() 1278 s.cert = &cert 1279 s.cert.Leaf = &x509.Certificate{ 1280 NotBefore: now.Add(-24 * time.Hour), 1281 NotAfter: now.Add(24 * time.Hour), 1282 } 1283 return s.cert, nil 1284} 1285 1286func certificatesEqual(c1 *tls.Certificate, c2 *tls.Certificate) bool { 1287 if c1 == nil || c2 == nil { 1288 return c1 == c2 1289 } 1290 if len(c1.Certificate) != len(c2.Certificate) { 1291 return false 1292 } 1293 for i := 0; i < len(c1.Certificate); i++ { 1294 if !bytes.Equal(c1.Certificate[i], c2.Certificate[i]) { 1295 return false 1296 } 1297 } 1298 return true 1299} 1300 1301func certificateString(c *tls.Certificate) string { 1302 if c == nil { 1303 return "certificate == nil" 1304 } 1305 if c.Leaf == nil { 1306 return "certificate.Leaf == nil" 1307 } 1308 return c.Leaf.Subject.CommonName 1309} 1310