112 lines
4.0 KiB
Go
112 lines
4.0 KiB
Go
/*
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
you may not use this file except in compliance with the License.
|
|
You may obtain a copy of the License at
|
|
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
Unless required by applicable law or agreed to in writing, software
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
See the License for the specific language governing permissions and
|
|
limitations under the License.
|
|
*/
|
|
|
|
package utils
|
|
|
|
import (
|
|
"crypto/tls"
|
|
"crypto/x509"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"k8s.io/api/admission/v1beta1"
|
|
)
|
|
|
|
// NewAdmissionWebhookServer sets up a webhook server with TLS enabled, returns URL and Close function
|
|
// for the server
|
|
func NewAdmissionWebhookServer(handler http.Handler) (string, func(), error) {
|
|
// set up webhook server
|
|
roots := x509.NewCertPool()
|
|
if !roots.AppendCertsFromPEM(LocalhostCert) {
|
|
return "", nil, fmt.Errorf("Failed to append Cert from PEM")
|
|
}
|
|
cert, err := tls.X509KeyPair(LocalhostCert, LocalhostKey)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("Failed to build cert with error: %+v", err)
|
|
}
|
|
webhookServer := httptest.NewUnstartedServer(handler)
|
|
webhookServer.TLS = &tls.Config{
|
|
RootCAs: roots,
|
|
Certificates: []tls.Certificate{cert},
|
|
}
|
|
webhookServer.StartTLS()
|
|
return webhookServer.URL, webhookServer.Close, nil
|
|
}
|
|
|
|
// AdmissionWebhookHandler creates a HandlerFunc that decodes/encodes AdmissionReview and performs
|
|
// given admit function
|
|
func AdmissionWebhookHandler(t *testing.T, admit func(*v1beta1.AdmissionReview) error) http.HandlerFunc {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
defer r.Body.Close()
|
|
data, err := ioutil.ReadAll(r.Body)
|
|
if err != nil {
|
|
t.Error(err)
|
|
return
|
|
}
|
|
if contentType := r.Header.Get("Content-Type"); contentType != "application/json" {
|
|
t.Errorf("contentType=%s, expect application/json", contentType)
|
|
return
|
|
}
|
|
|
|
review := v1beta1.AdmissionReview{}
|
|
if err := json.Unmarshal(data, &review); err != nil {
|
|
t.Errorf("Fail to deserialize object: %s with error: %v", string(data), err)
|
|
http.Error(w, err.Error(), 400)
|
|
return
|
|
}
|
|
|
|
if err := admit(&review); err != nil {
|
|
t.Errorf("%v", err)
|
|
http.Error(w, err.Error(), 400)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
if err := json.NewEncoder(w).Encode(review); err != nil {
|
|
t.Errorf("Marshal of response failed with error: %v", err)
|
|
}
|
|
})
|
|
}
|
|
|
|
// LocalhostCert was generated from crypto/tls/generate_cert.go with the following command:
|
|
// go run generate_cert.go --rsa-bits 512 --host 127.0.0.1,::1,example.com --ca --start-date "Jan 1 00:00:00 1970" --duration=1000000h
|
|
var LocalhostCert = []byte(`-----BEGIN CERTIFICATE-----
|
|
MIIBjzCCATmgAwIBAgIRAKpi2WmTcFrVjxrl5n5YDUEwDQYJKoZIhvcNAQELBQAw
|
|
EjEQMA4GA1UEChMHQWNtZSBDbzAgFw03MDAxMDEwMDAwMDBaGA8yMDg0MDEyOTE2
|
|
MDAwMFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC
|
|
QQC9fEbRszP3t14Gr4oahV7zFObBI4TfA5i7YnlMXeLinb7MnvT4bkfOJzE6zktn
|
|
59zP7UiHs3l4YOuqrjiwM413AgMBAAGjaDBmMA4GA1UdDwEB/wQEAwICpDATBgNV
|
|
HSUEDDAKBggrBgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MC4GA1UdEQQnMCWCC2V4
|
|
YW1wbGUuY29thwR/AAABhxAAAAAAAAAAAAAAAAAAAAABMA0GCSqGSIb3DQEBCwUA
|
|
A0EAUsVE6KMnza/ZbodLlyeMzdo7EM/5nb5ywyOxgIOCf0OOLHsPS9ueGLQX9HEG
|
|
//yjTXuhNcUugExIjM/AIwAZPQ==
|
|
-----END CERTIFICATE-----`)
|
|
|
|
// LocalhostKey is the private key for LocalhostCert.
|
|
var LocalhostKey = []byte(`-----BEGIN RSA PRIVATE KEY-----
|
|
MIIBOwIBAAJBAL18RtGzM/e3XgavihqFXvMU5sEjhN8DmLtieUxd4uKdvsye9Phu
|
|
R84nMTrOS2fn3M/tSIezeXhg66quOLAzjXcCAwEAAQJBAKcRxH9wuglYLBdI/0OT
|
|
BLzfWPZCEw1vZmMR2FF1Fm8nkNOVDPleeVGTWoOEcYYlQbpTmkGSxJ6ya+hqRi6x
|
|
goECIQDx3+X49fwpL6B5qpJIJMyZBSCuMhH4B7JevhGGFENi3wIhAMiNJN5Q3UkL
|
|
IuSvv03kaPR5XVQ99/UeEetUgGvBcABpAiBJSBzVITIVCGkGc7d+RCf49KTCIklv
|
|
bGWObufAR8Ni4QIgWpILjW8dkGg8GOUZ0zaNA6Nvt6TIv2UWGJ4v5PoV98kCIQDx
|
|
rIiZs5QbKdycsv9gQJzwQAogC8o04X3Zz3dsoX+h4A==
|
|
-----END RSA PRIVATE KEY-----`)
|