mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-06 16:06:56 +00:00
# Conflicts: # pkg/engine/engine.go # pkg/event/controller.go # pkg/event/msgbuilder.go # pkg/event/util.go # pkg/info/info.go # pkg/webhooks/server.go
124 lines
4.3 KiB
Go
124 lines
4.3 KiB
Go
package engine
|
|
|
|
import (
|
|
jsonpatch "github.com/evanphx/json-patch"
|
|
"github.com/golang/glog"
|
|
"github.com/minio/minio/pkg/wildcard"
|
|
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
|
|
client "github.com/nirmata/kyverno/pkg/dclient"
|
|
"github.com/nirmata/kyverno/pkg/info"
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
)
|
|
|
|
// As the logic to process the policies in stateless, we do not need to define struct and implement behaviors for it
|
|
// Instead we expose them as standalone functions passing the required atrributes
|
|
// The each function returns the changes that need to be applied on the resource
|
|
// the caller is responsible to apply the changes to the resource
|
|
|
|
// ProcessExisting checks for mutation and validation violations of existing resources
|
|
func ProcessExisting(client *client.Client, policy *types.Policy) []*info.PolicyInfo {
|
|
glog.Infof("Applying policy %s on existing resources", policy.Name)
|
|
// policyInfo := info.NewPolicyInfo(policy.Name,
|
|
// rname,
|
|
// rns)
|
|
resources := []*resourceInfo{}
|
|
|
|
for _, rule := range policy.Spec.Rules {
|
|
for _, k := range rule.Kinds {
|
|
// kind -> resource
|
|
gvr := client.DiscoveryClient.GetGVRFromKind(k)
|
|
// label selectors
|
|
// namespace ? should it be default or allow policy to specify it
|
|
list, err := client.ListResource(gvr.Resource, "default", rule.ResourceDescription.Selector)
|
|
if err != nil {
|
|
glog.Errorf("unable to list resource for %s with label selector %s", gvr.Resource, rule.Selector.String())
|
|
glog.Errorf("unable to apply policy %s rule %s. err: %s", policy.Name, rule.Name, err)
|
|
continue
|
|
}
|
|
for _, res := range list.Items {
|
|
name := rule.ResourceDescription.Name
|
|
gvk := res.GroupVersionKind()
|
|
if name != nil {
|
|
// wild card matching
|
|
if !wildcard.Match(*name, res.GetName()) {
|
|
continue
|
|
}
|
|
}
|
|
ri := &resourceInfo{resource: &res, gvk: &metav1.GroupVersionKind{Group: gvk.Group,
|
|
Version: gvk.Version,
|
|
Kind: gvk.Kind}}
|
|
resources = append(resources, ri)
|
|
|
|
}
|
|
}
|
|
}
|
|
policyInfos := []*info.PolicyInfo{}
|
|
// for the filtered resource apply policy
|
|
for _, r := range resources {
|
|
|
|
policyInfo, err := applyPolicy(client, policy, r)
|
|
if err != nil {
|
|
glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, r.resource.GetName(), r.resource.GetNamespace())
|
|
glog.Error(err)
|
|
continue
|
|
}
|
|
policyInfos = append(policyInfos, policyInfo)
|
|
}
|
|
|
|
return policyInfos
|
|
}
|
|
|
|
func applyPolicy(client *client.Client, policy *types.Policy, res *resourceInfo) (*info.PolicyInfo, error) {
|
|
policyInfo := info.NewPolicyInfo(policy.Name, res.gvk.Kind, res.resource.GetName(), res.resource.GetNamespace())
|
|
glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
|
|
rawResource, err := res.resource.MarshalJSON()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Mutate
|
|
mruleInfos, err := mutation(policy, rawResource, res.gvk)
|
|
policyInfo.AddRuleInfos(mruleInfos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Validation
|
|
vruleInfos, err := Validate(*policy, rawResource, *res.gvk)
|
|
policyInfo.AddRuleInfos(vruleInfos)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// Generate
|
|
gruleInfos := Generate(client, *policy, rawResource, *res.gvk, false)
|
|
policyInfo.AddRuleInfos(gruleInfos)
|
|
|
|
return policyInfo, nil
|
|
}
|
|
|
|
func mutation(p *types.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
|
|
patches, ruleInfos := Mutate(*p, rawResource, *gvk)
|
|
// option 2: (original Resource + patch) compare with (original resource)
|
|
mergePatches := JoinPatches(patches)
|
|
// merge the patches
|
|
patch, err := jsonpatch.DecodePatch(mergePatches)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// apply the patches returned by mutate to the original resource
|
|
patchedResource, err := patch.Apply(rawResource)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
// compare (original Resource + patch) vs (original resource)
|
|
// to verify if they are equal
|
|
ruleInfo := info.NewRuleInfo("over-all mutation", info.Mutation)
|
|
if !jsonpatch.Equal(patchedResource, rawResource) {
|
|
//resource does not match so there was a mutation rule violated
|
|
// TODO : check the rule name "mutation rules"
|
|
ruleInfo.Fail()
|
|
ruleInfo.Add("resource does not satisfy mutation rules")
|
|
} else {
|
|
ruleInfo.Add("resource satisfys the mutation rule")
|
|
}
|
|
ruleInfos = append(ruleInfos, ruleInfo)
|
|
return ruleInfos, nil
|
|
}
|