1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-04-09 02:29:22 +00:00

Merge pull request #181 from nirmata/171_filter_logs

closes #171
This commit is contained in:
Shivkumar Dudhani 2019-06-19 14:28:25 -07:00 committed by GitHub
commit 7e49fcda36
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 108 additions and 18 deletions

View file

@ -176,6 +176,7 @@ spec:
containers:
- name: kyverno
image: nirmata/kyverno:latest
args: ["--filterKind","Nodes,Events,APIService,SubjectAccessReview"]
ports:
- containerPort: 443
securityContext:

View file

@ -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>

View file

@ -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()
}

View file

@ -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
View 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
}