k8s.io/kubernetes@v1.29.3/pkg/kubelet/certificate/transport_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 "context" 21 "crypto/tls" 22 "crypto/x509" 23 "fmt" 24 "math/big" 25 "net/http" 26 "net/http/httptest" 27 "sync/atomic" 28 "testing" 29 "time" 30 31 "k8s.io/apimachinery/pkg/runtime" 32 "k8s.io/apimachinery/pkg/runtime/serializer" 33 "k8s.io/apimachinery/pkg/util/wait" 34 certificatesclient "k8s.io/client-go/kubernetes/typed/certificates/v1beta1" 35 "k8s.io/client-go/rest" 36 ) 37 38 var ( 39 client1CertData = newCertificateData(`-----BEGIN CERTIFICATE----- 40 MIICBDCCAW2gAwIBAgIJAPgVBh+4xbGoMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV 41 BAMMEHdlYmhvb2tfdGVzdHNfY2EwIBcNMTcwNzI4MjMxNTI4WhgPMjI5MTA1MTMy 42 MzE1MjhaMB8xHTAbBgNVBAMMFHdlYmhvb2tfdGVzdHNfY2xpZW50MIGfMA0GCSqG 43 SIb3DQEBAQUAA4GNADCBiQKBgQDkGXXSm6Yun5o3Jlmx45rItcQ2pmnoDk4eZfl0 44 rmPa674s2pfYo3KywkXQ1Fp3BC8GUgzPLSfJ8xXya9Lg1Wo8sHrDln0iRg5HXxGu 45 uFNhRBvj2S0sIff0ZG/IatB9I6WXVOUYuQj6+A0CdULNj1vBqH9+7uWbLZ6lrD4b 46 a44x/wIDAQABo0owSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAU 47 BggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B 48 AQsFAAOBgQCpN27uh/LjUVCaBK7Noko25iih/JSSoWzlvc8CaipvSPofNWyGx3Vu 49 OdcSwNGYX/pp4ZoAzFij/Y5u0vKTVLkWXATeTMVmlPvhmpYjj9gPkCSY6j/SiKlY 50 kGy0xr+0M5UQkMBcfIh9oAp9um1fZHVWAJAGP/ikZgkcUey0LmBn8w== 51 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 52 MIICWwIBAAKBgQDkGXXSm6Yun5o3Jlmx45rItcQ2pmnoDk4eZfl0rmPa674s2pfY 53 o3KywkXQ1Fp3BC8GUgzPLSfJ8xXya9Lg1Wo8sHrDln0iRg5HXxGuuFNhRBvj2S0s 54 Iff0ZG/IatB9I6WXVOUYuQj6+A0CdULNj1vBqH9+7uWbLZ6lrD4ba44x/wIDAQAB 55 AoGAZbWwowvCq1GBq4vPPRI3h739Uz0bRl1ymf1woYXNguXRtCB4yyH+2BTmmrrF 56 6AIWkePuUEdbUaKyK5nGu3iOWM+/i6NP3kopQANtbAYJ2ray3kwvFlhqyn1bxX4n 57 gl/Cbdw1If4zrDrB66y8mYDsjzK7n/gFaDNcY4GArjvOXKkCQQD9Lgv+WD73y4RP 58 yS+cRarlEeLLWVsX/pg2oEBLM50jsdUnrLSW071MjBgP37oOXzqynF9SoDbP2Y5C 59 x+aGux9LAkEA5qPlQPv0cv8Wc3qTI+LixZ/86PPHKWnOnwaHm3b9vQjZAkuVQg3n 60 Wgg9YDmPM87t3UFH7ZbDihUreUxwr9ZjnQJAZ9Z95shMsxbOYmbSVxafu6m1Sc+R 61 M+sghK7/D5jQpzYlhUspGf8n0YBX0hLhXUmjamQGGH5LXL4Owcb4/mM6twJAEVio 62 SF/qva9jv+GrKVrKFXT374lOJFY53Qn/rvifEtWUhLCslCA5kzLlctRBafMZPrfH 63 Mh5RrJP1BhVysDbenQJASGcc+DiF7rB6K++ZGyC11E2AP29DcZ0pgPESSV7npOGg 64 +NqPRZNVCSZOiVmNuejZqmwKhZNGZnBFx1Y+ChAAgw== 65 -----END RSA PRIVATE KEY-----`) 66 client2CertData = newCertificateData(`-----BEGIN CERTIFICATE----- 67 MIICBDCCAW2gAwIBAgIJAPgVBh+4xbGnMA0GCSqGSIb3DQEBCwUAMBsxGTAXBgNV 68 BAMMEHdlYmhvb2tfdGVzdHNfY2EwIBcNMTcwNzI4MjMxNTI4WhgPMjI5MTA1MTMy 69 MzE1MjhaMB8xHTAbBgNVBAMMFHdlYmhvb2tfdGVzdHNfY2xpZW50MIGfMA0GCSqG 70 SIb3DQEBAQUAA4GNADCBiQKBgQDQQLzbrmHbtlxE7wViaoXFp5tQx7zzM2Ed7O1E 71 gs3JUws5KkPbNrejLwixvLkzzU152M43UGsyKDn7HPyjXDogTZSW6C257XpYodk3 72 S/gZS9oZtPss4UJuJioQk/M8X1ZjYP8kCTArOvVRJeNQL8GM7h5QQ6J5LUq+IdZb 73 T0retQIDAQABo0owSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAdBgNVHSUEFjAU 74 BggrBgEFBQcDAgYIKwYBBQUHAwEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0B 75 AQsFAAOBgQBdAxoU5YAmp0d+5b4qg/xOGC5rKcnksQEXYoGwFBWwaKvh9oUlGGxI 76 A5Ykf2TEl24br4tLmicpdxUX4H4PbkdPxOjM9ghIKlmgHo8vBRC0iVIwYgQsw1W8 77 ETY34Or+PJqaeslqx/t7kUKY5UIF9DLVolsIiAHveJNR2uBWiP0KiQ== 78 -----END CERTIFICATE-----`, `-----BEGIN RSA PRIVATE KEY----- 79 MIICXQIBAAKBgQDQQLzbrmHbtlxE7wViaoXFp5tQx7zzM2Ed7O1Egs3JUws5KkPb 80 NrejLwixvLkzzU152M43UGsyKDn7HPyjXDogTZSW6C257XpYodk3S/gZS9oZtPss 81 4UJuJioQk/M8X1ZjYP8kCTArOvVRJeNQL8GM7h5QQ6J5LUq+IdZbT0retQIDAQAB 82 AoGBAMFjTL4IKvG4X+jXub1RxFXvNkkGos2Jaec7TH5xpZ4OUv7L4+We41tTYxSC 83 d83GGetLzPwK3vDd8DHkEiu1incket78rwmQ89LnQNyM0B5ejaTjW2zHcvKJ0Mtn 84 nM32juQfq8St9JZVweS87k8RkLt9cOrg6219MRbFO+1Vn8WhAkEA+/rqHCspBdXr 85 7RL+H63k7RjqBllVEYlw1ukqTw1gp5IImmeOwgl3aRrJJfFV6gxxEqQ4CCb2vf9M 86 yjrGEvP9KQJBANOTPcpskT/0dyipsAkvLFZTKjN+4fdfq37H3dVgMR6oQcMJwukd 87 cEio1Hx+XzXuD0RHXighq7bUzel+IqzRuq0CQBJkzpIf1G7InuA/cq19VCi6mNq9 88 yqftEH+fpab/ov6YemhLBvDDICRcADL02wCqx9ZEhpKRxZE5AbIBeFQJ24ECQG4f 89 9cmnOPNRC7TengIpy6ojH5QuNu/LnDghUBYAO5D5g0FBk3JDIG6xceha3rPzdX7U 90 pu28mORRX9xpCyNpBwECQQCtDNZoehdPVuZA3Wocno31Rjmuy83ajgRRuEzqv0tj 91 uC6Jo2eLcSV1sSdzTjaaWdM6XeYj6yHOAm8ZBIQs7m6V 92 -----END RSA PRIVATE KEY-----`) 93 ) 94 95 type certificateData struct { 96 keyPEM []byte 97 certificatePEM []byte 98 certificate *tls.Certificate 99 } 100 101 func newCertificateData(certificatePEM string, keyPEM string) *certificateData { 102 certificate, err := tls.X509KeyPair([]byte(certificatePEM), []byte(keyPEM)) 103 if err != nil { 104 panic(fmt.Sprintf("Unable to initialize certificate: %v", err)) 105 } 106 certs, err := x509.ParseCertificates(certificate.Certificate[0]) 107 if err != nil { 108 panic(fmt.Sprintf("Unable to initialize certificate leaf: %v", err)) 109 } 110 certificate.Leaf = certs[0] 111 return &certificateData{ 112 keyPEM: []byte(keyPEM), 113 certificatePEM: []byte(certificatePEM), 114 certificate: &certificate, 115 } 116 } 117 118 type fakeManager struct { 119 cert atomic.Value // Always a *tls.Certificate 120 healthy bool 121 } 122 123 func (f *fakeManager) SetCertificateSigningRequestClient(certificatesclient.CertificateSigningRequestInterface) error { 124 return nil 125 } 126 127 func (f *fakeManager) ServerHealthy() bool { return f.healthy } 128 129 func (f *fakeManager) Start() {} 130 func (f *fakeManager) Stop() {} 131 func (f *fakeManager) RotateCerts() (bool, error) { return false, nil } 132 133 func (f *fakeManager) Current() *tls.Certificate { 134 if val := f.cert.Load(); val != nil { 135 return val.(*tls.Certificate) 136 } 137 return nil 138 } 139 140 func (f *fakeManager) setCurrent(cert *tls.Certificate) { 141 f.cert.Store(cert) 142 } 143 144 func TestRotateShutsDownConnections(t *testing.T) { 145 146 // This test fails if you comment out the t.closeAllConns() call in 147 // transport.go and don't close connections on a rotate. 148 149 stop := make(chan struct{}) 150 defer close(stop) 151 152 m := new(fakeManager) 153 m.setCurrent(client1CertData.certificate) 154 155 // The last certificate we've seen. 156 lastSeenLeafCert := new(atomic.Value) // Always *x509.Certificate 157 158 lastSerialNumber := func() *big.Int { 159 if cert := lastSeenLeafCert.Load(); cert != nil { 160 return cert.(*x509.Certificate).SerialNumber 161 } 162 return big.NewInt(0) 163 } 164 165 h := func(w http.ResponseWriter, r *http.Request) { 166 if r.TLS != nil && len(r.TLS.PeerCertificates) != 0 { 167 // Record the last TLS certificate the client sent. 168 lastSeenLeafCert.Store(r.TLS.PeerCertificates[0]) 169 } 170 w.Write([]byte(`{}`)) 171 } 172 173 s := httptest.NewUnstartedServer(http.HandlerFunc(h)) 174 s.TLS = &tls.Config{ 175 // Just request a cert, we don't need to verify it. 176 ClientAuth: tls.RequestClientCert, 177 } 178 s.StartTLS() 179 defer s.Close() 180 181 c := &rest.Config{ 182 Host: s.URL, 183 TLSClientConfig: rest.TLSClientConfig{ 184 // We don't care about the server's cert. 185 Insecure: true, 186 }, 187 ContentConfig: rest.ContentConfig{ 188 // This is a hack. We don't actually care about the serializer. 189 NegotiatedSerializer: serializer.NegotiatedSerializerWrapper(runtime.SerializerInfo{}), 190 }, 191 } 192 193 // Check for a new cert every 10 milliseconds 194 if _, err := updateTransport(stop, 10*time.Millisecond, c, m, 0); err != nil { 195 t.Fatal(err) 196 } 197 198 client, err := rest.UnversionedRESTClientFor(c) 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 if err := client.Get().Do(context.TODO()).Error(); err != nil { 204 t.Fatal(err) 205 } 206 firstCertSerial := lastSerialNumber() 207 208 // Change the manager's certificate. This should cause the client to shut down 209 // its connections to the server. 210 m.setCurrent(client2CertData.certificate) 211 212 err = wait.PollImmediate(time.Millisecond*50, wait.ForeverTestTimeout, func() (done bool, err error) { 213 client.Get().Do(context.TODO()) 214 if firstCertSerial.Cmp(lastSerialNumber()) != 0 { 215 // The certificate changed! 216 return true, nil 217 } 218 t.Logf("Certificate not changed, will retry.") 219 return false, nil 220 }) 221 if err != nil { 222 t.Fatal("certificate rotated but client never reconnected with new cert") 223 } 224 }