mirror of
https://github.com/kyverno/kyverno.git
synced 2025-04-09 02:29:22 +00:00
commit
7e49fcda36
5 changed files with 108 additions and 18 deletions
|
@ -176,6 +176,7 @@ spec:
|
|||
containers:
|
||||
- name: kyverno
|
||||
image: nirmata/kyverno:latest
|
||||
args: ["--filterKind","Nodes,Events,APIService,SubjectAccessReview"]
|
||||
ports:
|
||||
- containerPort: 443
|
||||
securityContext:
|
||||
|
|
|
@ -126,6 +126,11 @@ To run controller in this mode you should prepare TLS key/certificate pair for d
|
|||
The [Kyverno CLI](documentation/testing-policies.md#test-using-the-kyverno-cli) allows you to write and test policies without installing Kyverno in a Kubernetes cluster. Some features are not supported without a Kubernetes cluster.
|
||||
|
||||
|
||||
# Filter kuberenetes resources that admission webhook should not process
|
||||
|
||||
The admission webhook checks if a policy is applicable on all admission requests. The kubernetes kinds that are not be processed can be filtered by using the command line argument 'filterKind'.
|
||||
|
||||
By default we have specified Nodes, Events, APIService & SubjectAccessReview as the kinds to be skipped in the [install.yaml](https://github.com/nirmata/kyverno/raw/master/definitions/install.yaml).
|
||||
|
||||
---
|
||||
<small>*Read Next >> [Writing Policies](/documentation/writing-policies.md)*</small>
|
||||
|
|
9
main.go
9
main.go
|
@ -15,8 +15,9 @@ import (
|
|||
)
|
||||
|
||||
var (
|
||||
kubeconfig string
|
||||
serverIP string
|
||||
kubeconfig string
|
||||
serverIP string
|
||||
filterK8Kinds webhooks.ArrayFlags
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
@ -50,8 +51,7 @@ func main() {
|
|||
if err != nil {
|
||||
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
||||
}
|
||||
|
||||
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory)
|
||||
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, filterK8Kinds)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to create webhook server: %v\n", err)
|
||||
}
|
||||
|
@ -83,6 +83,7 @@ func main() {
|
|||
func init() {
|
||||
flag.StringVar(&kubeconfig, "kubeconfig", "", "Path to a kubeconfig. Only required if out-of-cluster.")
|
||||
flag.StringVar(&serverIP, "serverIP", "", "IP address where Kyverno controller runs. Only required if out-of-cluster.")
|
||||
flag.Var(&filterK8Kinds, "filterKind", "k8 kind where policy is not evaluated by the admission webhook. example --filterKind \"Event\" --filterKind \"TokenReview,ClusterRole\"")
|
||||
config.LogDefaultFlags()
|
||||
flag.Parse()
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ type WebhookServer struct {
|
|||
server http.Server
|
||||
client *client.Client
|
||||
policyLister v1alpha1.PolicyLister
|
||||
filterKinds []string
|
||||
}
|
||||
|
||||
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
|
||||
|
@ -36,7 +37,8 @@ type WebhookServer struct {
|
|||
func NewWebhookServer(
|
||||
client *client.Client,
|
||||
tlsPair *tlsutils.TlsPemPair,
|
||||
shareInformer sharedinformer.PolicyInformer) (*WebhookServer, error) {
|
||||
shareInformer sharedinformer.PolicyInformer,
|
||||
filterKinds []string) (*WebhookServer, error) {
|
||||
|
||||
if tlsPair == nil {
|
||||
return nil, errors.New("NewWebhookServer is not initialized properly")
|
||||
|
@ -52,8 +54,8 @@ func NewWebhookServer(
|
|||
ws := &WebhookServer{
|
||||
client: client,
|
||||
policyLister: shareInformer.GetLister(),
|
||||
filterKinds: parseKinds(filterKinds),
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc(config.MutatingWebhookServicePath, ws.serve)
|
||||
mux.HandleFunc(config.ValidatingWebhookServicePath, ws.serve)
|
||||
|
@ -79,11 +81,15 @@ func (ws *WebhookServer) serve(w http.ResponseWriter, r *http.Request) {
|
|||
admissionReview.Response = &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
}
|
||||
switch r.URL.Path {
|
||||
case config.MutatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleMutation(admissionReview.Request)
|
||||
case config.ValidatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleValidation(admissionReview.Request)
|
||||
// Do not process the admission requests for kinds that are in filterKinds for filtering
|
||||
if !StringInSlice(admissionReview.Request.Kind.Kind, ws.filterKinds) {
|
||||
|
||||
switch r.URL.Path {
|
||||
case config.MutatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleMutation(admissionReview.Request)
|
||||
case config.ValidatingWebhookServicePath:
|
||||
admissionReview.Response = ws.HandleValidation(admissionReview.Request)
|
||||
}
|
||||
}
|
||||
|
||||
admissionReview.Response.UID = admissionReview.Request.UID
|
||||
|
@ -124,8 +130,6 @@ func (ws *WebhookServer) Stop() {
|
|||
|
||||
// HandleMutation handles mutating webhook admission request
|
||||
func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
||||
glog.Infof("Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
|
||||
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
|
||||
|
||||
policies, err := ws.policyLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
|
@ -137,6 +141,14 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
var allPatches []engine.PatchBytes
|
||||
for _, policy := range policies {
|
||||
|
||||
// check if policy has a rule for the admission request kind
|
||||
if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) {
|
||||
continue
|
||||
}
|
||||
|
||||
glog.V(3).Infof("Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
|
||||
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
|
||||
|
||||
glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
|
||||
policyPatches, mutationResult := engine.Mutate(*policy, request.Object.Raw, request.Kind)
|
||||
|
@ -152,10 +164,10 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
name := engine.ParseNameFromObject(request.Object.Raw)
|
||||
glog.Infof("Mutation from policy %s has applied to %s %s/%s", policy.Name, request.Kind.Kind, namespace, name)
|
||||
}
|
||||
glog.Info(admissionResult.String())
|
||||
}
|
||||
|
||||
message := "\n" + admissionResult.String()
|
||||
glog.Info(message)
|
||||
|
||||
if admissionResult.GetReason() == result.Success {
|
||||
patchType := v1beta1.PatchTypeJSONPatch
|
||||
|
@ -176,8 +188,6 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
|
|||
|
||||
// HandleValidation handles validating webhook admission request
|
||||
func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
|
||||
glog.Infof("Handling validation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
|
||||
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
|
||||
|
||||
policies, err := ws.policyLister.List(labels.NewSelector())
|
||||
if err != nil {
|
||||
|
@ -187,6 +197,14 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
|||
|
||||
admissionResult := result.NewAdmissionResult(string(request.UID))
|
||||
for _, policy := range policies {
|
||||
|
||||
if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) {
|
||||
continue
|
||||
}
|
||||
|
||||
glog.V(3).Infof("Handling validation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
|
||||
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
|
||||
|
||||
glog.Infof("Validating resource with policy %s with %d rules", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
||||
validationResult := engine.Validate(*policy, request.Object.Raw, request.Kind)
|
||||
admissionResult = result.Append(admissionResult, validationResult)
|
||||
|
@ -194,10 +212,10 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
|||
if validationError := validationResult.ToError(); validationError != nil {
|
||||
glog.Warningf(validationError.Error())
|
||||
}
|
||||
glog.Info(admissionResult.String())
|
||||
}
|
||||
|
||||
message := "\n" + admissionResult.String()
|
||||
glog.Info(message)
|
||||
|
||||
// Generation loop after all validation succeeded
|
||||
var response *v1beta1.AdmissionResponse
|
||||
|
@ -206,7 +224,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
|||
for _, policy := range policies {
|
||||
engine.Generate(ws.client, *policy, request.Object.Raw, request.Kind)
|
||||
}
|
||||
glog.Info("Validation is successful")
|
||||
glog.V(3).Info("Validation is successful")
|
||||
|
||||
response = &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
|
|
65
pkg/webhooks/utils.go
Normal file
65
pkg/webhooks/utils.go
Normal file
|
@ -0,0 +1,65 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
||||
)
|
||||
|
||||
//StringInSlice checks if string is present in slice of strings
|
||||
func StringInSlice(kind string, list []string) bool {
|
||||
for _, b := range list {
|
||||
if b == kind {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
//parseKinds parses the kinds if a single string contains comma seperated kinds
|
||||
// {"1,2,3","4","5"} => {"1","2","3","4","5"}
|
||||
func parseKinds(list []string) []string {
|
||||
kinds := []string{}
|
||||
for _, k := range list {
|
||||
args := strings.Split(k, ",")
|
||||
for _, arg := range args {
|
||||
if arg != "" {
|
||||
kinds = append(kinds, strings.TrimSpace(arg))
|
||||
}
|
||||
}
|
||||
}
|
||||
return kinds
|
||||
}
|
||||
|
||||
type ArrayFlags []string
|
||||
|
||||
func (i *ArrayFlags) String() string {
|
||||
var sb strings.Builder
|
||||
for _, str := range *i {
|
||||
sb.WriteString(str)
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
func (i *ArrayFlags) Set(value string) error {
|
||||
*i = append(*i, value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// extract the kinds that the policy rules apply to
|
||||
func getApplicableKindsForPolicy(p *v1alpha1.Policy) []string {
|
||||
kindsMap := map[string]interface{}{}
|
||||
kinds := []string{}
|
||||
// iterate over the rules an identify all kinds
|
||||
for _, rule := range p.Spec.Rules {
|
||||
for _, k := range rule.ResourceDescription.Kinds {
|
||||
kindsMap[k] = nil
|
||||
}
|
||||
}
|
||||
|
||||
// get the kinds
|
||||
for k := range kindsMap {
|
||||
kinds = append(kinds, k)
|
||||
}
|
||||
return kinds
|
||||
}
|
Loading…
Add table
Reference in a new issue