diff --git a/main.go b/main.go index 6e3cab4839..b9e1d34bc8 100644 --- a/main.go +++ b/main.go @@ -31,13 +31,6 @@ func main() { glog.Fatalf("Error building kubeconfig: %v\n", err) } - // DYNAMIC CLIENT - // - client for all registered resources - client, err := client.NewClient(clientConfig) - if err != nil { - glog.Fatalf("Error creating client: %v\n", err) - } - // KYVENO CRD CLIENT // access CRD resources // - Policy @@ -46,6 +39,12 @@ func main() { if err != nil { glog.Fatalf("Error creating client: %v\n", err) } + // DYNAMIC CLIENT + // - client for all registered resources + client, err := client.NewClient(clientConfig) + if err != nil { + glog.Fatalf("Error creating client: %v\n", err) + } // KYVERNO CRD INFORMER // watches CRD resources: @@ -78,7 +77,7 @@ func main() { if err != nil { glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err) } - server, err := webhooks.NewWebhookServer(client, tlsPair, pInformer.Kyverno().V1alpha1().Policies(), egen, filterK8Resources) + server, err := webhooks.NewWebhookServer(pclient, client, tlsPair, pInformer.Kyverno().V1alpha1().Policies(), egen, filterK8Resources) if err != nil { glog.Fatalf("Unable to create webhook server: %v\n", err) } diff --git a/pkg/policyviolation/helpers.go b/pkg/policyviolation/helpers.go index 69d8d85ae4..ee3aa94bf2 100644 --- a/pkg/policyviolation/helpers.go +++ b/pkg/policyviolation/helpers.go @@ -13,5 +13,7 @@ func BuildPolicyViolation(policy string, resource kyverno.ResourceSpec, fRules [ ViolatedRules: fRules, }, } + //TODO: check if this can be removed or use unstructured? + // pv.Kind = "PolicyViolation" return pv } diff --git a/pkg/webhooks/mutation.go b/pkg/webhooks/mutation.go index 5fd48d198c..99447f85e6 100644 --- a/pkg/webhooks/mutation.go +++ b/pkg/webhooks/mutation.go @@ -14,6 +14,8 @@ import ( func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse { var patches [][]byte var policyInfos []info.PolicyInfo + // map to store the mutation changes on the resource + // mAnn := map[string]string{} glog.V(4).Infof("Receive request in mutating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s", request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation) @@ -61,6 +63,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be } continue } + // build annotations per policy being applied to show the mutation changes patches = append(patches, policyPatches...) glog.V(4).Infof("Mutation from policy %s has applied succesfully to %s %s/%s", policy.Name, request.Kind.Kind, resource.GetNamespace(), resource.GetName()) } diff --git a/pkg/webhooks/report.go b/pkg/webhooks/report.go index f0e171e1d8..1f6b93087f 100644 --- a/pkg/webhooks/report.go +++ b/pkg/webhooks/report.go @@ -1,14 +1,18 @@ package webhooks import ( + "reflect" "strings" "github.com/nirmata/kyverno/pkg/annotations" + kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1" + kyvernoclient "github.com/nirmata/kyverno/pkg/clientNew/clientset/versioned" "github.com/nirmata/kyverno/pkg/violation" "github.com/golang/glog" "github.com/nirmata/kyverno/pkg/event" "github.com/nirmata/kyverno/pkg/info" + "github.com/nirmata/kyverno/pkg/policyviolation" ) //TODO: change validation from bool -> enum(validation, mutation) @@ -75,3 +79,74 @@ func addAnnotationsToResource(rawResource []byte, pi *info.PolicyInfo, ruleType } return patch } + +//buildAnnotation we add annotations for the successful application of JSON patches +//TODO +func buildAnnotation(mAnn map[string]string, pi *info.PolicyInfo) { + if len(pi.Rules) == 0 { + return + } + var mchanges []string + + for _, r := range pi.Rules { + if r.Changes != "" { + // the rule generate a patch + // key policy name will be updated to right format during creation of annotations + mchanges = append(mchanges) + } + } +} + +// buildPolicyViolationsForAPolicy returns a policy violation object if there are any rules that fail +func buildPolicyViolationsForAPolicy(pi info.PolicyInfo) kyverno.PolicyViolation { + var fRules []kyverno.ViolatedRule + var pv kyverno.PolicyViolation + for _, r := range pi.Rules { + if !r.IsSuccessful() { + fRules = append(fRules, kyverno.ViolatedRule{Name: r.Name, Message: r.GetErrorString(), Type: r.RuleType.String()}) + } + } + if len(fRules) > 0 { + glog.V(4).Infof("building policy violation for policy %s on resource %s/%s/%s", pi.Name, pi.RKind, pi.RNamespace, pi.RName) + // there is an error + pv = policyviolation.BuildPolicyViolation(pi.Name, kyverno.ResourceSpec{ + Kind: pi.RKind, + Namespace: pi.RNamespace, + Name: pi.RName, + }, + fRules, + ) + + } + return pv +} + +//generatePolicyViolations generate policyViolation resources for the rules that failed +func generatePolicyViolations(client *kyvernoclient.Clientset, policyInfos []info.PolicyInfo) { + var pvs []kyverno.PolicyViolation + for _, policyInfo := range policyInfos { + if !policyInfo.IsSuccessful() { + if pv := buildPolicyViolationsForAPolicy(policyInfo); !reflect.DeepEqual(pv, kyverno.PolicyViolation{}) { + pvs = append(pvs, pv) + } + } + } + + if len(pvs) > 0 { + for _, newPv := range pvs { + // generate PolicyViolation objects + glog.V(4).Infof("creating policyViolation resource for policy %s and resource %s/%s/%s", newPv.Spec.Policy, newPv.Spec.Kind, newPv.Spec.Namespace, newPv.Spec.Name) + + // check if there was a previous violation for policy & resource combination + //TODO: check for existing ov using label selectors on resource and policy + // curPv, err:= client.KyvernoV1alpha1().PolicyViolations(). + + // _, err := client.KyvernoV1alpha1().PolicyViolations().Create(&newPv) + // // _, err := client.CreateResource("PolicyViolation", "", &pv, false) + // if err != nil { + // glog.Error(err) + // continue + // } + } + } +} diff --git a/pkg/webhooks/server.go b/pkg/webhooks/server.go index cd36edf8d2..5ef509f639 100644 --- a/pkg/webhooks/server.go +++ b/pkg/webhooks/server.go @@ -11,6 +11,7 @@ import ( "time" "github.com/golang/glog" + kyvernoclient "github.com/nirmata/kyverno/pkg/clientNew/clientset/versioned" informer "github.com/nirmata/kyverno/pkg/clientNew/informers/externalversions/kyverno/v1alpha1" lister "github.com/nirmata/kyverno/pkg/clientNew/listers/kyverno/v1alpha1" "github.com/nirmata/kyverno/pkg/config" @@ -26,6 +27,7 @@ import ( type WebhookServer struct { server http.Server client *client.Client + kyvernoClient *kyvernoclient.Clientset pLister lister.PolicyLister eventGen event.Interface filterK8Resources []utils.K8Resource @@ -34,6 +36,7 @@ type WebhookServer struct { // NewWebhookServer creates new instance of WebhookServer accordingly to given configuration // Policy Controller and Kubernetes Client should be initialized in configuration func NewWebhookServer( + kyvernoClient *kyvernoclient.Clientset, client *client.Client, tlsPair *tlsutils.TlsPemPair, pInformer informer.PolicyInformer, @@ -53,6 +56,7 @@ func NewWebhookServer( ws := &WebhookServer{ client: client, + kyvernoClient: kyvernoClient, pLister: pInformer.Lister(), eventGen: eventGen, filterK8Resources: utils.ParseKinds(filterK8Resources), diff --git a/pkg/webhooks/validation.go b/pkg/webhooks/validation.go index 75f12ffa2d..23e733e2eb 100644 --- a/pkg/webhooks/validation.go +++ b/pkg/webhooks/validation.go @@ -84,8 +84,6 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1 ws.eventGen.Add(eventsInfo...) } - // ADD POLICY VIOLATIONS - ok, msg := isAdmSuccesful(policyInfos) if !ok && toBlock(policyInfos) { return &v1beta1.AdmissionResponse{ @@ -96,6 +94,9 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1 } } + // ADD POLICY VIOLATIONS + generatePolicyViolations(ws.kyvernoClient, policyInfos) + return &v1beta1.AdmissionResponse{ Allowed: true, }