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:
parent
135f241a4a
commit
1e621146be
16 changed files with 160 additions and 167 deletions
64
main.go
64
main.go
|
@ -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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue