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-----`)