k8s.io/kubernetes@v1.29.3/test/utils/admission_webhook.go (about) 1 /* 2 Copyright 2019 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 utils 18 19 import ( 20 "crypto/tls" 21 "crypto/x509" 22 "encoding/json" 23 "fmt" 24 "io" 25 "net/http" 26 "net/http/httptest" 27 "testing" 28 29 "k8s.io/api/admission/v1beta1" 30 ) 31 32 // NewAdmissionWebhookServer sets up a webhook server with TLS enabled, returns URL and Close function 33 // for the server 34 func NewAdmissionWebhookServer(handler http.Handler) (string, func(), error) { 35 // set up webhook server 36 roots := x509.NewCertPool() 37 if !roots.AppendCertsFromPEM(LocalhostCert) { 38 return "", nil, fmt.Errorf("Failed to append Cert from PEM") 39 } 40 cert, err := tls.X509KeyPair(LocalhostCert, LocalhostKey) 41 if err != nil { 42 return "", nil, fmt.Errorf("Failed to build cert with error: %+v", err) 43 } 44 webhookServer := httptest.NewUnstartedServer(handler) 45 webhookServer.TLS = &tls.Config{ 46 RootCAs: roots, 47 Certificates: []tls.Certificate{cert}, 48 } 49 webhookServer.StartTLS() 50 return webhookServer.URL, webhookServer.Close, nil 51 } 52 53 // AdmissionWebhookHandler creates a HandlerFunc that decodes/encodes AdmissionReview and performs 54 // given admit function 55 func AdmissionWebhookHandler(t *testing.T, admit func(*v1beta1.AdmissionReview) error) http.HandlerFunc { 56 return func(w http.ResponseWriter, r *http.Request) { 57 defer r.Body.Close() 58 data, err := io.ReadAll(r.Body) 59 if err != nil { 60 t.Error(err) 61 return 62 } 63 if contentType := r.Header.Get("Content-Type"); contentType != "application/json" { 64 t.Errorf("contentType=%s, expect application/json", contentType) 65 return 66 } 67 68 review := v1beta1.AdmissionReview{} 69 if err := json.Unmarshal(data, &review); err != nil { 70 t.Errorf("Fail to deserialize object: %s with error: %v", string(data), err) 71 http.Error(w, err.Error(), 400) 72 return 73 } 74 75 if err := admit(&review); err != nil { 76 t.Errorf("%v", err) 77 http.Error(w, err.Error(), 400) 78 return 79 } 80 81 w.Header().Set("Content-Type", "application/json") 82 if err := json.NewEncoder(w).Encode(review); err != nil { 83 t.Errorf("Marshal of response failed with error: %v", err) 84 } 85 } 86 } 87 88 // LocalhostCert was generated from crypto/tls/generate_cert.go with the following command: 89 // 90 // go run generate_cert.go --rsa-bits 2048 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h 91 var LocalhostCert = []byte(`-----BEGIN CERTIFICATE----- 92 MIIDGDCCAgCgAwIBAgIQTKCKn99d5HhQVCLln2Q+eTANBgkqhkiG9w0BAQsFADAS 93 MRAwDgYDVQQKEwdBY21lIENvMCAXDTcwMDEwMTAwMDAwMFoYDzIwODQwMTI5MTYw 94 MDAwWjASMRAwDgYDVQQKEwdBY21lIENvMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A 95 MIIBCgKCAQEA1Z5/aTwqY706M34tn60l8ZHkanWDl8mM1pYf4Q7qg3zA9XqWLX6S 96 4rTYDYCb4stEasC72lQnbEWHbthiQE76zubP8WOFHdvGR3mjAvHWz4FxvLOTheZ+ 97 3iDUrl6Aj9UIsYqzmpBJAoY4+vGGf+xHvuukHrVcFqR9ZuBdZuJ/HbbjUyuNr3X9 98 erNIr5Ha17gVzf17SNbYgNrX9gbCeEB8Z9Ox7dVuJhLDkpF0T/B5Zld3BjyUVY/T 99 cukU4dTVp6isbWPvCMRCZCCOpb+qIhxEjJ0n6tnPt8nf9lvDl4SWMl6X1bH+2EFa 100 a8R06G0QI+XhwPyjXUyCR8QEOZPCR5wyqQIDAQABo2gwZjAOBgNVHQ8BAf8EBAMC 101 AqQwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDwYDVR0TAQH/BAUwAwEB/zAuBgNVHREE 102 JzAlggtleGFtcGxlLmNvbYcEfwAAAYcQAAAAAAAAAAAAAAAAAAAAATANBgkqhkiG 103 9w0BAQsFAAOCAQEAThqgJ/AFqaANsOp48lojDZfZBFxJQ3A4zfR/MgggUoQ9cP3V 104 rxuKAFWQjze1EZc7J9iO1WvH98lOGVNRY/t2VIrVoSsBiALP86Eew9WucP60tbv2 105 8/zsBDSfEo9Wl+Q/gwdEh8dgciUKROvCm76EgAwPGicMAgRsxXgwXHhS5e8nnbIE 106 Ewaqvb5dY++6kh0Oz+adtNT5OqOwXTIRI67WuEe6/B3Z4LNVPQDIj7ZUJGNw8e6L 107 F4nkUthwlKx4yEJHZBRuFPnO7Z81jNKuwL276+mczRH7piI6z9uyMV/JbEsOIxyL 108 W6CzB7pZ9Nj1YLpgzc1r6oONHLokMJJIz/IvkQ== 109 -----END CERTIFICATE-----`) 110 111 // LocalhostKey is the private key for LocalhostCert. 112 var LocalhostKey = []byte(`-----BEGIN RSA PRIVATE KEY----- 113 MIIEowIBAAKCAQEA1Z5/aTwqY706M34tn60l8ZHkanWDl8mM1pYf4Q7qg3zA9XqW 114 LX6S4rTYDYCb4stEasC72lQnbEWHbthiQE76zubP8WOFHdvGR3mjAvHWz4FxvLOT 115 heZ+3iDUrl6Aj9UIsYqzmpBJAoY4+vGGf+xHvuukHrVcFqR9ZuBdZuJ/HbbjUyuN 116 r3X9erNIr5Ha17gVzf17SNbYgNrX9gbCeEB8Z9Ox7dVuJhLDkpF0T/B5Zld3BjyU 117 VY/TcukU4dTVp6isbWPvCMRCZCCOpb+qIhxEjJ0n6tnPt8nf9lvDl4SWMl6X1bH+ 118 2EFaa8R06G0QI+XhwPyjXUyCR8QEOZPCR5wyqQIDAQABAoIBAFAJmb1pMIy8OpFO 119 hnOcYWoYepe0vgBiIOXJy9n8R7vKQ1X2f0w+b3SHw6eTd1TLSjAhVIEiJL85cdwD 120 MRTdQrXA30qXOioMzUa8eWpCCHUpD99e/TgfO4uoi2dluw+pBx/WUyLnSqOqfLDx 121 S66kbeFH0u86jm1hZibki7pfxLbxvu7KQgPe0meO5/13Retztz7/xa/pWIY71Zqd 122 YC8UckuQdWUTxfuQf0470lAK34GZlDy9tvdVOG/PmNkG4j6OQjy0Kmz4Uk7rewKo 123 ZbdphaLPJ2A4Rdqfn4WCoyDnxlfV861T922/dEDZEbNWiQpB81G8OfLL+FLHxyIT 124 LKEu4R0CgYEA4RDj9jatJ/wGkMZBt+UF05mcJlRVMEijqdKgFwR2PP8b924Ka1mj 125 9zqWsfbxQbdPdwsCeVBZrSlTEmuFSQLeWtqBxBKBTps/tUP0qZf7HjfSmcVI89WE 126 3ab8LFjfh4PtK/LOq2D1GRZZkFliqi0gKwYdDoK6gxXWwrumXq4c2l8CgYEA8vrX 127 dMuGCNDjNQkGXx3sr8pyHCDrSNR4Z4FrSlVUkgAW1L7FrCM911BuGh86FcOu9O/1 128 Ggo0E8ge7qhQiXhB5vOo7hiVzSp0FxxCtGSlpdp4W6wx6ZWK8+Pc+6Moos03XdG7 129 MKsdPGDciUn9VMOP3r8huX/btFTh90C/L50sH/cCgYAd02wyW8qUqux/0RYydZJR 130 GWE9Hx3u+SFfRv9aLYgxyyj8oEOXOFjnUYdY7D3KlK1ePEJGq2RG81wD6+XM6Clp 131 Zt2di0pBjYdi0S+iLfbkaUdqg1+ImLoz2YY/pkNxJQWQNmw2//FbMsAJxh6yKKrD 132 qNq+6oonBwTf55hDodVHBwKBgEHgEBnyM9ygBXmTgM645jqiwF0v75pHQH2PcO8u 133 Q0dyDr6PGjiZNWLyw2cBoFXWP9DYXbM5oPTcBMbfizY6DGP5G4uxzqtZHzBE0TDn 134 OKHGoWr5PG7/xDRrSrZOfe3lhWVCP2XqfnqoKCJwlOYuPws89n+8UmyJttm6DBt0 135 mUnxAoGBAIvbR87ZFXkvqstLs4KrdqTz4TQIcpzB3wENukHODPA6C1gzWTqp+OEe 136 GMNltPfGCLO+YmoMQuTpb0kECYV3k4jR3gXO6YvlL9KbY+UOA6P0dDX4ROi2Rklj 137 yh+lxFLYa1vlzzi9r8B7nkR9hrOGMvkfXF42X89g7lx4uMtu2I4q 138 -----END RSA PRIVATE KEY-----`)