2019-05-13 18:33:01 +00:00
|
|
|
package webhooks
|
2019-02-07 17:22:04 +00:00
|
|
|
|
|
|
|
import (
|
2019-03-04 18:40:02 +00:00
|
|
|
"context"
|
|
|
|
"crypto/tls"
|
|
|
|
"encoding/json"
|
|
|
|
"errors"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
2019-05-30 19:28:56 +00:00
|
|
|
"github.com/golang/glog"
|
2019-10-30 20:39:19 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/checker"
|
2019-08-17 16:58:14 +00:00
|
|
|
kyvernoclient "github.com/nirmata/kyverno/pkg/client/clientset/versioned"
|
2020-03-29 01:55:13 +00:00
|
|
|
kyvernoinformer "github.com/nirmata/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
2019-11-13 21:41:08 +00:00
|
|
|
kyvernolister "github.com/nirmata/kyverno/pkg/client/listers/kyverno/v1"
|
2019-05-22 17:29:10 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/config"
|
2019-05-29 21:12:09 +00:00
|
|
|
client "github.com/nirmata/kyverno/pkg/dclient"
|
2019-06-27 01:04:50 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/event"
|
2020-03-07 07:23:37 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/policystatus"
|
2019-11-11 19:10:25 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/policystore"
|
2019-11-12 22:41:29 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/policyviolation"
|
2019-05-22 17:29:10 +00:00
|
|
|
tlsutils "github.com/nirmata/kyverno/pkg/tls"
|
2019-11-11 22:52:09 +00:00
|
|
|
userinfo "github.com/nirmata/kyverno/pkg/userinfo"
|
2019-08-21 08:07:32 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/webhookconfig"
|
2020-01-07 18:33:28 +00:00
|
|
|
"github.com/nirmata/kyverno/pkg/webhooks/generate"
|
2019-03-04 18:40:02 +00:00
|
|
|
v1beta1 "k8s.io/api/admission/v1beta1"
|
2019-08-24 01:34:23 +00:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
2020-03-29 01:55:13 +00:00
|
|
|
rbacinformer "k8s.io/client-go/informers/rbac/v1"
|
2019-11-11 23:43:13 +00:00
|
|
|
rbaclister "k8s.io/client-go/listers/rbac/v1"
|
2019-08-12 17:02:07 +00:00
|
|
|
"k8s.io/client-go/tools/cache"
|
2019-02-07 17:22:04 +00:00
|
|
|
)
|
|
|
|
|
2019-03-04 18:40:02 +00:00
|
|
|
// WebhookServer contains configured TLS server with MutationWebhook.
|
|
|
|
// MutationWebhook gets policies from policyController and takes control of the cluster with kubeclient.
|
2019-02-07 17:22:04 +00:00
|
|
|
type WebhookServer struct {
|
2019-11-15 23:59:37 +00:00
|
|
|
server http.Server
|
2020-03-29 01:55:13 +00:00
|
|
|
client *client.Client
|
|
|
|
kyvernoClient *kyvernoclient.Clientset
|
2019-11-15 23:59:37 +00:00
|
|
|
// list/get cluster policy resource
|
2020-03-29 01:55:13 +00:00
|
|
|
pLister kyvernolister.ClusterPolicyLister
|
2019-11-15 23:59:37 +00:00
|
|
|
// returns true if the cluster policy store has synced atleast
|
2020-03-29 01:55:13 +00:00
|
|
|
pSynced cache.InformerSynced
|
2019-11-15 23:59:37 +00:00
|
|
|
// list/get role binding resource
|
2020-03-29 01:55:13 +00:00
|
|
|
rbLister rbaclister.RoleBindingLister
|
2019-11-15 23:59:37 +00:00
|
|
|
// return true if role bining store has synced atleast once
|
2020-03-29 01:55:13 +00:00
|
|
|
rbSynced cache.InformerSynced
|
2019-11-15 23:59:37 +00:00
|
|
|
// list/get cluster role binding resource
|
2020-03-29 01:55:13 +00:00
|
|
|
crbLister rbaclister.ClusterRoleBindingLister
|
2019-11-15 23:59:37 +00:00
|
|
|
// return true if cluster role binding store has synced atleast once
|
2020-03-29 01:55:13 +00:00
|
|
|
crbSynced cache.InformerSynced
|
2019-11-15 23:59:37 +00:00
|
|
|
// generate events
|
2020-03-29 01:55:13 +00:00
|
|
|
eventGen event.Interface
|
2019-11-15 23:59:37 +00:00
|
|
|
// webhook registration client
|
2020-03-29 01:55:13 +00:00
|
|
|
webhookRegistrationClient *webhookconfig.WebhookRegistrationClient
|
2019-08-20 19:51:25 +00:00
|
|
|
// API to send policy stats for aggregation
|
2020-03-29 01:55:13 +00:00
|
|
|
statusListener policystatus.Listener
|
2019-10-19 00:38:46 +00:00
|
|
|
// helpers to validate against current loaded configuration
|
2020-03-29 01:55:13 +00:00
|
|
|
configHandler config.Interface
|
2019-10-19 00:38:46 +00:00
|
|
|
// channel for cleanup notification
|
2020-03-29 01:55:13 +00:00
|
|
|
cleanUp chan<- struct{}
|
2019-10-30 20:39:19 +00:00
|
|
|
// last request time
|
2020-03-29 01:55:13 +00:00
|
|
|
lastReqTime *checker.LastReqTime
|
2019-11-11 19:10:25 +00:00
|
|
|
// store to hold policy meta data for faster lookup
|
2020-03-29 01:55:13 +00:00
|
|
|
pMetaStore policystore.LookupInterface
|
2019-11-12 22:41:29 +00:00
|
|
|
// policy violation generator
|
2020-03-29 01:55:13 +00:00
|
|
|
pvGenerator policyviolation.GeneratorInterface
|
2020-01-07 18:33:28 +00:00
|
|
|
// generate request generator
|
2020-03-29 01:55:13 +00:00
|
|
|
grGenerator *generate.Generator
|
|
|
|
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister
|
2019-03-04 18:40:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
|
|
|
|
// Policy Controller and Kubernetes Client should be initialized in configuration
|
2019-05-13 18:27:47 +00:00
|
|
|
func NewWebhookServer(
|
2020-03-29 01:55:13 +00:00
|
|
|
kyvernoClient *kyvernoclient.Clientset,
|
|
|
|
client *client.Client,
|
|
|
|
tlsPair *tlsutils.TlsPemPair,
|
|
|
|
pInformer kyvernoinformer.ClusterPolicyInformer,
|
|
|
|
rbInformer rbacinformer.RoleBindingInformer,
|
|
|
|
crbInformer rbacinformer.ClusterRoleBindingInformer,
|
|
|
|
eventGen event.Interface,
|
|
|
|
webhookRegistrationClient *webhookconfig.WebhookRegistrationClient,
|
|
|
|
statusSync policystatus.Listener,
|
|
|
|
configHandler config.Interface,
|
|
|
|
pMetaStore policystore.LookupInterface,
|
|
|
|
pvGenerator policyviolation.GeneratorInterface,
|
|
|
|
grGenerator *generate.Generator,
|
|
|
|
resourceWebhookWatcher *webhookconfig.ResourceWebhookRegister,
|
|
|
|
cleanUp chan<- struct{}) (*WebhookServer, error) {
|
2019-03-04 18:40:02 +00:00
|
|
|
|
2019-05-13 18:27:47 +00:00
|
|
|
if tlsPair == nil {
|
2019-03-22 20:11:55 +00:00
|
|
|
return nil, errors.New("NewWebhookServer is not initialized properly")
|
2019-03-04 18:40:02 +00:00
|
|
|
}
|
2020-03-29 01:55:13 +00:00
|
|
|
|
2019-03-04 18:40:02 +00:00
|
|
|
var tlsConfig tls.Config
|
2019-03-22 20:11:55 +00:00
|
|
|
pair, err := tls.X509KeyPair(tlsPair.Certificate, tlsPair.PrivateKey)
|
2019-03-04 18:40:02 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
tlsConfig.Certificates = []tls.Certificate{pair}
|
|
|
|
|
2020-03-29 01:55:13 +00:00
|
|
|
ws := &WebhookServer{
|
|
|
|
client: client,
|
|
|
|
kyvernoClient: kyvernoClient,
|
|
|
|
pLister: pInformer.Lister(),
|
|
|
|
pSynced: pInformer.Informer().HasSynced,
|
|
|
|
rbLister: rbInformer.Lister(),
|
|
|
|
rbSynced: rbInformer.Informer().HasSynced,
|
|
|
|
crbLister: crbInformer.Lister(),
|
|
|
|
crbSynced: crbInformer.Informer().HasSynced,
|
|
|
|
eventGen: eventGen,
|
|
|
|
webhookRegistrationClient: webhookRegistrationClient,
|
|
|
|
statusListener: statusSync,
|
|
|
|
configHandler: configHandler,
|
|
|
|
cleanUp: cleanUp,
|
|
|
|
lastReqTime: resourceWebhookWatcher.LastReqTime,
|
|
|
|
pvGenerator: pvGenerator,
|
|
|
|
pMetaStore: pMetaStore,
|
|
|
|
grGenerator: grGenerator,
|
|
|
|
resourceWebhookWatcher: resourceWebhookWatcher,
|
|
|
|
}
|
2019-03-04 18:40:02 +00:00
|
|
|
mux := http.NewServeMux()
|
2020-03-29 02:06:18 +00:00
|
|
|
mux.HandleFunc(config.MutatingWebhookServicePath, ws.handlerFunc(ws.handleMutateAdmissionRequest, true))
|
|
|
|
mux.HandleFunc(config.ValidatingWebhookServicePath, ws.handlerFunc(ws.handleValidateAdmissionRequest, true))
|
|
|
|
mux.HandleFunc(config.PolicyMutatingWebhookServicePath, ws.handlerFunc(ws.handlePolicyMutation, true))
|
|
|
|
mux.HandleFunc(config.PolicyValidatingWebhookServicePath, ws.handlerFunc(ws.handlePolicyValidation, true))
|
|
|
|
mux.HandleFunc(config.VerifyMutatingWebhookServicePath, ws.handlerFunc(ws.handleVerifyRequest, false))
|
2019-03-04 18:40:02 +00:00
|
|
|
ws.server = http.Server{
|
|
|
|
Addr: ":443", // Listen on port for HTTPS requests
|
|
|
|
TLSConfig: &tlsConfig,
|
|
|
|
Handler: mux,
|
|
|
|
ReadTimeout: 15 * time.Second,
|
|
|
|
WriteTimeout: 15 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
return ws, nil
|
2019-02-21 18:31:18 +00:00
|
|
|
}
|
|
|
|
|
2020-03-29 02:06:18 +00:00
|
|
|
func (ws *WebhookServer) handlerFunc(handler func(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse, filter bool) http.HandlerFunc {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
startTime := time.Now()
|
|
|
|
// for every request received on the ep update last request time,
|
|
|
|
// this is used to verify admission control
|
|
|
|
ws.lastReqTime.SetTime(time.Now())
|
|
|
|
admissionReview := ws.bodyToAdmissionReview(r, w)
|
|
|
|
if admissionReview == nil {
|
|
|
|
return
|
2020-03-25 05:23:03 +00:00
|
|
|
}
|
2020-03-29 02:06:18 +00:00
|
|
|
defer func() {
|
|
|
|
glog.V(4).Infof("request: %v %s/%s/%s", time.Since(startTime), admissionReview.Request.Kind, admissionReview.Request.Namespace, admissionReview.Request.Name)
|
|
|
|
}()
|
|
|
|
|
|
|
|
admissionReview.Response = &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: true,
|
2020-03-25 05:23:03 +00:00
|
|
|
}
|
2020-03-29 02:06:18 +00:00
|
|
|
|
|
|
|
// Do not process the admission requests for kinds that are in filterKinds for filtering
|
|
|
|
request := admissionReview.Request
|
|
|
|
if filter {
|
|
|
|
if !ws.configHandler.ToFilter(request.Kind.Kind, request.Namespace, request.Name) {
|
|
|
|
admissionReview.Response = handler(request)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
admissionReview.Response = handler(request)
|
2020-03-29 01:55:13 +00:00
|
|
|
}
|
2020-03-29 02:06:18 +00:00
|
|
|
admissionReview.Response.UID = request.UID
|
2020-03-29 01:55:13 +00:00
|
|
|
|
2020-03-29 02:06:18 +00:00
|
|
|
responseJSON, err := json.Marshal(admissionReview)
|
|
|
|
if err != nil {
|
|
|
|
http.Error(w, fmt.Sprintf("Could not encode response: %v", err), http.StatusInternalServerError)
|
|
|
|
return
|
|
|
|
}
|
2020-03-29 01:55:13 +00:00
|
|
|
|
2020-03-29 02:06:18 +00:00
|
|
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
|
|
|
if _, err := w.Write(responseJSON); err != nil {
|
|
|
|
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError)
|
|
|
|
}
|
2019-03-04 18:40:02 +00:00
|
|
|
}
|
2019-02-15 18:00:49 +00:00
|
|
|
}
|
|
|
|
|
2020-01-11 13:03:11 +00:00
|
|
|
func (ws *WebhookServer) handleMutateAdmissionRequest(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
2020-03-29 01:55:13 +00:00
|
|
|
policies, err := ws.pMetaStore.ListAll()
|
2019-11-07 20:13:16 +00:00
|
|
|
if err != nil {
|
2019-11-13 20:15:51 +00:00
|
|
|
// Unable to connect to policy Lister to access policies
|
2019-11-07 20:13:16 +00:00
|
|
|
glog.Errorf("Unable to connect to policy controller to access policies. Policies are NOT being applied: %v", err)
|
|
|
|
return &v1beta1.AdmissionResponse{Allowed: true}
|
|
|
|
}
|
|
|
|
|
2019-11-11 22:52:09 +00:00
|
|
|
var roles, clusterRoles []string
|
|
|
|
|
|
|
|
// getRoleRef only if policy has roles/clusterroles defined
|
2019-11-12 05:23:26 +00:00
|
|
|
startTime := time.Now()
|
2019-11-11 22:52:09 +00:00
|
|
|
if containRBACinfo(policies) {
|
2020-03-29 01:55:13 +00:00
|
|
|
roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request)
|
2019-11-11 22:52:09 +00:00
|
|
|
if err != nil {
|
|
|
|
// TODO(shuting): continue apply policy if error getting roleRef?
|
|
|
|
glog.Errorf("Unable to get rbac information for request Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s: %v",
|
|
|
|
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation, err)
|
|
|
|
}
|
2019-11-09 02:56:24 +00:00
|
|
|
}
|
2019-11-12 05:23:26 +00:00
|
|
|
glog.V(4).Infof("Time: webhook GetRoleRef %v", time.Since(startTime))
|
2019-11-09 02:56:24 +00:00
|
|
|
|
2020-01-07 03:24:24 +00:00
|
|
|
// convert RAW to unstructured
|
2020-01-07 19:32:52 +00:00
|
|
|
resource, err := convertResource(request.Object.Raw, request.Kind.Group, request.Kind.Version, request.Kind.Kind, request.Namespace)
|
2020-01-07 03:24:24 +00:00
|
|
|
if err != nil {
|
2020-01-07 19:32:52 +00:00
|
|
|
glog.Errorf(err.Error())
|
|
|
|
|
2020-01-07 03:24:24 +00:00
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: false,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Failure",
|
2020-01-07 19:32:52 +00:00
|
|
|
Message: err.Error(),
|
2020-01-07 03:24:24 +00:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-07 19:32:52 +00:00
|
|
|
if checkPodTemplateAnn(resource) {
|
2020-01-07 03:24:24 +00:00
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: true,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Success",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-24 01:34:23 +00:00
|
|
|
// MUTATION
|
2020-01-16 05:46:58 +00:00
|
|
|
// mutation failure should not block the resource creation
|
|
|
|
// any mutation failure is reported as the violation
|
2020-01-16 22:29:44 +00:00
|
|
|
patches := ws.HandleMutation(request, resource, policies, roles, clusterRoles)
|
2019-08-14 18:51:01 +00:00
|
|
|
|
2019-08-24 01:34:23 +00:00
|
|
|
// patch the resource with patches before handling validation rules
|
|
|
|
patchedResource := processResourceWithPatches(patches, request.Object.Raw)
|
|
|
|
|
2020-03-29 01:55:13 +00:00
|
|
|
if ws.resourceWebhookWatcher != nil && ws.resourceWebhookWatcher.RunValidationInMutatingWebhook == "true" {
|
2020-01-11 13:03:11 +00:00
|
|
|
// VALIDATION
|
2020-01-24 17:54:20 +00:00
|
|
|
ok, msg := ws.HandleValidation(request, policies, patchedResource, roles, clusterRoles)
|
2020-01-11 13:03:11 +00:00
|
|
|
if !ok {
|
|
|
|
glog.V(4).Infof("Deny admission request: %v/%s/%s", request.Kind, request.Namespace, request.Name)
|
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: false,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Failure",
|
|
|
|
Message: msg,
|
|
|
|
},
|
|
|
|
}
|
2019-08-24 01:34:23 +00:00
|
|
|
}
|
2019-08-14 18:51:01 +00:00
|
|
|
}
|
|
|
|
|
2020-01-07 18:33:28 +00:00
|
|
|
// GENERATE
|
|
|
|
// Only applied during resource creation
|
|
|
|
// Success -> Generate Request CR created successsfully
|
|
|
|
// Failed -> Failed to create Generate Request CR
|
|
|
|
if request.Operation == v1beta1.Create {
|
2020-01-24 17:55:39 +00:00
|
|
|
ok, msg := ws.HandleGenerate(request, policies, patchedResource, roles, clusterRoles)
|
2020-01-07 18:33:28 +00:00
|
|
|
if !ok {
|
|
|
|
glog.V(4).Infof("Deny admission request: %v/%s/%s", request.Kind, request.Namespace, request.Name)
|
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: false,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Failure",
|
|
|
|
Message: msg,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-08-24 01:34:23 +00:00
|
|
|
// Succesfful processing of mutation & validation rules in policy
|
|
|
|
patchType := v1beta1.PatchTypeJSONPatch
|
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: true,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Success",
|
|
|
|
},
|
|
|
|
Patch: patches,
|
|
|
|
PatchType: &patchType,
|
|
|
|
}
|
2019-08-14 18:51:01 +00:00
|
|
|
}
|
|
|
|
|
2020-01-11 13:03:11 +00:00
|
|
|
func (ws *WebhookServer) handleValidateAdmissionRequest(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
2020-03-29 01:55:13 +00:00
|
|
|
policies, err := ws.pMetaStore.ListAll()
|
2020-01-11 13:03:11 +00:00
|
|
|
if err != nil {
|
|
|
|
// Unable to connect to policy Lister to access policies
|
|
|
|
glog.Errorf("Unable to connect to policy controller to access policies. Policies are NOT being applied: %v", err)
|
|
|
|
return &v1beta1.AdmissionResponse{Allowed: true}
|
|
|
|
}
|
|
|
|
|
|
|
|
var roles, clusterRoles []string
|
|
|
|
|
|
|
|
// getRoleRef only if policy has roles/clusterroles defined
|
|
|
|
startTime := time.Now()
|
|
|
|
if containRBACinfo(policies) {
|
2020-03-29 01:55:13 +00:00
|
|
|
roles, clusterRoles, err = userinfo.GetRoleRef(ws.rbLister, ws.crbLister, request)
|
2020-01-11 13:03:11 +00:00
|
|
|
if err != nil {
|
|
|
|
// TODO(shuting): continue apply policy if error getting roleRef?
|
|
|
|
glog.Errorf("Unable to get rbac information for request Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s: %v",
|
|
|
|
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation, err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
glog.V(4).Infof("Time: webhook GetRoleRef %v", time.Since(startTime))
|
|
|
|
|
|
|
|
// VALIDATION
|
|
|
|
ok, msg := ws.HandleValidation(request, policies, nil, roles, clusterRoles)
|
|
|
|
if !ok {
|
|
|
|
glog.V(4).Infof("Deny admission request: %v/%s/%s", request.Kind, request.Namespace, request.Name)
|
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: false,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Failure",
|
|
|
|
Message: msg,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return &v1beta1.AdmissionResponse{
|
|
|
|
Allowed: true,
|
|
|
|
Result: &metav1.Status{
|
|
|
|
Status: "Success",
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-14 15:10:25 +00:00
|
|
|
// RunAsync TLS server in separate thread and returns control immediately
|
2019-10-25 21:55:48 +00:00
|
|
|
func (ws *WebhookServer) RunAsync(stopCh <-chan struct{}) {
|
2020-03-29 01:55:13 +00:00
|
|
|
if !cache.WaitForCacheSync(stopCh, ws.pSynced, ws.rbSynced, ws.crbSynced) {
|
2019-11-15 23:59:37 +00:00
|
|
|
glog.Error("webhook: failed to sync informer cache")
|
|
|
|
}
|
|
|
|
|
2019-03-04 18:40:02 +00:00
|
|
|
go func(ws *WebhookServer) {
|
2019-07-24 00:54:31 +00:00
|
|
|
glog.V(3).Infof("serving on %s\n", ws.server.Addr)
|
2019-08-28 00:00:16 +00:00
|
|
|
if err := ws.server.ListenAndServeTLS("", ""); err != http.ErrServerClosed {
|
|
|
|
glog.Infof("HTTP server error: %v", err)
|
2019-03-04 18:40:02 +00:00
|
|
|
}
|
|
|
|
}(ws)
|
2019-05-30 19:28:56 +00:00
|
|
|
glog.Info("Started Webhook Server")
|
2019-10-30 20:39:19 +00:00
|
|
|
// verifys if the admission control is enabled and active
|
|
|
|
// resync: 60 seconds
|
|
|
|
// deadline: 60 seconds (send request)
|
|
|
|
// max deadline: deadline*3 (set the deployment annotation as false)
|
2020-03-29 01:55:13 +00:00
|
|
|
go ws.lastReqTime.Run(ws.pLister, ws.eventGen, ws.client, checker.DefaultResync, checker.DefaultDeadline, stopCh)
|
2020-01-07 18:33:28 +00:00
|
|
|
|
2019-02-07 17:22:04 +00:00
|
|
|
}
|
|
|
|
|
2019-05-14 15:10:25 +00:00
|
|
|
// Stop TLS server and returns control after the server is shut down
|
2019-11-18 19:41:37 +00:00
|
|
|
func (ws *WebhookServer) Stop(ctx context.Context) {
|
|
|
|
// cleanUp
|
|
|
|
// remove the static webhookconfigurations
|
2020-03-29 01:55:13 +00:00
|
|
|
go ws.webhookRegistrationClient.RemoveWebhookConfigurations(ws.cleanUp)
|
2019-11-18 19:41:37 +00:00
|
|
|
// shutdown http.Server with context timeout
|
|
|
|
err := ws.server.Shutdown(ctx)
|
2019-03-04 18:40:02 +00:00
|
|
|
if err != nil {
|
|
|
|
// Error from closing listeners, or context timeout:
|
2019-06-07 11:46:18 +00:00
|
|
|
glog.Info("Server Shutdown error: ", err)
|
2019-03-04 18:40:02 +00:00
|
|
|
ws.server.Close()
|
|
|
|
}
|
2019-02-07 17:22:04 +00:00
|
|
|
}
|
2019-05-13 18:27:47 +00:00
|
|
|
|
2019-05-14 15:10:25 +00:00
|
|
|
// bodyToAdmissionReview creates AdmissionReview object from request body
|
|
|
|
// Answers to the http.ResponseWriter if request is not valid
|
|
|
|
func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer http.ResponseWriter) *v1beta1.AdmissionReview {
|
|
|
|
var body []byte
|
|
|
|
if request.Body != nil {
|
|
|
|
if data, err := ioutil.ReadAll(request.Body); err == nil {
|
|
|
|
body = data
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if len(body) == 0 {
|
2019-05-30 19:28:56 +00:00
|
|
|
glog.Error("Error: empty body")
|
2019-05-14 15:10:25 +00:00
|
|
|
http.Error(writer, "empty body", http.StatusBadRequest)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
contentType := request.Header.Get("Content-Type")
|
|
|
|
if contentType != "application/json" {
|
2019-06-07 11:46:18 +00:00
|
|
|
glog.Error("Error: invalid Content-Type: ", contentType)
|
2019-05-14 15:10:25 +00:00
|
|
|
http.Error(writer, "invalid Content-Type, expect `application/json`", http.StatusUnsupportedMediaType)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
admissionReview := &v1beta1.AdmissionReview{}
|
|
|
|
if err := json.Unmarshal(body, &admissionReview); err != nil {
|
2019-05-30 19:28:56 +00:00
|
|
|
glog.Errorf("Error: Can't decode body as AdmissionReview: %v", err)
|
2019-05-14 15:10:25 +00:00
|
|
|
http.Error(writer, "Can't decode body as AdmissionReview", http.StatusExpectationFailed)
|
|
|
|
return nil
|
|
|
|
}
|
2019-06-06 00:43:59 +00:00
|
|
|
|
|
|
|
return admissionReview
|
2019-05-13 18:27:47 +00:00
|
|
|
}
|