mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +00:00
policy violation support (incomplete)
This commit is contained in:
parent
2cdeac5988
commit
a5e1b43eb7
6 changed files with 120 additions and 17 deletions
2
main.go
2
main.go
|
@ -77,7 +77,7 @@ func main() {
|
|||
if err != nil {
|
||||
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
|
||||
}
|
||||
server, err := webhooks.NewWebhookServer(pclient, client, tlsPair, pInformer.Kyverno().V1alpha1().Policies(), egen, filterK8Resources)
|
||||
server, err := webhooks.NewWebhookServer(pclient, client, tlsPair, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations(), egen, filterK8Resources)
|
||||
if err != nil {
|
||||
glog.Fatalf("Unable to create webhook server: %v\n", err)
|
||||
}
|
||||
|
|
|
@ -101,3 +101,11 @@ func (gen *Generation) DeepCopyInto(out *Generation) {
|
|||
*out = *gen
|
||||
}
|
||||
}
|
||||
|
||||
//ToKey generates the key string used for adding label to polivy violation
|
||||
func (rs ResourceSpec) ToKey() string {
|
||||
if rs.Namespace == "" {
|
||||
return rs.Kind + "." + rs.Name
|
||||
}
|
||||
return rs.Kind + "." + rs.Namespace + "." + rs.Name
|
||||
}
|
||||
|
|
|
@ -716,7 +716,7 @@ type patchLabelMapValue struct {
|
|||
Value map[string]string `json:"value"`
|
||||
}
|
||||
|
||||
func createLabelPatch(policy string) ([]byte, error) {
|
||||
func createPolicyLabelPatch(policy string) ([]byte, error) {
|
||||
payload := []patchLabelValue{{
|
||||
Op: "add",
|
||||
Path: "/metadata/labels/policy",
|
||||
|
@ -725,11 +725,20 @@ func createLabelPatch(policy string) ([]byte, error) {
|
|||
return json.Marshal(payload)
|
||||
}
|
||||
|
||||
func createLabelMapPatch(policy string) ([]byte, error) {
|
||||
func createResourceLabelPatch(resource string) ([]byte, error) {
|
||||
payload := []patchLabelValue{{
|
||||
Op: "add",
|
||||
Path: "/metadata/labels/resource",
|
||||
Value: resource,
|
||||
}}
|
||||
return json.Marshal(payload)
|
||||
}
|
||||
|
||||
func createLabelMapPatch(policy string, resource string) ([]byte, error) {
|
||||
payload := []patchLabelMapValue{{
|
||||
Op: "add",
|
||||
Path: "/metadata/labels",
|
||||
Value: map[string]string{"policy": policy},
|
||||
Value: map[string]string{"policy": policy, "resource": resource},
|
||||
}}
|
||||
return json.Marshal(payload)
|
||||
}
|
||||
|
@ -739,6 +748,7 @@ func createLabelMapPatch(policy string) ([]byte, error) {
|
|||
func updatePolicyLabelIfNotDefined(pvControl PVControlInterface, pv *kyverno.PolicyViolation) bool {
|
||||
updateLabel := func() bool {
|
||||
glog.V(4).Infof("adding label 'policy:%s' to PolicyViolation %s", pv.Spec.Policy, pv.Name)
|
||||
glog.V(4).Infof("adding label 'resource:%s' to PolicyViolation %s", pv.Spec.ResourceSpec.ToKey(), pv.Name)
|
||||
// add label based on the policy spec
|
||||
labels := pv.GetLabels()
|
||||
if pv.Spec.Policy == "" {
|
||||
|
@ -748,7 +758,7 @@ func updatePolicyLabelIfNotDefined(pvControl PVControlInterface, pv *kyverno.Pol
|
|||
}
|
||||
if labels == nil {
|
||||
// create a patch to generate the labels map with policy label
|
||||
patch, err := createLabelMapPatch(pv.Spec.Policy)
|
||||
patch, err := createLabelMapPatch(pv.Spec.Policy, pv.Spec.ResourceSpec.ToKey())
|
||||
if err != nil {
|
||||
glog.Errorf("unable to init label map. %v", err)
|
||||
return false
|
||||
|
@ -761,11 +771,23 @@ func updatePolicyLabelIfNotDefined(pvControl PVControlInterface, pv *kyverno.Pol
|
|||
return true
|
||||
}
|
||||
// JSON Patch to add exact label
|
||||
labelPatch, err := createLabelPatch(pv.Spec.Policy)
|
||||
policyLabelPatch, err := createPolicyLabelPatch(pv.Spec.Policy)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to generate patch to add label 'policy': %v", err)
|
||||
return false
|
||||
}
|
||||
resourceLabelPatch, err := createResourceLabelPatch(pv.Spec.ResourceSpec.ToKey())
|
||||
if err != nil {
|
||||
glog.Errorf("failed to generate patch to add label 'resource': %v", err)
|
||||
return false
|
||||
}
|
||||
//join patches
|
||||
labelPatch := joinPatches(policyLabelPatch, resourceLabelPatch)
|
||||
if labelPatch == nil {
|
||||
glog.Errorf("failed to join patches : %v", err)
|
||||
return false
|
||||
}
|
||||
glog.V(4).Infof("patching policy violation %s with patch %s", pv.Name, string(labelPatch))
|
||||
if err := pvControl.PatchPolicyViolation(pv.Name, labelPatch); err != nil {
|
||||
glog.Errorf("Unable to add 'policy' label to PolicyViolation %s: %v", pv.Name, err)
|
||||
return false
|
||||
|
@ -789,3 +811,20 @@ func updatePolicyLabelIfNotDefined(pvControl PVControlInterface, pv *kyverno.Pol
|
|||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func joinPatches(patches ...[]byte) []byte {
|
||||
var result []byte
|
||||
if patches == nil {
|
||||
//nothing tot join
|
||||
return result
|
||||
}
|
||||
result = append(result, []byte("[\n")...)
|
||||
for index, patch := range patches {
|
||||
result = append(result, patch...)
|
||||
if index != len(patches)-1 {
|
||||
result = append(result, []byte(",\n")...)
|
||||
}
|
||||
}
|
||||
result = append(result, []byte("\n]")...)
|
||||
return result
|
||||
}
|
||||
|
|
|
@ -1,13 +1,16 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"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"
|
||||
lister "github.com/nirmata/kyverno/pkg/clientNew/listers/kyverno/v1alpha1"
|
||||
"github.com/nirmata/kyverno/pkg/violation"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/nirmata/kyverno/pkg/event"
|
||||
|
@ -122,7 +125,7 @@ func buildPolicyViolationsForAPolicy(pi info.PolicyInfo) kyverno.PolicyViolation
|
|||
}
|
||||
|
||||
//generatePolicyViolations generate policyViolation resources for the rules that failed
|
||||
func generatePolicyViolations(client *kyvernoclient.Clientset, policyInfos []info.PolicyInfo) {
|
||||
func generatePolicyViolations(pvLister lister.PolicyViolationLister, client *kyvernoclient.Clientset, policyInfos []info.PolicyInfo) {
|
||||
var pvs []kyverno.PolicyViolation
|
||||
for _, policyInfo := range policyInfos {
|
||||
if !policyInfo.IsSuccessful() {
|
||||
|
@ -138,15 +141,65 @@ func generatePolicyViolations(client *kyvernoclient.Clientset, policyInfos []inf
|
|||
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
|
||||
// }
|
||||
curPv, err := getExistingPolicyViolationIfAny(pvLister, newPv)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if curPv == nil {
|
||||
// no existing policy violation, create a new one
|
||||
_, err := client.KyvernoV1alpha1().PolicyViolations().Create(&newPv)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
// compare the policyviolation spec for existing resource if present else
|
||||
if reflect.DeepEqual(curPv.Spec, newPv.Spec) {
|
||||
// if they are equal there has been no change so dont update the polivy violation
|
||||
glog.Infof("policy violation spec %v did not change so not updating it", newPv.Spec)
|
||||
continue
|
||||
}
|
||||
// spec changed so update the policyviolation
|
||||
//TODO: wont work, as name is not defined yet
|
||||
_, err = client.KyvernoV1alpha1().PolicyViolations().Update(&newPv)
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
continue
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//TODO: change the name
|
||||
func getExistingPolicyViolationIfAny(pvLister lister.PolicyViolationLister, newPv kyverno.PolicyViolation) (*kyverno.PolicyViolation, error) {
|
||||
// TODO: check for existing ov using label selectors on resource and policy
|
||||
labelMap := map[string]string{"policy": newPv.Spec.Name, "resource": newPv.Spec.ResourceSpec.ToKey()}
|
||||
ls := &metav1.LabelSelector{}
|
||||
err := metav1.Convert_Map_string_To_string_To_v1_LabelSelector(&labelMap, ls, nil)
|
||||
if err != nil {
|
||||
glog.Errorf("failed to generate label sector of Policy name %s: %v", newPv.Spec.Policy, err)
|
||||
return nil, err
|
||||
}
|
||||
policyViolationSelector, err := metav1.LabelSelectorAsSelector(ls)
|
||||
if err != nil {
|
||||
glog.Errorf("invalid label selector: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pvs, err := pvLister.List(policyViolationSelector)
|
||||
if err != nil {
|
||||
glog.Errorf("unable to list policy violations with label selector %v: %v", policyViolationSelector, err)
|
||||
return nil, err
|
||||
}
|
||||
//TODO: ideally there should be only one policy violation returned
|
||||
if len(pvs) > 1 {
|
||||
glog.Errorf("more than one policy violation exists with labels %v", labelMap)
|
||||
return nil, fmt.Errorf("more than one policy violation exists with labels %v", labelMap)
|
||||
}
|
||||
|
||||
if len(pvs) == 0 {
|
||||
glog.Infof("policy violation does not exist with labels %v", labelMap)
|
||||
return nil, nil
|
||||
}
|
||||
return pvs[0], nil
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ type WebhookServer struct {
|
|||
client *client.Client
|
||||
kyvernoClient *kyvernoclient.Clientset
|
||||
pLister lister.PolicyLister
|
||||
pvLister lister.PolicyViolationLister
|
||||
eventGen event.Interface
|
||||
filterK8Resources []utils.K8Resource
|
||||
}
|
||||
|
@ -40,6 +41,7 @@ func NewWebhookServer(
|
|||
client *client.Client,
|
||||
tlsPair *tlsutils.TlsPemPair,
|
||||
pInformer informer.PolicyInformer,
|
||||
pvInormer informer.PolicyViolationInformer,
|
||||
eventGen event.Interface,
|
||||
filterK8Resources string) (*WebhookServer, error) {
|
||||
|
||||
|
@ -58,6 +60,7 @@ func NewWebhookServer(
|
|||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
pLister: pInformer.Lister(),
|
||||
pvLister: pvInormer.Lister(),
|
||||
eventGen: eventGen,
|
||||
filterK8Resources: utils.ParseKinds(filterK8Resources),
|
||||
}
|
||||
|
|
|
@ -95,7 +95,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
|
|||
}
|
||||
|
||||
// ADD POLICY VIOLATIONS
|
||||
generatePolicyViolations(ws.kyvernoClient, policyInfos)
|
||||
generatePolicyViolations(ws.pvLister, ws.kyvernoClient, policyInfos)
|
||||
|
||||
return &v1beta1.AdmissionResponse{
|
||||
Allowed: true,
|
||||
|
|
Loading…
Reference in a new issue