1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-31 03:45:17 +00:00

create event from policy info

This commit is contained in:
Shuting Zhao 2019-06-26 18:04:50 -07:00
parent 059993a78f
commit b63b3b869e
14 changed files with 212 additions and 44 deletions

View file

@ -16,4 +16,4 @@ spec:
containers:
# if the image tag is latest, set the imagePullPolicy to Always
- (image): "*:latest"
imagePullPolicy: "Always"
imagePullPolicy: "IfNotPresent"

View file

@ -51,7 +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, filterK8Kinds)
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, eventController, filterK8Kinds)
if err != nil {
glog.Fatalf("Unable to create webhook server: %v\n", err)
}

View file

@ -17,7 +17,7 @@ import (
// ProcessExisting checks for mutation and validation violations of existing resources
func ProcessExisting(client *client.Client, policy *types.Policy) []*info.PolicyInfo {
glog.Info("Applying policy %s on existing resources", policy.Name)
glog.Infof("Applying policy %s on existing resources", policy.Name)
// policyInfo := info.NewPolicyInfo(policy.Name,
// rname,
// rns)
@ -58,7 +58,7 @@ func ProcessExisting(client *client.Client, policy *types.Policy) []*info.Policy
policyInfo, err := applyPolicy(client, policy, r)
if err != nil {
glog.Error("unable to apply policy %s on resource %s/%s", policy.Name, r.resource.GetName(), r.resource.GetNamespace())
glog.Errorf("unable to apply policy %s on resource %s/%s", policy.Name, r.resource.GetName(), r.resource.GetNamespace())
glog.Error(err)
continue
}
@ -69,7 +69,10 @@ func ProcessExisting(client *client.Client, policy *types.Policy) []*info.Policy
}
func applyPolicy(client *client.Client, policy *types.Policy, res *resourceInfo) (*info.PolicyInfo, error) {
policyInfo := info.NewPolicyInfo(policy.Name, res.resource.GetName(), res.resource.GetNamespace())
policyInfo := info.NewPolicyInfo(policy.Name, res.resource.GetName(),
res.resource.GroupVersionKind().Kind,
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 {

View file

@ -30,9 +30,9 @@ func Generate(client *client.Client, policy kubepolicy.Policy, rawResource []byt
err := applyRuleGenerator(client, rawResource, rule.Generation, gvk)
if err != nil {
ri.Fail()
ri.Addf(" Failed to apply rule generator. err %v", err)
ri.Addf("Rule %s: Failed to apply rule generator, err %v.", rule.Name, err)
} else {
ri.Add("Generation succesfully")
ri.Addf("Rule %s: Generation succesfully.", rule.Name)
}
ris = append(ris, ri)
}

View file

@ -29,9 +29,9 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
overlayPatches, err := ProcessOverlay(rule, rawResource, gvk)
if err != nil {
ri.Fail()
ri.Addf("Overlay application has failed. err %s", err)
ri.Addf("Rule %s: Overlay application has failed, err %s.", rule.Name, err)
} else {
ri.Add("Overlay succesfully applied")
ri.Addf("Rule %s: Overlay succesfully applied.", rule.Name)
//TODO: patchbytes -> string
//glog.V(3).Info(" Overlay succesfully applied. Patch %s", string(overlayPatches))
allPatches = append(allPatches, overlayPatches...)
@ -44,10 +44,10 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
if len(errs) > 0 {
ri.Fail()
for _, err := range errs {
ri.Addf("Patches application has failed. err %s", err)
ri.Addf("Rule %s: Patches application has failed, err %s.", rule.Name, err)
}
} else {
ri.Add("Patches succesfully applied")
ri.Addf("Rule %s: Patches succesfully applied.", rule.Name)
//TODO: patchbytes -> string
//glog.V(3).Info("Patches succesfully applied. Patch %s", string(overlayPatches))
allPatches = append(allPatches, rulePatches...)

View file

@ -41,9 +41,9 @@ func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
err := validateResourceWithPattern(resource, rule.Validation.Pattern)
if err != nil {
ri.Fail()
ri.Addf("Validation has failed. err %s", err)
ri.Addf("Rule %s: Validation has failed, err %s.", rule.Name, err)
} else {
ri.Add("Validation succesfully")
ri.Addf("Rule %s: Validation succesfully.", rule.Name)
}
ris = append(ris, ri)

View file

@ -9,7 +9,6 @@ import (
policyscheme "github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
v1alpha1 "github.com/nirmata/kyverno/pkg/client/listers/policy/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/result"
"github.com/nirmata/kyverno/pkg/sharedinformer"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
@ -30,7 +29,7 @@ type controller struct {
//Generator to generate event
type Generator interface {
Add(info Info)
Add(infoList []*Info)
}
//Controller api
@ -76,8 +75,10 @@ func initRecorder(client *client.Client) record.EventRecorder {
return recorder
}
func (c *controller) Add(info Info) {
c.queue.Add(info)
func (c *controller) Add(infoList []*Info) {
for _, info := range infoList {
c.queue.Add(*info)
}
}
func (c *controller) Run(stopCh <-chan struct{}) {
@ -158,13 +159,14 @@ func (c *controller) SyncHandler(key Info) error {
return nil
}
//NewEvent returns a new event
func NewEvent(kind string, resource string, reason result.Reason, message MsgKey, args ...interface{}) Info {
msgText, err := getEventMsg(message, args)
// NewEvent returns a new event
// resource contains namespace/resourceName
func NewEvent(kind string, resource string, reason Reason, message MsgKey, args ...interface{}) *Info {
msgText, err := getEventMsg(message, args...)
if err != nil {
glog.Error(err)
}
return Info{
return &Info{
Kind: kind,
Resource: resource,
Reason: reason.String(),

View file

@ -7,11 +7,11 @@ import (
func (k MsgKey) String() string {
return [...]string{
"Failed to satisfy policy on resource %s.The following rules %s failed to apply. Created Policy Violation",
"Failed to satisfy policy on resource %s.The following rule(s) %s failed to apply. Created Policy Violation",
"Failed to process rule %s of policy %s. Created Policy Violation %s",
"Policy applied successfully on the resource %s",
"Rule %s of Policy %s applied successful",
"Failed to apply policy, blocked creation of resource %s. The following rules %s failed to apply",
"Rule(s) %s of Policy %s applied successful",
"Creation of resource %s blocked by rule(s) %s",
"Failed to apply rule %s of policy %s Blocked update of the resource",
"Failed to apply policy on resource %s.Blocked update of the resource. The following rules %s failed to apply",
}[k]

View file

@ -22,7 +22,7 @@ const (
FResourcePolcy MsgKey = iota
FProcessRule
SPolicyApply
SRuleApply
SRulesApply
FPolicyApplyBlockCreate
FPolicyApplyBlockUpdate
FPolicyApplyBlockUpdateRule

View file

@ -7,18 +7,25 @@ import (
//PolicyInfo defines policy information
type PolicyInfo struct {
Name string
Resource string
// Name is policy name
Name string
// Resource is resource name
Resource string
// Kind represents the resource kind
Kind string
// Namespace is the ns of resource
// empty on non-namespaced resources
Namespace string
success bool
Rules []*RuleInfo
}
//NewPolicyInfo returns a new policy info
func NewPolicyInfo(policyName string, resource string, ns string) *PolicyInfo {
func NewPolicyInfo(policyName, resource, kind, ns string) *PolicyInfo {
return &PolicyInfo{
Name: policyName,
Resource: resource,
Kind: kind,
Namespace: ns,
success: true, // fail to be set explicity
}

View file

@ -16,6 +16,7 @@ import (
"github.com/nirmata/kyverno/pkg/config"
client "github.com/nirmata/kyverno/pkg/dclient"
engine "github.com/nirmata/kyverno/pkg/engine"
"github.com/nirmata/kyverno/pkg/event"
"github.com/nirmata/kyverno/pkg/info"
"github.com/nirmata/kyverno/pkg/sharedinformer"
tlsutils "github.com/nirmata/kyverno/pkg/tls"
@ -27,10 +28,11 @@ import (
// WebhookServer contains configured TLS server with MutationWebhook.
// MutationWebhook gets policies from policyController and takes control of the cluster with kubeclient.
type WebhookServer struct {
server http.Server
client *client.Client
policyLister v1alpha1.PolicyLister
filterKinds []string
server http.Server
client *client.Client
policyLister v1alpha1.PolicyLister
eventController event.Generator
filterKinds []string
}
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
@ -39,6 +41,7 @@ func NewWebhookServer(
client *client.Client,
tlsPair *tlsutils.TlsPemPair,
shareInformer sharedinformer.PolicyInformer,
eventController event.Generator,
filterKinds []string) (*WebhookServer, error) {
if tlsPair == nil {
@ -53,9 +56,10 @@ func NewWebhookServer(
tlsConfig.Certificates = []tls.Certificate{pair}
ws := &WebhookServer{
client: client,
policyLister: shareInformer.GetLister(),
filterKinds: parseKinds(filterKinds),
client: client,
policyLister: shareInformer.GetLister(),
eventController: eventController,
filterKinds: parseKinds(filterKinds),
}
mux := http.NewServeMux()
mux.HandleFunc(config.MutatingWebhookServicePath, ws.serve)
@ -152,9 +156,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
}
rname := engine.ParseNameFromObject(request.Object.Raw)
rns := engine.ParseNamespaceFromObject(request.Object.Raw)
policyInfo := info.NewPolicyInfo(policy.Name,
rname,
rns)
policyInfo := info.NewPolicyInfo(policy.Name, rname, request.Kind.Kind, rns)
glog.V(3).Infof("Handling mutation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, rns, rname, request.UID, request.Operation)
@ -162,7 +164,9 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
glog.Infof("Applying policy %s with %d rules\n", policy.ObjectMeta.Name, len(policy.Spec.Rules))
policyPatches, ruleInfos := engine.Mutate(*policy, request.Object.Raw, request.Kind)
policyInfo.AddRuleInfos(ruleInfos)
if !policyInfo.IsSuccessful() {
glog.Infof("Failed to apply policy %s on resource %s/%s", policy.Name, rname, rns)
for _, r := range ruleInfos {
@ -175,6 +179,9 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
policyInfos = append(policyInfos, policyInfo)
}
eventsInfo := NewEventInfoFromPolicyInfo(policyInfos)
ws.eventController.Add(eventsInfo)
ok, msg := isAdmSuccesful(policyInfos)
if ok {
patchType := v1beta1.PatchTypeJSONPatch
@ -230,9 +237,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
rname := engine.ParseNameFromObject(request.Object.Raw)
rns := engine.ParseNamespaceFromObject(request.Object.Raw)
policyInfo := info.NewPolicyInfo(policy.Name,
rname,
rns)
policyInfo := info.NewPolicyInfo(policy.Name, rname, request.Kind.Kind, rns)
glog.V(3).Infof("Handling validation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, rns, rname, request.UID, request.Operation)
@ -299,9 +304,7 @@ func (ws *WebhookServer) HandleGeneration(request *v1beta1.AdmissionRequest) *v1
rname := engine.ParseNameFromObject(request.Object.Raw)
rns := engine.ParseNamespaceFromObject(request.Object.Raw)
policyInfo := info.NewPolicyInfo(policy.Name,
rname,
rns)
policyInfo := info.NewPolicyInfo(policy.Name, rname, request.Kind.Kind, rns)
glog.V(3).Infof("Handling generation for Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, rns, rname, request.UID, request.Operation)
glog.Infof("Applying policy %s with generation %d rules", policy.ObjectMeta.Name, len(policy.Spec.Rules))
@ -364,3 +367,49 @@ func (ws *WebhookServer) bodyToAdmissionReview(request *http.Request, writer htt
return admissionReview
}
const policyKind = "Policy"
func NewEventInfoFromPolicyInfo(policyInfoList []*info.PolicyInfo) []*event.Info {
var eventsInfo []*event.Info
ok, msg := isAdmSuccesful(policyInfoList)
if ok {
for _, pi := range policyInfoList {
ruleNames := getRuleNames(*pi, true)
eventsInfo = append(eventsInfo,
event.NewEvent(pi.Kind, pi.Namespace+"/"+pi.Resource, event.PolicyApplied, event.SRulesApply, ruleNames, pi.Name))
eventsInfo = append(eventsInfo,
event.NewEvent(policyKind, pi.Name, event.PolicyApplied, event.SPolicyApply, pi.Name, pi.Resource))
glog.V(3).Infof("Success events info prepared for %s/%s and %s/%s\n", policyKind, pi.Name, pi.Kind, pi.Resource)
}
return eventsInfo
}
for _, pi := range policyInfoList {
ruleNames := getRuleNames(*pi, false)
eventsInfo = append(eventsInfo,
event.NewEvent(policyKind, pi.Name, event.RequestBlocked, event.FPolicyApplyBlockCreate, pi.Resource, ruleNames))
glog.V(3).Infof("Rule(s) %s of policy %s blocked resource creation, error: %s\n", ruleNames, pi.Name, msg)
}
return eventsInfo
}
func getRuleNames(policyInfo info.PolicyInfo, onSuccess bool) string {
var ruleNames []string
for _, rule := range policyInfo.Rules {
if onSuccess {
if rule.IsSuccessful() {
ruleNames = append(ruleNames, rule.Name)
}
} else {
if !rule.IsSuccessful() {
ruleNames = append(ruleNames, rule.Name)
}
}
}
return strings.Join(ruleNames, ",")
}

View file

@ -34,3 +34,4 @@ chmod +x "${certsGenerator}"
${certsGenerator} "--service=${service}" "--serverIP=${serverIP}" || exit 2
echo -e "\n### You can build and run kyverno project locally.\n### To check its work, run it with flags --kubeconfig and --serverIP parameters."
sudo ./kyverno --kubeconfig ~/.kube/config --serverIP=10.0.0.11 -v 4

25
test/mix/nginx.yaml Normal file
View file

@ -0,0 +1,25 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
cli: test
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nirmata/nginx:green
# imagePullPolicy: Always
ports:
- containerPort: 80
- name: nginx1
image: launcher.gcr.io/google/nginx1

81
test/mix/policy.yaml Normal file
View file

@ -0,0 +1,81 @@
apiVersion : kyverno.io/v1alpha1
kind : Policy
metadata :
name : policy-deployment
spec :
rules:
- name: add-label
resource:
kinds :
- Deployment
selector :
matchLabels :
cli: test
mutate:
patches:
- path: /metadata/labels/isMutated
op: add
value: "true"
overlay:
spec:
template:
spec:
containers:
# if the image nginx, set the imagePullPolicy to Always
- (image): "*nginx*"
imagePullPolicy: "Always"
- name: add-label2
resource:
kinds :
- Deployment
selector :
matchLabels :
cli: test
mutate:
patches:
- path: /metadata/labels/app1
op: replace
value: "nginx_is_mutated"
- name: add-label3
resource:
kinds :
- Deployment
selector :
matchLabels :
cli: test
mutate:
patches:
- path: /metadata/labels/app2
op: add
value: "nginx_is_mutated2"
- name: check-image
resource:
kinds :
- Deployment
selector :
matchLabels :
cli: test
validate:
message: "The imagePullPolicy must be Always when using image nginx"
pattern:
spec:
template:
spec:
containers:
- (image): "*nginx*"
imagePullPolicy: "Always"
- name: check-registries
resource:
kinds:
- Deployment
- StatefulSet
validate:
message: "Registry is not allowed"
pattern:
spec:
template:
spec:
containers:
- name: "*"
# Check allowed registries
image: "*nirmata/* | launcher.gcr.io/*"