1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

test policy engine on admission requests

This commit is contained in:
shivkumar dudhani 2019-08-09 16:55:43 -07:00
parent 135f241a4a
commit 1e621146be
16 changed files with 160 additions and 167 deletions

64
main.go
View file

@ -4,7 +4,6 @@ import (
"flag"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/annotations"
clientNew "github.com/nirmata/kyverno/pkg/clientNew/clientset/versioned"
kyvernoinformer "github.com/nirmata/kyverno/pkg/clientNew/informers/externalversions"
"github.com/nirmata/kyverno/pkg/config"
@ -12,8 +11,6 @@ import (
event "github.com/nirmata/kyverno/pkg/event"
"github.com/nirmata/kyverno/pkg/policy"
"github.com/nirmata/kyverno/pkg/policyviolation"
"github.com/nirmata/kyverno/pkg/sharedinformer"
"github.com/nirmata/kyverno/pkg/utils"
"github.com/nirmata/kyverno/pkg/webhooks"
"k8s.io/sample-controller/pkg/signals"
)
@ -27,58 +24,61 @@ var (
func main() {
defer glog.Flush()
printVersionInfo()
// CLIENT CONFIG
clientConfig, err := createClientConfig(kubeconfig)
if err != nil {
glog.Fatalf("Error building kubeconfig: %v\n", err)
}
// DYNAMIC CLIENT
// - client for all registered resources
client, err := client.NewClient(clientConfig)
if err != nil {
glog.Fatalf("Error creating client: %v\n", err)
}
// check if the k8 server version is supported ?
// if !version.Supportedk8Server(client) {
// glog.Fatalf("the k8 server version is not supported. refer to https://github.com/nirmata/kyverno/blob/master/documentation/installation.md for more details")
// }
//-------------------------------------
// create policy client
// KYVENO CRD CLIENT
// access CRD resources
// - Policy
// - PolicyViolation
pclient, err := clientNew.NewForConfig(clientConfig)
if err != nil {
glog.Fatalf("Error creating client: %v\n", err)
}
// KYVERNO CRD INFORMER
// watches CRD resources:
// - Policy
// - PolicyVolation
// - cache resync time: 10 seconds
pInformer := kyvernoinformer.NewSharedInformerFactoryWithOptions(pclient, 10)
// POLICY CONTROLLER
// - reconciliation policy and policy violation
// - status: violation count
pc, err := policy.NewPolicyController(pclient, client, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations())
if err != nil {
glog.Fatalf("error creating policy controller: %v\n", err)
}
// POLICY VIOLATION CONTROLLER
// status: lastUpdatTime
pvc, err := policyviolation.NewPolicyViolationController(client, pclient, pInformer.Kyverno().V1alpha1().Policies(), pInformer.Kyverno().V1alpha1().PolicyViolations())
if err != nil {
glog.Fatalf("error creating policy violation controller: %v\n", err)
}
//-------------------------------------
policyInformerFactory, err := sharedinformer.NewSharedInformerFactory(clientConfig)
if err != nil {
glog.Fatalf("Error creating policy sharedinformer: %v\n", err)
}
kubeInformer := utils.NewKubeInformerFactory(clientConfig)
egen := event.NewEventGenerator(client, policyInformerFactory)
// violationBuilder := violation.NewPolicyViolationBuilder(client, policyInformerFactory, eventController)
annotationsController := annotations.NewAnnotationControler(client)
// policyController := controller.NewPolicyController(
// client,
// policyInformerFactory,
// violationBuilder,
// eventController,
// annotationsController,
// filterK8Resources)
// genControler := gencontroller.NewGenController(client, eventController, policyInformerFactory, violationBuilder, kubeInformer.Core().V1().Namespaces(), annotationsController)
// EVENT GENERATOR
// - generate event with retry
egen := event.NewEventGenerator(client, pInformer.Kyverno().V1alpha1().Policies())
// TODO : Process Existing
tlsPair, err := initTLSPemPair(clientConfig, client)
if err != nil {
glog.Fatalf("Failed to initialize TLS key/certificate pair: %v\n", err)
}
server, err := webhooks.NewWebhookServer(client, tlsPair, policyInformerFactory, egen, nil, annotationsController, filterK8Resources)
server, err := webhooks.NewWebhookServer(client, tlsPair, pInformer.Kyverno().V1alpha1().Policies(), egen, filterK8Resources)
if err != nil {
glog.Fatalf("Unable to create webhook server: %v\n", err)
}
@ -99,23 +99,21 @@ func main() {
go pc.Run(1, stopCh)
go pvc.Run(1, stopCh)
go egen.Run(1, stopCh)
//TODO add WG for the go routine?
//TODO add WG for the go routines?
//--------
policyInformerFactory.Run(stopCh)
kubeInformer.Start(stopCh)
// eventController.Run(stopCh)
// genControler.Run(stopCh)
annotationsController.Run(stopCh)
// annotationsController.Run(stopCh)
// if err = policyController.Run(stopCh); err != nil {
// glog.Fatalf("Error running PolicyController: %v\n", err)
// }
server.RunAsync()
<-stopCh
server.Stop()
// genControler.Stop()
// eventController.Stop()
annotationsController.Stop()
// annotationsController.Stop()
// policyController.Stop()
}

View file

@ -3,7 +3,7 @@ package engine
import (
jsonpatch "github.com/evanphx/json-patch"
"github.com/golang/glog"
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/info"
"github.com/nirmata/kyverno/pkg/utils"
@ -11,11 +11,11 @@ import (
)
// ProcessExisting checks for mutation and validation violations of existing resources
func ProcessExisting(client *client.Client, policy *types.Policy, filterK8Resources []utils.K8Resource) []*info.PolicyInfo {
func ProcessExisting(client *client.Client, policy *kyverno.Policy, filterK8Resources []utils.K8Resource) []info.PolicyInfo {
glog.Infof("Applying policy %s on existing resources", policy.Name)
// key uid
resourceMap := ListResourcesThatApplyToPolicy(client, policy, filterK8Resources)
policyInfos := []*info.PolicyInfo{}
policyInfos := []info.PolicyInfo{}
// for the filtered resource apply policy
for _, v := range resourceMap {
@ -31,25 +31,28 @@ func ProcessExisting(client *client.Client, policy *types.Policy, filterK8Resour
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(), policy.Spec.ValidationFailureAction)
func applyPolicy(client *client.Client, policy *kyverno.Policy, res resourceInfo) (info.PolicyInfo, error) {
var policyInfo info.PolicyInfo
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
return policyInfo, err
}
// Mutate
mruleInfos, err := mutation(policy, rawResource, res.Gvk)
policyInfo.AddRuleInfos(mruleInfos)
if err != nil {
return nil, err
return policyInfo, err
}
// Validation
//TODO check by value or pointer
vruleInfos, err := Validate(*policy, rawResource, *res.Gvk)
policyInfo.AddRuleInfos(vruleInfos)
if err != nil {
return nil, err
return policyInfo, err
}
policyInfo.AddRuleInfos(vruleInfos)
policyInfo = info.NewPolicyInfo(policy.Name, res.Gvk.Kind, res.Resource.GetName(), res.Resource.GetNamespace(), policy.Spec.ValidationFailureAction)
if res.Gvk.Kind == "Namespace" {
// Generation
@ -60,7 +63,7 @@ func applyPolicy(client *client.Client, policy *types.Policy, res resourceInfo)
return policyInfo, nil
}
func mutation(p *types.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
func mutation(p *kyverno.Policy, rawResource []byte, gvk *metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
patches, ruleInfos := Mutate(*p, rawResource, *gvk)
if len(ruleInfos) == 0 {
// no rules were processed

View file

@ -5,7 +5,7 @@ import (
"errors"
"github.com/golang/glog"
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/info"
"github.com/nirmata/kyverno/pkg/utils"
@ -14,10 +14,10 @@ import (
)
//Generate apply generation rules on a resource
func Generate(client *client.Client, policy *v1alpha1.Policy, ns unstructured.Unstructured) []*info.RuleInfo {
func Generate(client *client.Client, policy *kyverno.Policy, ns unstructured.Unstructured) []*info.RuleInfo {
ris := []*info.RuleInfo{}
for _, rule := range policy.Spec.Rules {
if rule.Generation == nil {
if rule.Generation == (kyverno.Generation{}) {
continue
}
ri := info.NewRuleInfo(rule.Name, info.Generation)
@ -34,7 +34,7 @@ func Generate(client *client.Client, policy *v1alpha1.Policy, ns unstructured.Un
return ris
}
func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen *v1alpha1.Generation) error {
func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen kyverno.Generation) error {
var err error
resource := &unstructured.Unstructured{}
var rdata map[string]interface{}
@ -61,7 +61,7 @@ func applyRuleGenerator(client *client.Client, ns unstructured.Unstructured, gen
return err
}
}
if gen.Clone != nil {
if gen.Clone != (kyverno.CloneFrom{}) {
// 1> Check if resource exists
_, err := client.GetResource(gen.Kind, ns.GetName(), gen.Name)
if err == nil {

View file

@ -1,15 +1,17 @@
package engine
import (
"reflect"
"github.com/golang/glog"
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
"github.com/nirmata/kyverno/pkg/info"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Mutate performs mutation. Overlay first and then mutation patches
//TODO: check if gvk needs to be passed or can be set in resource
func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, []*info.RuleInfo) {
func Mutate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([][]byte, []*info.RuleInfo) {
//TODO: convert rawResource to unstructured to avoid unmarhalling all the time for get some resource information
//TODO: pass unstructured instead of rawResource ?
resource, err := convertToUnstructured(rawResource)
@ -20,7 +22,7 @@ func Mutate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersio
var ruleInfos []*info.RuleInfo
for _, rule := range policy.Spec.Rules {
if rule.Mutation == nil {
if reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) {
continue
}

View file

@ -11,13 +11,13 @@ import (
"github.com/golang/glog"
jsonpatch "github.com/evanphx/json-patch"
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
)
// ProcessOverlay handles validating admission request
// Checks the target resources for rules defined in the policy
func processOverlay(resourceUnstr *unstructured.Unstructured, rule kubepolicy.Rule, rawResource []byte) ([][]byte, error) {
func processOverlay(resourceUnstr *unstructured.Unstructured, rule kyverno.Rule, rawResource []byte) ([][]byte, error) {
//TODO check if there is better solution
resourceRaw, err := resourceUnstr.MarshalJSON()
@ -32,9 +32,9 @@ func processOverlay(resourceUnstr *unstructured.Unstructured, rule kubepolicy.Ru
}
// resourceInfo := ParseResourceInfoFromObject(rawResource)
patches, err := processOverlayPatches(resource, *rule.Mutation.Overlay)
patches, err := processOverlayPatches(resource, rule.Mutation.Overlay)
if err != nil && strings.Contains(err.Error(), "Conditions are not met") {
glog.V(4).Infof("overlay pattern %s does not match resource %s/%s", *rule.Mutation.Overlay, resourceUnstr.GetNamespace(), resourceUnstr.GetName())
glog.V(4).Infof("overlay pattern %s does not match resource %s/%s", rule.Mutation.Overlay, resourceUnstr.GetNamespace(), resourceUnstr.GetName())
// glog.Infof("Resource does not meet conditions in overlay pattern, resource=%s, rule=%s\n", resourceInfo, rule.Name)
return nil, nil
}

View file

@ -3,21 +3,22 @@ package engine
import (
"encoding/json"
"errors"
"reflect"
"github.com/golang/glog"
jsonpatch "github.com/evanphx/json-patch"
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
)
// ProcessPatches Returns array from separate patches that can be applied to the document
// Returns error ONLY in case when creation of resource should be denied.
func processPatches(rule kubepolicy.Rule, resource []byte) (allPatches [][]byte, errs []error) {
func processPatches(rule kyverno.Rule, resource []byte) (allPatches [][]byte, errs []error) {
if len(resource) == 0 {
errs = append(errs, errors.New("Source document for patching is empty"))
return nil, errs
}
if rule.Mutation == nil {
if reflect.DeepEqual(rule.Mutation, kyverno.Mutation{}) {
errs = append(errs, errors.New("No Mutation rules defined"))
return nil, errs
}

View file

@ -9,8 +9,7 @@ import (
"github.com/golang/glog"
"github.com/minio/minio/pkg/wildcard"
types "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
v1alpha1 "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/utils"
v1helper "k8s.io/apimachinery/pkg/apis/meta/v1"
@ -21,7 +20,7 @@ import (
)
//ListResourcesThatApplyToPolicy returns list of resources that are filtered by policy rules
func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy, filterK8Resources []utils.K8Resource) map[string]resourceInfo {
func ListResourcesThatApplyToPolicy(client *client.Client, policy *kyverno.Policy, filterK8Resources []utils.K8Resource) map[string]resourceInfo {
// key uid
resourceMap := map[string]resourceInfo{}
for _, rule := range policy.Spec.Rules {
@ -31,9 +30,9 @@ func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy,
if k == "Namespace" {
namespaces = []string{""}
} else {
if rule.MatchResources.Namespace != nil {
if rule.MatchResources.Namespace != "" {
// if namespace is specified then we add the namespace
namespaces = append(namespaces, *rule.MatchResources.Namespace)
namespaces = append(namespaces, rule.MatchResources.Namespace)
} else {
// no namespace specified, refer to all namespaces
namespaces = getAllNamespaces(client)
@ -54,7 +53,7 @@ func ListResourcesThatApplyToPolicy(client *client.Client, policy *types.Policy,
return resourceMap
}
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule types.Rule, filterK8Resources []utils.K8Resource) map[string]resourceInfo {
func getResourcesPerNamespace(kind string, client *client.Client, namespace string, rule kyverno.Rule, filterK8Resources []utils.K8Resource) map[string]resourceInfo {
resourceMap := map[string]resourceInfo{}
// List resources
list, err := client.ListResource(kind, namespace, rule.MatchResources.Selector)
@ -79,14 +78,14 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
continue
}
}
var name *string
var name string
// match
// name
// wild card matching
name = rule.MatchResources.Name
if name != nil {
if name != "" {
// if does not match then we skip
if !wildcard.Match(*name, res.GetName()) {
if !wildcard.Match(name, res.GetName()) {
continue
}
}
@ -94,9 +93,9 @@ func getResourcesPerNamespace(kind string, client *client.Client, namespace stri
// name
// wild card matching
name = rule.ExcludeResources.Name
if name != nil {
if name != "nil" {
// if matches then we skip
if wildcard.Match(*name, res.GetName()) {
if wildcard.Match(name, res.GetName()) {
continue
}
}
@ -136,13 +135,13 @@ func getAllNamespaces(client *client.Client) []string {
return namespaces
}
func excludeNamespaces(namespaces []string, excludeNs *string) []string {
if excludeNs == nil {
func excludeNamespaces(namespaces []string, excludeNs string) []string {
if excludeNs == "" {
return namespaces
}
filteredNamespaces := []string{}
for _, n := range namespaces {
if n == *excludeNs {
if n == excludeNs {
continue
}
filteredNamespaces = append(filteredNamespaces, n)
@ -151,7 +150,7 @@ func excludeNamespaces(namespaces []string, excludeNs *string) []string {
}
//MatchesResourceDescription checks if the resource matches resource desription of the rule or not
func MatchesResourceDescription(resource *unstructured.Unstructured, rule v1alpha1.Rule, gvk metav1.GroupVersionKind) bool {
func MatchesResourceDescription(resource *unstructured.Unstructured, rule kyverno.Rule, gvk metav1.GroupVersionKind) bool {
matches := rule.MatchResources.ResourceDescription
exclude := rule.ExcludeResources.ResourceDescription
@ -163,25 +162,25 @@ func MatchesResourceDescription(resource *unstructured.Unstructured, rule v1alph
name := resource.GetName()
namespace := resource.GetNamespace()
if matches.Name != nil {
if matches.Name != "" {
// Matches
if !wildcard.Match(*matches.Name, name) {
if !wildcard.Match(matches.Name, name) {
return false
}
}
// Exclude
// the resource name matches the exclude resource name then reject
if exclude.Name != nil {
if wildcard.Match(*exclude.Name, name) {
if exclude.Name != "" {
if wildcard.Match(exclude.Name, name) {
return false
}
}
// Matches
if matches.Namespace != nil && *matches.Namespace != namespace {
if matches.Namespace != "" && matches.Namespace != namespace {
return false
}
// Exclude
if exclude.Namespace != nil && *exclude.Namespace == namespace {
if exclude.Namespace != "" && exclude.Namespace == namespace {
return false
}
// Matches
@ -211,7 +210,7 @@ func MatchesResourceDescription(resource *unstructured.Unstructured, rule v1alph
}
// ResourceMeetsDescription checks requests kind, name and labels to fit the policy rule
func ResourceMeetsDescription(resourceRaw []byte, matches v1alpha1.ResourceDescription, exclude v1alpha1.ResourceDescription, gvk metav1.GroupVersionKind) bool {
func ResourceMeetsDescription(resourceRaw []byte, matches kyverno.ResourceDescription, exclude kyverno.ResourceDescription, gvk metav1.GroupVersionKind) bool {
if !findKind(matches.Kinds, gvk.Kind) {
return false
}
@ -221,25 +220,25 @@ func ResourceMeetsDescription(resourceRaw []byte, matches v1alpha1.ResourceDescr
name := ParseNameFromObject(resourceRaw)
namespace := ParseNamespaceFromObject(resourceRaw)
if matches.Name != nil {
if matches.Name != "" {
// Matches
if !wildcard.Match(*matches.Name, name) {
if !wildcard.Match(matches.Name, name) {
return false
}
}
// Exclude
// the resource name matches the exclude resource name then reject
if exclude.Name != nil {
if wildcard.Match(*exclude.Name, name) {
if exclude.Name != "" {
if wildcard.Match(exclude.Name, name) {
return false
}
}
// Matches
if matches.Namespace != nil && *matches.Namespace != namespace {
if matches.Namespace != "" && matches.Namespace != namespace {
return false
}
// Exclude
if exclude.Namespace != nil && *exclude.Namespace == namespace {
if exclude.Namespace != "" && exclude.Namespace == namespace {
return false
}
// Matches

View file

@ -10,14 +10,14 @@ import (
"strings"
"github.com/golang/glog"
kubepolicy "github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
"github.com/nirmata/kyverno/pkg/info"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Validate handles validating admission request
// Checks the target resources for rules defined in the policy
func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
func Validate(policy kyverno.Policy, rawResource []byte, gvk metav1.GroupVersionKind) ([]*info.RuleInfo, error) {
//TODO: convert rawResource to unstructured to avoid unmarhalling all the time for get some resource information
//TODO: pass unstructured instead of rawResource ?
resourceUnstr, err := convertToUnstructured(rawResource)
@ -38,7 +38,7 @@ func Validate(policy kubepolicy.Policy, rawResource []byte, gvk metav1.GroupVers
var ruleInfos []*info.RuleInfo
for _, rule := range policy.Spec.Rules {
if rule.Validation == nil {
if reflect.DeepEqual(rule.Validation, kyverno.Validation{}) {
continue
}

View file

@ -6,9 +6,9 @@ import (
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
policyscheme "github.com/nirmata/kyverno/pkg/client/clientset/versioned/scheme"
v1alpha1 "github.com/nirmata/kyverno/pkg/client/listers/policy/v1alpha1"
informer "github.com/nirmata/kyverno/pkg/clientNew/informers/externalversions/kyverno/v1alpha1"
lister "github.com/nirmata/kyverno/pkg/clientNew/listers/kyverno/v1alpha1"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/sharedinformer"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
@ -20,10 +20,10 @@ import (
//Generator generate events
type Generator struct {
client *client.Client
policyLister v1alpha1.PolicyLister
queue workqueue.RateLimitingInterface
recorder record.EventRecorder
client *client.Client
pLister lister.PolicyLister
queue workqueue.RateLimitingInterface
recorder record.EventRecorder
}
//Interface to generate event
@ -33,13 +33,13 @@ type Interface interface {
//NewEventGenerator to generate a new event controller
func NewEventGenerator(client *client.Client,
shareInformer sharedinformer.PolicyInformer) *Generator {
pInformer informer.PolicyInformer) *Generator {
gen := Generator{
client: client,
policyLister: shareInformer.GetLister(),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName),
recorder: initRecorder(client),
client: client,
pLister: pInformer.Lister(),
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), eventWorkQueueName),
recorder: initRecorder(client),
}
return &gen
@ -145,7 +145,7 @@ func (gen *Generator) syncHandler(key Info) error {
switch key.Kind {
case "Policy":
//TODO: policy is clustered resource so wont need namespace
robj, err = gen.policyLister.Get(key.Name)
robj, err = gen.pLister.Get(key.Name)
if err != nil {
glog.Errorf("Error creating event: unable to get policy %s, will retry ", key.Name)
return err

View file

@ -25,8 +25,8 @@ type PolicyInfo struct {
}
//NewPolicyInfo returns a new policy info
func NewPolicyInfo(policyName, rKind, rName, rNamespace, validationFailureAction string) *PolicyInfo {
return &PolicyInfo{
func NewPolicyInfo(policyName, rKind, rName, rNamespace, validationFailureAction string) PolicyInfo {
pi := PolicyInfo{
Name: policyName,
RKind: rKind,
RName: rName,
@ -34,6 +34,7 @@ func NewPolicyInfo(policyName, rKind, rName, rNamespace, validationFailureAction
success: true, // fail to be set explicity
ValidationFailureAction: validationFailureAction,
}
return pi
}
//IsSuccessful checks if policy is succesful

View file

@ -1,40 +1,38 @@
package webhooks
import (
"errors"
engine "github.com/nirmata/kyverno/pkg/engine"
v1beta1 "k8s.io/api/admission/v1beta1"
"k8s.io/apimachinery/pkg/labels"
)
func (ws *WebhookServer) removePolicyViolation(request *v1beta1.AdmissionRequest) error {
// Get the list of policies that apply on the resource
policies, err := ws.policyLister.List(labels.NewSelector())
if err != nil {
// Unable to connect to policy Lister to access policies
return errors.New("Unable to connect to policy controller to access policies. Clean Up of Policy Violations is not being done")
}
for _, policy := range policies {
// check if policy has a rule for the admission request kind
if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) {
continue
}
// get the details from the request
rname := request.Name
rns := request.Namespace
rkind := request.Kind.Kind
// check if the resource meets the policy Resource description
for _, rule := range policy.Spec.Rules {
ok := engine.ResourceMeetsDescription(request.Object.Raw, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, request.Kind)
if ok {
// Check if the policy has a violation for this resource
err := ws.violationBuilder.ResourceRemoval(policy.Name, rkind, rns, rname)
if err != nil {
return err
}
}
}
}
//TODO: ClenUp will be handled by the policycontroller
// // Get the list of policies that apply on the resource
// policies, err := ws.policyLister.List(labels.NewSelector())
// if err != nil {
// // Unable to connect to policy Lister to access policies
// return errors.New("Unable to connect to policy controller to access policies. Clean Up of Policy Violations is not being done")
// }
// for _, policy := range policies {
// // check if policy has a rule for the admission request kind
// if !StringInSlice(request.Kind.Kind, getApplicableKindsForPolicy(policy)) {
// continue
// }
// // get the details from the request
// rname := request.Name
// rns := request.Namespace
// rkind := request.Kind.Kind
// // check if the resource meets the policy Resource description
// for _, rule := range policy.Spec.Rules {
// ok := engine.ResourceMeetsDescription(request.Object.Raw, rule.MatchResources.ResourceDescription, rule.ExcludeResources.ResourceDescription, request.Kind)
// if ok {
// // Check if the policy has a violation for this resource
// err := ws.violationBuilder.ResourceRemoval(policy.Name, rkind, rns, rname)
// if err != nil {
// return err
// }
// }
// }
// }
return nil
}

View file

@ -13,11 +13,11 @@ import (
// HandleMutation handles mutating webhook admission request
func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
var patches [][]byte
var policyInfos []*info.PolicyInfo
var policyInfos []info.PolicyInfo
glog.V(4).Infof("Receive request in mutating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
policies, err := ws.policyLister.List(labels.NewSelector())
policies, err := ws.pLister.List(labels.NewSelector())
if err != nil {
//TODO check if the CRD is created ?
// Unable to connect to policy Lister to access policies
@ -53,8 +53,7 @@ func (ws *WebhookServer) HandleMutation(request *v1beta1.AdmissionRequest) *v1be
policyPatches, ruleInfos := engine.Mutate(*policy, request.Object.Raw, request.Kind)
policyInfo.AddRuleInfos(ruleInfos)
policyInfos = append(policyInfos, policyInfo)
if !policyInfo.IsSuccessful() {
if !policyInfo.IsSuccessful() {
glog.V(4).Infof("Failed to apply policy %s on resource %s/%s", policy.Name, resource.GetNamespace(), resource.GetName())
glog.V(4).Info("Failed rule details")
for _, r := range ruleInfos {

View file

@ -12,7 +12,7 @@ import (
)
//TODO: change validation from bool -> enum(validation, mutation)
func newEventInfoFromPolicyInfo(policyInfoList []*info.PolicyInfo, onUpdate bool, ruleType info.RuleType) ([]*event.Info, []*violation.Info) {
func newEventInfoFromPolicyInfo(policyInfoList []info.PolicyInfo, onUpdate bool, ruleType info.RuleType) ([]*event.Info, []*violation.Info) {
var eventsInfo []*event.Info
var violations []*violation.Info
ok, msg := isAdmSuccesful(policyInfoList)

View file

@ -11,28 +11,24 @@ import (
"time"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/annotations"
"github.com/nirmata/kyverno/pkg/client/listers/policy/v1alpha1"
informer "github.com/nirmata/kyverno/pkg/clientNew/informers/externalversions/kyverno/v1alpha1"
lister "github.com/nirmata/kyverno/pkg/clientNew/listers/kyverno/v1alpha1"
"github.com/nirmata/kyverno/pkg/config"
client "github.com/nirmata/kyverno/pkg/dclient"
"github.com/nirmata/kyverno/pkg/event"
"github.com/nirmata/kyverno/pkg/sharedinformer"
tlsutils "github.com/nirmata/kyverno/pkg/tls"
"github.com/nirmata/kyverno/pkg/utils"
"github.com/nirmata/kyverno/pkg/violation"
v1beta1 "k8s.io/api/admission/v1beta1"
)
// 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
eventGen event.Interface
violationBuilder violation.Generator
annotationsController annotations.Controller
filterK8Resources []utils.K8Resource
server http.Server
client *client.Client
pLister lister.PolicyLister
eventGen event.Interface
filterK8Resources []utils.K8Resource
}
// NewWebhookServer creates new instance of WebhookServer accordingly to given configuration
@ -40,10 +36,8 @@ type WebhookServer struct {
func NewWebhookServer(
client *client.Client,
tlsPair *tlsutils.TlsPemPair,
shareInformer sharedinformer.PolicyInformer,
pInformer informer.PolicyInformer,
eventGen event.Interface,
violationBuilder violation.Generator,
annotationsController annotations.Controller,
filterK8Resources string) (*WebhookServer, error) {
if tlsPair == nil {
@ -58,12 +52,10 @@ func NewWebhookServer(
tlsConfig.Certificates = []tls.Certificate{pair}
ws := &WebhookServer{
client: client,
policyLister: shareInformer.GetLister(),
eventGen: eventGen,
violationBuilder: violationBuilder,
annotationsController: annotationsController,
filterK8Resources: utils.ParseKinds(filterK8Resources),
client: client,
pLister: pInformer.Lister(),
eventGen: eventGen,
filterK8Resources: utils.ParseKinds(filterK8Resources),
}
mux := http.NewServeMux()
mux.HandleFunc(config.MutatingWebhookServicePath, ws.serve)

View file

@ -7,7 +7,7 @@ import (
"strings"
"github.com/golang/glog"
"github.com/nirmata/kyverno/pkg/apis/policy/v1alpha1"
kyverno "github.com/nirmata/kyverno/pkg/api/kyverno/v1alpha1"
"github.com/nirmata/kyverno/pkg/info"
v1beta1 "k8s.io/api/admission/v1beta1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
@ -15,7 +15,7 @@ import (
const policyKind = "Policy"
func isAdmSuccesful(policyInfos []*info.PolicyInfo) (bool, string) {
func isAdmSuccesful(policyInfos []info.PolicyInfo) (bool, string) {
var admSuccess = true
var errMsgs []string
for _, pi := range policyInfos {
@ -73,7 +73,7 @@ func (i *ArrayFlags) Set(value string) error {
}
// extract the kinds that the policy rules apply to
func getApplicableKindsForPolicy(p *v1alpha1.Policy) []string {
func getApplicableKindsForPolicy(p *kyverno.Policy) []string {
kindsMap := map[string]interface{}{}
kinds := []string{}
// iterate over the rules an identify all kinds
@ -106,7 +106,7 @@ const (
// returns true -> if there is even one policy that blocks resource requst
// returns false -> if all the policies are meant to report only, we dont block resource request
func toBlock(pis []*info.PolicyInfo) bool {
func toBlock(pis []info.PolicyInfo) bool {
for _, pi := range pis {
if pi.ValidationFailureAction != ReportViolation {
return true

View file

@ -13,13 +13,12 @@ import (
// HandleValidation handles validating webhook admission request
// If there are no errors in validating rule we apply generation rules
func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1beta1.AdmissionResponse {
// var patches [][]byte
var policyInfos []*info.PolicyInfo
var policyInfos []info.PolicyInfo
glog.V(4).Infof("Receive request in validating webhook: Kind=%s, Namespace=%s Name=%s UID=%s patchOperation=%s",
request.Kind.Kind, request.Namespace, request.Name, request.UID, request.Operation)
policies, err := ws.policyLister.List(labels.NewSelector())
policies, err := ws.pLister.List(labels.NewSelector())
if err != nil {
//TODO check if the CRD is created ?
// Unable to connect to policy Lister to access policies
@ -62,6 +61,7 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
continue
}
policyInfo.AddRuleInfos(ruleInfos)
policyInfos = append(policyInfos, policyInfo)
if !policyInfo.IsSuccessful() {
glog.Infof("Failed to apply policy %s on resource %s/%s", policy.Name, resource.GetNamespace(), resource.GetName())
@ -74,10 +74,10 @@ func (ws *WebhookServer) HandleValidation(request *v1beta1.AdmissionRequest) *v1
if len(ruleInfos) > 0 {
glog.V(4).Infof("Validation from policy %s has applied succesfully to %s %s/%s", policy.Name, request.Kind.Kind, resource.GetNamespace(), resource.GetName())
}
policyInfos = append(policyInfos, policyInfo)
}
// ADD EVENTS
// ADD POLICY VIOLATIONS
ok, msg := isAdmSuccesful(policyInfos)
if !ok && toBlock(policyInfos) {