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:
commit
6d83aa6b9e
19 changed files with 616 additions and 39 deletions
|
@ -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
|
||||
}
|
||||
|
|
3
main.go
3
main.go
|
@ -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,
|
||||
|
|
|
@ -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`
|
||||
}
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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
|
||||
|
|
96
pkg/policyengine/mutation.go
Normal file
96
pkg/policyengine/mutation.go
Normal 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
|
||||
}
|
|
@ -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)
|
103
pkg/policyengine/policyengine.go
Normal file
103
pkg/policyengine/policyengine.go
Normal 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
|
||||
}
|
5
pkg/policyengine/validation.go
Normal file
5
pkg/policyengine/validation.go
Normal 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) {}
|
|
@ -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},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
122
policycontroller/processPolicy.go
Normal file
122
policycontroller/processPolicy.go
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue