1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2025-03-13 11:18:47 +00:00

merge the changes with policy-engine

This commit is contained in:
shivdudhani 2019-05-10 12:36:55 -07:00
commit 6d83aa6b9e
19 changed files with 616 additions and 39 deletions

View file

@ -206,7 +206,34 @@ var rMapper = map[string]getter{
"StatefulSet": statefulSetGetter,
}
var lMapper = map[string]lister{
"ConfigMap": configMapLister,
"Pods": podLister,
"Deployment": deploymentLister,
"CronJob": cronJobLister,
"Endpoints": endpointsLister,
"HorizontalPodAutoscaler": horizontalPodAutoscalerLister,
"Ingress": ingressLister,
"Job": jobLister,
"LimitRange": limitRangeLister,
"Namespace": namespaceLister,
"NetworkPolicy": networkPolicyLister,
"PersistentVolumeClaim": persistentVolumeClaimLister,
"PodDisruptionBudget": podDisruptionBudgetLister,
"PodTemplate": podTemplateLister,
"ResourceQuota": resourceQuotaLister,
"Secret": secretLister,
"Service": serviceLister,
"StatefulSet": statefulSetLister,
}
type getter func(*kubernetes.Clientset, string, string) (runtime.Object, error)
type lister func(*kubernetes.Clientset, string) ([]runtime.Object, error)
//ListResource to return resource list
func (kc *KubeClient) ListResource(kind string, namespace string) ([]runtime.Object, error) {
return lMapper[kind](kc.client, namespace)
}
//GetResource get the resource object
func (kc *KubeClient) GetResource(kind string, resource string) (runtime.Object, error) {
@ -233,6 +260,19 @@ func configMapGetter(clientSet *kubernetes.Clientset, namespace string, name str
}
return obj, nil
}
func configMapLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().ConfigMaps(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func podsGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().Pods(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -241,6 +281,18 @@ func podsGetter(clientSet *kubernetes.Clientset, namespace string, name string)
return obj, nil
}
func podLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().Pods(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func deploymentGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.AppsV1().Deployments(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -248,6 +300,17 @@ func deploymentGetter(clientSet *kubernetes.Clientset, namespace string, name st
}
return obj, nil
}
func deploymentLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.AppsV1().Deployments(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func cronJobGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.BatchV1beta1().CronJobs(namespace).Get(name, metav1.GetOptions{})
@ -257,6 +320,18 @@ func cronJobGetter(clientSet *kubernetes.Clientset, namespace string, name strin
return obj, nil
}
func cronJobLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.BatchV1beta1().CronJobs(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func endpointsbGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().Endpoints(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -265,6 +340,18 @@ func endpointsbGetter(clientSet *kubernetes.Clientset, namespace string, name st
return obj, nil
}
func endpointsLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().Endpoints(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func horizontalPodAutoscalerGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.AutoscalingV1().HorizontalPodAutoscalers(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -273,6 +360,18 @@ func horizontalPodAutoscalerGetter(clientSet *kubernetes.Clientset, namespace st
return obj, nil
}
func horizontalPodAutoscalerLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.AutoscalingV1().HorizontalPodAutoscalers(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func ingressGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.ExtensionsV1beta1().Ingresses(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -281,6 +380,18 @@ func ingressGetter(clientSet *kubernetes.Clientset, namespace string, name strin
return obj, nil
}
func ingressLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.ExtensionsV1beta1().Ingresses(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func jobGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.BatchV1().Jobs(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -289,6 +400,18 @@ func jobGetter(clientSet *kubernetes.Clientset, namespace string, name string) (
return obj, nil
}
func jobLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.BatchV1().Jobs(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func limitRangeGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().LimitRanges(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -296,6 +419,17 @@ func limitRangeGetter(clientSet *kubernetes.Clientset, namespace string, name st
}
return obj, nil
}
func limitRangeLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().LimitRanges(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func namespaceGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().Namespaces().Get(name, metav1.GetOptions{})
@ -305,6 +439,18 @@ func namespaceGetter(clientSet *kubernetes.Clientset, namespace string, name str
return obj, nil
}
func namespaceLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().Namespaces().List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func networkPolicyGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.NetworkingV1().NetworkPolicies(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -313,6 +459,18 @@ func networkPolicyGetter(clientSet *kubernetes.Clientset, namespace string, name
return obj, nil
}
func networkPolicyLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.NetworkingV1().NetworkPolicies(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func persistentVolumeClaimGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().PersistentVolumeClaims(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -321,6 +479,18 @@ func persistentVolumeClaimGetter(clientSet *kubernetes.Clientset, namespace stri
return obj, nil
}
func persistentVolumeClaimLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().PersistentVolumeClaims(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func podDisruptionBudgetGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -329,6 +499,18 @@ func podDisruptionBudgetGetter(clientSet *kubernetes.Clientset, namespace string
return obj, nil
}
func podDisruptionBudgetLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.PolicyV1beta1().PodDisruptionBudgets(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func podTemplateGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().PodTemplates(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -337,6 +519,18 @@ func podTemplateGetter(clientSet *kubernetes.Clientset, namespace string, name s
return obj, nil
}
func podTemplateLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().PodTemplates(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func resourceQuotaGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().ResourceQuotas(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -345,6 +539,18 @@ func resourceQuotaGetter(clientSet *kubernetes.Clientset, namespace string, name
return obj, nil
}
func resourceQuotaLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().ResourceQuotas(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func secretGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().Secrets(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -353,6 +559,18 @@ func secretGetter(clientSet *kubernetes.Clientset, namespace string, name string
return obj, nil
}
func secretLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().Secrets(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func serviceGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.CoreV1().Services(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -361,6 +579,18 @@ func serviceGetter(clientSet *kubernetes.Clientset, namespace string, name strin
return obj, nil
}
func serviceLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.CoreV1().Services(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}
func statefulSetGetter(clientSet *kubernetes.Clientset, namespace string, name string) (runtime.Object, error) {
obj, err := clientSet.AppsV1().StatefulSets(namespace).Get(name, metav1.GetOptions{})
if err != nil {
@ -368,3 +598,15 @@ func statefulSetGetter(clientSet *kubernetes.Clientset, namespace string, name s
}
return obj, nil
}
func statefulSetLister(clientSet *kubernetes.Clientset, namespace string) ([]runtime.Object, error) {
list, err := clientSet.AppsV1().StatefulSets(namespace).List(metav1.ListOptions{})
if err != nil {
return nil, err
}
objList := []runtime.Object{}
for _, obj := range list.Items {
objList = append(objList, &obj)
}
return objList, nil
}

View file

@ -11,6 +11,7 @@ import (
policyclientset "github.com/nirmata/kube-policy/pkg/client/clientset/versioned"
informers "github.com/nirmata/kube-policy/pkg/client/informers/externalversions"
policyengine "github.com/nirmata/kube-policy/pkg/policyengine"
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
event "github.com/nirmata/kube-policy/pkg/event"
@ -45,9 +46,11 @@ func main() {
eventController := event.NewEventController(kubeclient, policyInformer.Lister(), nil)
violationBuilder := policyviolation.NewPolicyViolationBuilder(kubeclient, policyInformer.Lister(), policyClientset, eventController, nil)
policyEngine := policyengine.NewPolicyEngine(kubeclient, nil)
policyController := policycontroller.NewPolicyController(policyClientset,
policyInformer,
policyEngine,
violationBuilder,
eventController,
nil,

View file

@ -92,6 +92,4 @@ type Violation struct {
Kind string `json:"kind,omitempty"`
Resource string `json:"resource,omitempty"`
Rule string `json:"rule,omitempty"`
Reason string `json:"reason,omitempty"`
Message string `json:"message,omitempty`
}

View file

@ -29,7 +29,7 @@ type controller struct {
//Generator to generate event
type Generator interface {
Add(kind string, resource string, reason Reason, message MsgKey, args ...interface{})
Add(info Info)
}
//Controller api
@ -66,13 +66,8 @@ func initRecorder(kubeClient *kubeClient.KubeClient) record.EventRecorder {
return recorder
}
func (c *controller) Add(kind string, resource string, reason Reason, message MsgKey, args ...interface{}) {
c.queue.Add(c.newEvent(
kind,
resource,
reason,
message,
))
func (c *controller) Add(info Info) {
c.queue.Add(info)
}
func (c *controller) Run(stopCh <-chan struct{}) error {
@ -103,9 +98,9 @@ func (c *controller) processNextWorkItem() bool {
}
err := func(obj interface{}) error {
defer c.queue.Done(obj)
var key eventInfo
var key Info
var ok bool
if key, ok = obj.(eventInfo); !ok {
if key, ok = obj.(Info); !ok {
c.queue.Forget(obj)
log.Printf("Expecting type info by got %v", obj)
return nil
@ -124,7 +119,7 @@ func (c *controller) processNextWorkItem() bool {
return true
}
func (c *controller) SyncHandler(key eventInfo) error {
func (c *controller) SyncHandler(key Info) error {
var resource runtime.Object
var err error
switch key.Kind {
@ -150,12 +145,13 @@ func (c *controller) SyncHandler(key eventInfo) error {
return nil
}
func (c *controller) newEvent(kind string, resource string, reason Reason, message MsgKey, args ...interface{}) eventInfo {
//NewEvent returns a new event
func NewEvent(kind string, resource string, reason Reason, message MsgKey, args ...interface{}) Info {
msgText, err := getEventMsg(message, args)
if err != nil {
utilruntime.HandleError(err)
}
return eventInfo{
return Info{
Kind: kind,
Resource: resource,
Reason: reason.String(),

View file

@ -6,7 +6,8 @@ const eventWorkQueueName = "policy-controller-events"
const eventWorkerThreadCount = 1
type eventInfo struct {
//Info defines the event details
type Info struct {
Kind string
Resource string
Reason string

View file

@ -0,0 +1,96 @@
package policyengine
import (
"errors"
"fmt"
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
)
func (p *policyEngine) ProcessMutation(policy types.Policy, rawResource []byte) ([]mutation.PatchBytes, error) {
patchingSets := mutation.GetPolicyPatchingSets(policy)
var policyPatches []mutation.PatchBytes
for ruleIdx, rule := range policy.Spec.Rules {
err := rule.Validate()
if err != nil {
p.logger.Printf("Invalid rule detected: #%s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
continue
}
if ok, err := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); !ok {
p.logger.Printf("Rule %d of policy %s is not applicable to the request", ruleIdx, policy.Name)
return nil, err
}
err = p.applyRuleGenerators(rawResource, rule)
if err != nil && patchingSets == mutation.PatchingSetsStopOnError {
return nil, fmt.Errorf("Failed to apply generators from rule #%s: %v", rule.Name, err)
}
rulePatchesProcessed, err := mutation.ProcessPatches(rule.Patches, rawResource, patchingSets)
if err != nil {
return nil, fmt.Errorf("Failed to process patches from rule #%s: %v", rule.Name, err)
}
if rulePatchesProcessed != nil {
policyPatches = append(policyPatches, rulePatchesProcessed...)
p.logger.Printf("Rule %d: prepared %d patches", ruleIdx, len(rulePatchesProcessed))
// TODO: add PolicyApplied events per rule for policy and resource
} else {
p.logger.Printf("Rule %d: no patches prepared", ruleIdx)
}
}
// empty patch, return error to deny resource creation
if policyPatches == nil {
return nil, fmt.Errorf("no patches prepared")
}
return policyPatches, nil
}
// Applies "configMapGenerator" and "secretGenerator" described in PolicyRule
func (p *policyEngine) applyRuleGenerators(rawResource []byte, rule types.PolicyRule) error {
kind := mutation.ParseKindFromObject(rawResource)
// configMapGenerator and secretGenerator can be applied only to namespaces
if kind == "Namespace" {
namespaceName := mutation.ParseNameFromObject(rawResource)
err := p.applyConfigGenerator(rule.ConfigMapGenerator, namespaceName, "ConfigMap")
if err == nil {
err = p.applyConfigGenerator(rule.SecretGenerator, namespaceName, "Secret")
}
return err
}
return nil
}
// Creates resourceKind (ConfigMap or Secret) with parameters specified in generator in cluster specified in request.
func (p *policyEngine) applyConfigGenerator(generator *types.PolicyConfigGenerator, namespace string, configKind string) error {
if generator == nil {
return nil
}
err := generator.Validate()
if err != nil {
return errors.New(fmt.Sprintf("Generator for '%s' is invalid: %s", configKind, err))
}
switch configKind {
case "ConfigMap":
err = p.kubeClient.GenerateConfigMap(*generator, namespace)
case "Secret":
err = p.kubeClient.GenerateSecret(*generator, namespace)
default:
err = errors.New(fmt.Sprintf("Unsupported config Kind '%s'", configKind))
}
if err != nil {
return errors.New(fmt.Sprintf("Unable to apply generator for %s '%s/%s' : %s", configKind, namespace, generator.Name, err))
}
return nil
}

View file

@ -8,10 +8,11 @@ import (
// kind is the type of object being manipulated
// Checks requests kind, name and labels to fit the policy
func IsRuleApplicableToResource(kind string, resourceRaw []byte, policyResource types.PolicyResource) (bool, error) {
if policyResource.Kind != kind {
return false, nil
}
func IsRuleApplicableToResource(resourceRaw []byte, policyResource types.PolicyResource) (bool, error) {
// kind := ParseKindFromObject(resourceRaw)
// if policyResource.Kind != kind {
// return false, nil
// }
if resourceRaw != nil {
meta := ParseMetadataFromObject(resourceRaw)

View file

@ -0,0 +1,103 @@
package policyengine
import (
"fmt"
"log"
kubeClient "github.com/nirmata/kube-policy/kubeclient"
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
event "github.com/nirmata/kube-policy/pkg/event"
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
)
type PolicyEngine interface {
// ProcessMutation should be called from admission contoller
// when there is an creation / update of the resource
// ProcessMutation(policy types.Policy, rawResource []byte) (patchBytes []byte, events []Events, err error)
ProcessMutation(policy types.Policy, rawResource []byte) ([]mutation.PatchBytes, error)
// ProcessValidation should be called from admission contoller
// when there is an creation / update of the resource
ProcessValidation(policy types.Policy, rawResource []byte)
// ProcessExisting should be called from policy controller
// when there is an create / update of the policy
// we should process the policy on matched resources, generate violations accordingly
ProcessExisting(policy types.Policy, rawResource []byte) ([]policyviolation.Info, []event.Info, error)
}
type policyEngine struct {
kubeClient *kubeClient.KubeClient
logger *log.Logger
}
func NewPolicyEngine(kubeClient *kubeClient.KubeClient, logger *log.Logger) PolicyEngine {
return &policyEngine{
kubeClient: kubeClient,
logger: logger,
}
}
func (p *policyEngine) ProcessExisting(policy types.Policy, rawResource []byte) ([]policyviolation.Info, []event.Info, error) {
var violations []policyviolation.Info
var events []event.Info
patchingSets := mutation.GetPolicyPatchingSets(policy)
for _, rule := range policy.Spec.Rules {
err := rule.Validate()
if err != nil {
p.logger.Printf("Invalid rule detected: #%s in policy %s, err: %v\n", rule.Name, policy.ObjectMeta.Name, err)
continue
}
if ok, err := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); !ok {
p.logger.Printf("Rule %s of policy %s is not applicable to the request", rule.Name, policy.Name)
return nil, nil, err
}
violation, eventInfos, err := p.processRuleOnResource(policy.Name, rule, rawResource, patchingSets)
if err != nil {
p.logger.Printf("Failed to process rule %s, err: %v\n", rule.Name, err)
continue
}
// } else {
// policyPatches = append(policyPatches, processedPatches...)
// }
violations = append(violations, violation)
events = append(events, eventInfos...)
}
return violations, events, nil
}
func (p *policyEngine) processRuleOnResource(policyName string, rule types.PolicyRule, rawResource []byte, patchingSets mutation.PatchingSets) (
policyviolation.Info, []event.Info, error) {
var violationInfo policyviolation.Info
var eventInfos []event.Info
resourceKind := mutation.ParseKindFromObject(rawResource)
resourceName := mutation.ParseNameFromObject(rawResource)
resourceNamespace := mutation.ParseNamespaceFromObject(rawResource)
rulePatchesProcessed, err := mutation.ProcessPatches(rule.Patches, nil, patchingSets)
if err != nil {
return violationInfo, eventInfos, fmt.Errorf("Failed to process patches from rule %s: %v", rule.Name, err)
}
if rulePatchesProcessed != nil {
log.Printf("Rule %s: prepared %d patches", rule.Name, len(rulePatchesProcessed))
violationInfo = policyviolation.NewViolation(policyName, resourceKind, resourceNamespace+"/"+resourceName, rule.Name)
// add a violation to queue
// add an event to policy
//TODO: event msg
eventInfos = append(eventInfos, event.NewEvent("Policy", policyName, event.PolicyViolation, event.FResourcePolcy))
// add an event to resource
eventInfos = append(eventInfos, event.NewEvent(resourceKind, resourceNamespace+"/"+resourceName, event.PolicyViolation, event.FResourcePolcy))
}
return violationInfo, eventInfos, nil
}

View file

@ -0,0 +1,5 @@
package policyengine
import types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
func (p *policyEngine) ProcessValidation(policy types.Policy, rawResource []byte) {}

View file

@ -15,7 +15,7 @@ import (
//Generator to generate policy violation
type Generator interface {
Add(info ViolationInfo) error
Add(info Info) error
}
type builder struct {
@ -29,7 +29,7 @@ type builder struct {
//Builder is to build policy violations
type Builder interface {
Generator
processViolation(info ViolationInfo) error
processViolation(info Info) error
isActive(kind string, resource string) (bool, error)
}
@ -51,11 +51,11 @@ func NewPolicyViolationBuilder(
return builder
}
func (b *builder) Add(info ViolationInfo) error {
func (b *builder) Add(info Info) error {
return b.processViolation(info)
}
func (b *builder) processViolation(info ViolationInfo) error {
func (b *builder) processViolation(info Info) error {
// Get the policy
namespace, name, err := cache.SplitMetaNamespaceKey(info.Policy)
if err != nil {
@ -71,13 +71,7 @@ func (b *builder) processViolation(info ViolationInfo) error {
modifiedViolations := []types.Violation{}
// Create new violation
newViolation := types.Violation{
Kind: info.Kind,
Resource: info.Resource,
Rule: info.Rule,
Reason: info.Reason,
Message: info.Message,
}
newViolation := info.Violation
for _, violation := range modifiedPolicy.Status.Violations {
ok, err := b.isActive(info.Kind, violation.Resource)
@ -111,3 +105,11 @@ func (b *builder) isActive(kind string, resource string) (bool, error) {
}
return true, nil
}
//NewViolation return new policy violation
func NewViolation(policyName string, kind string, resource string, rule string) Info {
return Info{Policy: policyName,
Violation: types.Violation{
Kind: kind, Resource: resource, Rule: rule},
}
}

View file

@ -12,7 +12,7 @@ const workqueueViolationName = "Policy-Violations"
const violationEventResrouce = "Violation"
//ViolationInfo describes the policyviolation details
type ViolationInfo struct {
type Info struct {
Policy string
policytype.Violation
}

View file

@ -11,8 +11,8 @@ import (
infomertypes "github.com/nirmata/kube-policy/pkg/client/informers/externalversions/policy/v1alpha1"
lister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
event "github.com/nirmata/kube-policy/pkg/event"
policyengine "github.com/nirmata/kube-policy/pkg/policyengine"
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@ -27,6 +27,7 @@ type PolicyController struct {
policyLister lister.PolicyLister
policyInterface policyclientset.Interface
policySynced cache.InformerSynced
policyEngine policyengine.PolicyEngine
violationBuilder policyviolation.Generator
eventBuilder event.Generator
logger *log.Logger
@ -36,6 +37,7 @@ type PolicyController struct {
// NewPolicyController from cmd args
func NewPolicyController(policyInterface policyclientset.Interface,
policyInformer infomertypes.PolicyInformer,
policyEngine policyengine.PolicyEngine,
violationBuilder policyviolation.Generator,
eventController event.Generator,
logger *log.Logger,
@ -46,6 +48,7 @@ func NewPolicyController(policyInterface policyclientset.Interface,
policyLister: policyInformer.Lister(),
policyInterface: policyInterface,
policySynced: policyInformer.Informer().HasSynced,
policyEngine: policyEngine,
violationBuilder: violationBuilder,
eventBuilder: eventController,
logger: logger,

View file

@ -0,0 +1,122 @@
package policycontroller
import (
"encoding/json"
"fmt"
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
event "github.com/nirmata/kube-policy/pkg/event"
"github.com/nirmata/kube-policy/pkg/policyengine/mutation"
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
)
func (pc *PolicyController) runForPolicy(key string) {
policy, err := pc.getPolicyByKey(key)
if err != nil {
utilruntime.HandleError(fmt.Errorf("invalid resource key: %s, err: %v", key, err))
return
}
if policy == nil {
pc.logger.Printf("Counld not find policy by key %s", key)
return
}
violations, events, err := pc.processPolicy(*policy)
if err != nil {
// add Error processing policy event
}
pc.logger.Printf("%v, %v", violations, events)
// TODO:
// create violations
// pc.violationBuilder.Add()
// create events
// pc.eventBuilder.Add()
}
// processPolicy process the policy to all the matched resources
func (pc *PolicyController) processPolicy(policy types.Policy) (
violations []policyviolation.Info, events []event.Info, err error) {
for _, rule := range policy.Spec.Rules {
resources, err := pc.filterResourceByRule(rule)
if err != nil {
pc.logger.Printf("Failed to filter resources by rule %s, err: %v\n", rule.Name, err)
}
for _, resource := range resources {
rawResource, err := json.Marshal(resource)
if err != nil {
pc.logger.Printf("Failed to marshal resources map to rule %s, err: %v\n", rule.Name, err)
continue
}
violation, eventInfos, err := pc.policyEngine.ProcessExisting(policy, rawResource)
if err != nil {
pc.logger.Printf("Failed to process rule %s, err: %v\n", rule.Name, err)
continue
}
violations = append(violations, violation...)
events = append(events, eventInfos...)
}
}
return violations, events, nil
}
func (pc *PolicyController) filterResourceByRule(rule types.PolicyRule) ([]runtime.Object, error) {
var targetResources []runtime.Object
// TODO: make this namespace all
var namespace = "default"
if err := rule.Validate(); err != nil {
return nil, fmt.Errorf("invalid rule detected: %s, err: %v", rule.Name, err)
}
// Get the resource list from kind
resources, err := pc.kubeClient.ListResource(rule.Resource.Kind, namespace)
if err != nil {
return nil, err
}
for _, resource := range resources {
// TODO:
rawResource, err := json.Marshal(resource)
// objKind := resource.GetObjectKind()
// codecFactory := serializer.NewCodecFactory(runtime.NewScheme())
// codecFactory.EncoderForVersion()
if err != nil {
pc.logger.Printf("failed to marshal object %v", resource)
continue
}
// filter the resource by name and label
if ok, _ := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); ok {
targetResources = append(targetResources, resource)
}
}
return targetResources, nil
}
func (pc *PolicyController) getPolicyByKey(key string) (*types.Policy, error) {
// Create nil Selector to grab all the policies
selector := labels.NewSelector()
cachedPolicies, err := pc.policyLister.List(selector)
if err != nil {
return nil, err
}
for _, elem := range cachedPolicies {
if elem.Name == key {
return elem, nil
}
}
return nil, nil
}

View file

@ -3,7 +3,7 @@ package webhooks
import (
kubeclient "github.com/nirmata/kube-policy/kubeclient"
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
mutation "github.com/nirmata/kube-policy/pkg/mutation"
mutation "github.com/nirmata/kube-policy/pkg/policyengine/mutation"
"k8s.io/api/admission/v1beta1"
)
@ -24,5 +24,5 @@ func AdmissionIsRequired(request *v1beta1.AdmissionRequest) bool {
// Checks requests kind, name and labels to fit the policy
func IsRuleApplicableToRequest(policyResource types.PolicyResource, request *v1beta1.AdmissionRequest) (bool, error) {
return mutation.IsRuleApplicableToResource(request.Kind.Kind, request.Object.Raw, policyResource)
return mutation.IsRuleApplicableToResource(request.Object.Raw, policyResource)
}

View file

@ -11,7 +11,8 @@ import (
types "github.com/nirmata/kube-policy/pkg/apis/policy/v1alpha1"
policylister "github.com/nirmata/kube-policy/pkg/client/listers/policy/v1alpha1"
event "github.com/nirmata/kube-policy/pkg/event"
mutation "github.com/nirmata/kube-policy/pkg/mutation"
policyengine "github.com/nirmata/kube-policy/pkg/policyengine"
mutation "github.com/nirmata/kube-policy/pkg/policyengine/mutation"
policyviolation "github.com/nirmata/kube-policy/pkg/policyviolation"
v1beta1 "k8s.io/api/admission/v1beta1"
@ -25,6 +26,7 @@ import (
// business logic for resource mutation
type MutationWebhook struct {
kubeclient *kubeclient.KubeClient
policyEngine policyengine.PolicyEngine
policyLister policylister.PolicyLister
registration *MutationWebhookRegistration
violationBuilder policyviolation.Generator
@ -57,8 +59,11 @@ func CreateMutationWebhook(
if logger == nil {
logger = log.New(os.Stdout, "Mutation WebHook: ", log.LstdFlags|log.Lshortfile)
}
policyengine := policyengine.NewPolicyEngine(kubeclient, logger)
return &MutationWebhook{
kubeclient: kubeclient,
policyEngine: policyengine,
policyLister: policyLister,
registration: registration,
violationBuilder: violationBuilder,
@ -136,10 +141,10 @@ func (mw *MutationWebhook) Mutate(request *v1beta1.AdmissionRequest) *v1beta1.Ad
// May return nil patches if it is not necessary to create patches for requested object.
// Returns error ONLY in case when creation of resource should be denied.
func (mw *MutationWebhook) applyPolicyRules(request *v1beta1.AdmissionRequest, policy types.Policy) ([]mutation.PatchBytes, error) {
return mw.applyPolicyRulesOnResource(request.Kind.Kind, request.Object.Raw, policy)
return mw.policyEngine.ProcessMutation(policy, request.Object.Raw)
}
// kind is the type of object being manipulated
// kind is the type of object being manipulated, e.g. request.Kind.kind
func (mw *MutationWebhook) applyPolicyRulesOnResource(kind string, rawResource []byte, policy types.Policy) ([]mutation.PatchBytes, error) {
patchingSets := mutation.GetPolicyPatchingSets(policy)
var policyPatches []mutation.PatchBytes
@ -151,7 +156,7 @@ func (mw *MutationWebhook) applyPolicyRulesOnResource(kind string, rawResource [
continue
}
if ok, err := mutation.IsRuleApplicableToResource(kind, rawResource, rule.Resource); !ok {
if ok, err := mutation.IsRuleApplicableToResource(rawResource, rule.Resource); !ok {
mw.logger.Printf("Rule %d of policy %s is not applicable to the request", ruleIdx, policy.Name)
return nil, err
}