mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-13 19:28:55 +00:00
refactor: add more functionnalities to engine interface (#6212)
* refactor: add more functionnalities to engine interface Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * exclude mechanism Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * polex Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> * fix kuttl tests Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com> --------- Signed-off-by: Charles-Edouard Brétéché <charles.edouard@nirmata.com>
This commit is contained in:
parent
d0896cb57e
commit
6934c66a71
27 changed files with 255 additions and 238 deletions
|
@ -229,6 +229,8 @@ func main() {
|
|||
engine := engine.NewEngine(
|
||||
configuration,
|
||||
engine.LegacyContextLoaderFactory(rclient, configMapResolver),
|
||||
// TODO: do we need exceptions here ?
|
||||
nil,
|
||||
)
|
||||
// create non leader controllers
|
||||
nonLeaderControllers := createNonLeaderControllers(
|
||||
|
|
|
@ -477,6 +477,7 @@ OuterLoop:
|
|||
eng := engine.NewEngine(
|
||||
cfg,
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil),
|
||||
nil,
|
||||
)
|
||||
policyContext := engine.NewPolicyContextWithJsonContext(ctx).
|
||||
WithPolicy(c.Policy).
|
||||
|
@ -1080,6 +1081,7 @@ func initializeMockController(objects []runtime.Object) (*generate.GenerateContr
|
|||
c := generate.NewGenerateControllerWithOnlyClient(client, engine.NewEngine(
|
||||
config.NewDefaultConfiguration(),
|
||||
engine.LegacyContextLoaderFactory(nil, nil),
|
||||
nil,
|
||||
))
|
||||
return c, nil
|
||||
}
|
||||
|
|
|
@ -355,9 +355,19 @@ func main() {
|
|||
kubeKyvernoInformer.Apps().V1().Deployments(),
|
||||
certRenewer,
|
||||
)
|
||||
var exceptionsLister engineapi.PolicyExceptionSelector
|
||||
if enablePolicyException {
|
||||
lister := kyvernoInformer.Kyverno().V2alpha1().PolicyExceptions().Lister()
|
||||
if exceptionNamespace != "" {
|
||||
exceptionsLister = lister.PolicyExceptions(exceptionNamespace)
|
||||
} else {
|
||||
exceptionsLister = lister
|
||||
}
|
||||
}
|
||||
eng := engine.NewEngine(
|
||||
configuration,
|
||||
engine.LegacyContextLoaderFactory(rclient, configMapResolver),
|
||||
exceptionsLister,
|
||||
)
|
||||
// create non leader controllers
|
||||
nonLeaderControllers, nonLeaderBootstrap := createNonLeaderControllers(
|
||||
|
@ -468,15 +478,6 @@ func main() {
|
|||
dClient,
|
||||
openApiManager,
|
||||
)
|
||||
var exceptionsLister engine.PolicyExceptionLister
|
||||
if enablePolicyException {
|
||||
lister := kyvernoInformer.Kyverno().V2alpha1().PolicyExceptions().Lister()
|
||||
if exceptionNamespace != "" {
|
||||
exceptionsLister = lister.PolicyExceptions(exceptionNamespace)
|
||||
} else {
|
||||
exceptionsLister = lister
|
||||
}
|
||||
}
|
||||
resourceHandlers := webhooksresource.NewHandlers(
|
||||
eng,
|
||||
dClient,
|
||||
|
@ -489,7 +490,6 @@ func main() {
|
|||
kubeInformer.Rbac().V1().RoleBindings().Lister(),
|
||||
kubeInformer.Rbac().V1().ClusterRoleBindings().Lister(),
|
||||
kyvernoInformer.Kyverno().V1beta1().UpdateRequests().Lister().UpdateRequests(config.KyvernoNamespace()),
|
||||
exceptionsLister,
|
||||
urgen,
|
||||
eventGenerator,
|
||||
openApiManager,
|
||||
|
|
|
@ -86,7 +86,6 @@ func createReportControllers(
|
|||
var ctrls []internal.Controller
|
||||
var warmups []func(context.Context) error
|
||||
kyvernoV1 := kyvernoInformer.Kyverno().V1()
|
||||
kyvernoV2Alpha1 := kyvernoInformer.Kyverno().V2alpha1()
|
||||
if backgroundScan || admissionReports {
|
||||
resourceReportController := resourcereportcontroller.NewController(
|
||||
client,
|
||||
|
@ -136,7 +135,6 @@ func createReportControllers(
|
|||
kyvernoV1.Policies(),
|
||||
kyvernoV1.ClusterPolicies(),
|
||||
kubeInformer.Core().V1().Namespaces(),
|
||||
kyvernoV2Alpha1.PolicyExceptions().Lister(),
|
||||
resourceReportController,
|
||||
configMapResolver,
|
||||
backgroundScanInterval,
|
||||
|
@ -206,6 +204,8 @@ func main() {
|
|||
backgroundScanWorkers int
|
||||
backgroundScanInterval time.Duration
|
||||
maxQueuedEvents int
|
||||
enablePolicyException bool
|
||||
exceptionNamespace string
|
||||
)
|
||||
flagset := flag.NewFlagSet("reports-controller", flag.ExitOnError)
|
||||
flagset.DurationVar(&leaderElectionRetryPeriod, "leaderElectionRetryPeriod", leaderelection.DefaultRetryPeriod, "Configure leader election retry period.")
|
||||
|
@ -218,6 +218,8 @@ func main() {
|
|||
flagset.IntVar(&backgroundScanWorkers, "backgroundScanWorkers", backgroundscancontroller.Workers, "Configure the number of background scan workers.")
|
||||
flagset.DurationVar(&backgroundScanInterval, "backgroundScanInterval", time.Hour, "Configure background scan interval.")
|
||||
flagset.IntVar(&maxQueuedEvents, "maxQueuedEvents", 1000, "Maximum events to be queued.")
|
||||
flagset.StringVar(&exceptionNamespace, "exceptionNamespace", "", "Configure the namespace to accept PolicyExceptions.")
|
||||
flagset.BoolVar(&enablePolicyException, "enablePolicyException", false, "Enable PolicyException feature.")
|
||||
// config
|
||||
appConfig := internal.NewConfiguration(
|
||||
internal.WithProfiling(),
|
||||
|
@ -294,6 +296,15 @@ func main() {
|
|||
maxQueuedEvents,
|
||||
logging.WithName("EventGenerator"),
|
||||
)
|
||||
var exceptionsLister engineapi.PolicyExceptionSelector
|
||||
if enablePolicyException {
|
||||
lister := kyvernoInformer.Kyverno().V2alpha1().PolicyExceptions().Lister()
|
||||
if exceptionNamespace != "" {
|
||||
exceptionsLister = lister.PolicyExceptions(exceptionNamespace)
|
||||
} else {
|
||||
exceptionsLister = lister
|
||||
}
|
||||
}
|
||||
// start informers and wait for cache sync
|
||||
if !internal.StartInformersAndWaitForCacheSync(ctx, kyvernoInformer, kubeKyvernoInformer, cacheInformer) {
|
||||
logger.Error(errors.New("failed to wait for cache sync"), "failed to wait for cache sync")
|
||||
|
@ -304,6 +315,7 @@ func main() {
|
|||
eng := engine.NewEngine(
|
||||
configuration,
|
||||
engine.LegacyContextLoaderFactory(rclient, configMapResolver),
|
||||
exceptionsLister,
|
||||
)
|
||||
// setup leader election
|
||||
le, err := leaderelection.New(
|
||||
|
|
|
@ -81,7 +81,6 @@ func NewBackgroundContext(dclient dclient.Interface, ur *kyvernov1beta1.UpdateRe
|
|||
WithNewResource(*trigger).
|
||||
WithOldResource(old).
|
||||
WithAdmissionInfo(ur.Spec.Context.UserRequestInfo).
|
||||
WithConfiguration(cfg).
|
||||
WithNamespaceLabels(namespaceLabels).
|
||||
WithClient(dclient)
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/controllers"
|
||||
"github.com/kyverno/kyverno/pkg/controllers/report/resource"
|
||||
"github.com/kyverno/kyverno/pkg/controllers/report/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
|
@ -57,7 +56,6 @@ type controller struct {
|
|||
bgscanrLister cache.GenericLister
|
||||
cbgscanrLister cache.GenericLister
|
||||
nsLister corev1listers.NamespaceLister
|
||||
polexLister engine.PolicyExceptionLister
|
||||
|
||||
// queue
|
||||
queue workqueue.RateLimitingInterface
|
||||
|
@ -81,7 +79,6 @@ func NewController(
|
|||
polInformer kyvernov1informers.PolicyInformer,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
nsInformer corev1informers.NamespaceInformer,
|
||||
polexLister engine.PolicyExceptionLister,
|
||||
metadataCache resource.MetadataCache,
|
||||
informerCacheResolvers engineapi.ConfigmapResolver,
|
||||
forceDelay time.Duration,
|
||||
|
@ -101,7 +98,6 @@ func NewController(
|
|||
bgscanrLister: bgscanr.Lister(),
|
||||
cbgscanrLister: cbgscanr.Lister(),
|
||||
nsLister: nsInformer.Lister(),
|
||||
polexLister: polexLister,
|
||||
queue: queue,
|
||||
metadataCache: metadataCache,
|
||||
informerCacheResolvers: informerCacheResolvers,
|
||||
|
@ -312,7 +308,7 @@ func (c *controller) reconcileReport(
|
|||
// calculate necessary results
|
||||
for _, policy := range backgroundPolicies {
|
||||
if full || actual[reportutils.PolicyLabel(policy)] != policy.GetResourceVersion() {
|
||||
scanner := utils.NewScanner(logger, c.engine, c.client, c.rclient, c.polexLister, c.config)
|
||||
scanner := utils.NewScanner(logger, c.engine, c.client, c.rclient, c.config)
|
||||
for _, result := range scanner.ScanResource(ctx, *target, nsLabels, policy) {
|
||||
if result.Error != nil {
|
||||
return result.Error
|
||||
|
|
|
@ -16,13 +16,11 @@ import (
|
|||
)
|
||||
|
||||
type scanner struct {
|
||||
logger logr.Logger
|
||||
engine engineapi.Engine
|
||||
client dclient.Interface
|
||||
rclient registryclient.Client
|
||||
polexLister engine.PolicyExceptionLister
|
||||
excludeGroupRole []string
|
||||
config config.Configuration
|
||||
logger logr.Logger
|
||||
engine engineapi.Engine
|
||||
client dclient.Interface
|
||||
rclient registryclient.Client
|
||||
config config.Configuration
|
||||
}
|
||||
|
||||
type ScanResult struct {
|
||||
|
@ -39,18 +37,14 @@ func NewScanner(
|
|||
engine engineapi.Engine,
|
||||
client dclient.Interface,
|
||||
rclient registryclient.Client,
|
||||
polexLister engine.PolicyExceptionLister,
|
||||
config config.Configuration,
|
||||
excludeGroupRole ...string,
|
||||
) Scanner {
|
||||
return &scanner{
|
||||
logger: logger,
|
||||
engine: engine,
|
||||
client: client,
|
||||
rclient: rclient,
|
||||
polexLister: polexLister,
|
||||
config: config,
|
||||
excludeGroupRole: excludeGroupRole,
|
||||
logger: logger,
|
||||
engine: engine,
|
||||
client: client,
|
||||
rclient: rclient,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,9 +93,7 @@ func (s *scanner) validateResource(ctx context.Context, resource unstructured.Un
|
|||
WithNewResource(resource).
|
||||
WithPolicy(policy).
|
||||
WithClient(s.client).
|
||||
WithNamespaceLabels(nsLabels).
|
||||
WithExcludeGroupRole(s.excludeGroupRole...).
|
||||
WithExceptions(s.polexLister)
|
||||
WithNamespaceLabels(nsLabels)
|
||||
return s.engine.Validate(ctx, policyCtx), nil
|
||||
}
|
||||
|
||||
|
@ -123,9 +115,7 @@ func (s *scanner) validateImages(ctx context.Context, resource unstructured.Unst
|
|||
WithNewResource(resource).
|
||||
WithPolicy(policy).
|
||||
WithClient(s.client).
|
||||
WithNamespaceLabels(nsLabels).
|
||||
WithExcludeGroupRole(s.excludeGroupRole...).
|
||||
WithExceptions(s.polexLister)
|
||||
WithNamespaceLabels(nsLabels)
|
||||
response, _ := s.engine.VerifyAndPatchImages(ctx, s.rclient, policyCtx)
|
||||
if len(response.PolicyResponse.Rules) > 0 {
|
||||
s.logger.Info("validateImages", "policy", policy, "response", response)
|
||||
|
|
|
@ -4,9 +4,19 @@ import (
|
|||
"context"
|
||||
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type NamespacedResourceSelector[T any] interface {
|
||||
// List selects resources based on label selector.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []T, err error)
|
||||
}
|
||||
|
||||
type PolicyExceptionSelector = NamespacedResourceSelector[*kyvernov2alpha1.PolicyException]
|
||||
|
||||
type Engine interface {
|
||||
// Validate applies validation rules from policy on the resource
|
||||
Validate(
|
||||
|
|
|
@ -3,7 +3,6 @@ package api
|
|||
import (
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
@ -26,7 +25,6 @@ type PolicyContext interface {
|
|||
NamespaceLabels() map[string]string
|
||||
SubResource() string
|
||||
SubresourcesInPolicy() []SubResource
|
||||
ExcludeGroupRole() []string
|
||||
AdmissionOperation() bool
|
||||
RequestResource() metav1.GroupVersionResource
|
||||
Element() unstructured.Unstructured
|
||||
|
@ -35,7 +33,4 @@ type PolicyContext interface {
|
|||
JSONContext() enginecontext.Interface
|
||||
Client() dclient.Interface
|
||||
Copy() PolicyContext
|
||||
|
||||
FindExceptions(rule string) ([]*kyvernov2alpha1.PolicyException, error)
|
||||
ExcludeResourceFunc() ExcludeFunc
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
|
@ -19,16 +20,20 @@ import (
|
|||
// 2. returns the list of rules that are applicable on this policy and resource, if 1 succeed
|
||||
func doApplyBackgroundChecks(
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
policyStartTime := time.Now()
|
||||
return filterRules(contextLoader, policyContext, policyStartTime)
|
||||
return filterRules(contextLoader, selector, policyContext, policyStartTime, cfg)
|
||||
}
|
||||
|
||||
func filterRules(
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
startTime time.Time,
|
||||
cfg config.Configuration,
|
||||
) *engineapi.EngineResponse {
|
||||
newResource := policyContext.NewResource()
|
||||
policy := policyContext.Policy()
|
||||
|
@ -56,14 +61,14 @@ func filterRules(
|
|||
},
|
||||
}
|
||||
|
||||
if policyContext.ExcludeResourceFunc()(kind, namespace, name) {
|
||||
if cfg.ToFilter(kind, namespace, name) {
|
||||
logging.WithName("ApplyBackgroundChecks").Info("resource excluded", "kind", kind, "namespace", namespace, "name", name)
|
||||
return resp
|
||||
}
|
||||
|
||||
applyRules := policy.GetSpec().GetApplyRules()
|
||||
for _, rule := range autogen.ComputeRules(policy) {
|
||||
if ruleResp := filterRule(contextLoader, rule, policyContext); ruleResp != nil {
|
||||
if ruleResp := filterRule(contextLoader, selector, rule, policyContext, cfg); ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
if applyRules == kyvernov1.ApplyOne && ruleResp.Status != engineapi.RuleStatusSkip {
|
||||
break
|
||||
|
@ -76,8 +81,10 @@ func filterRules(
|
|||
|
||||
func filterRule(
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
rule kyvernov1.Rule,
|
||||
policyContext engineapi.PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) *engineapi.RuleResponse {
|
||||
if !rule.HasGenerate() && !rule.IsMutateExisting() {
|
||||
return nil
|
||||
|
@ -89,7 +96,7 @@ func filterRule(
|
|||
subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext)
|
||||
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(policyContext, &rule, subresourceGVKToAPIResource, logger)
|
||||
ruleResp := hasPolicyExceptions(logger, selector, policyContext, &rule, subresourceGVKToAPIResource, cfg)
|
||||
if ruleResp != nil {
|
||||
return ruleResp
|
||||
}
|
||||
|
@ -106,7 +113,7 @@ func filterRule(
|
|||
oldResource := policyContext.OldResource()
|
||||
admissionInfo := policyContext.AdmissionInfo()
|
||||
ctx := policyContext.JSONContext()
|
||||
excludeGroupRole := policyContext.ExcludeGroupRole()
|
||||
excludeGroupRole := cfg.GetExcludeGroupRole()
|
||||
namespaceLabels := policyContext.NamespaceLabels()
|
||||
|
||||
logger = logging.WithName(string(ruleType)).WithValues("policy", policy.GetName(),
|
||||
|
|
|
@ -10,17 +10,20 @@ import (
|
|||
)
|
||||
|
||||
type engine struct {
|
||||
configuration config.Configuration
|
||||
contextLoader engineapi.ContextLoaderFactory
|
||||
configuration config.Configuration
|
||||
contextLoader engineapi.ContextLoaderFactory
|
||||
exceptionSelector engineapi.PolicyExceptionSelector
|
||||
}
|
||||
|
||||
func NewEngine(
|
||||
configuration config.Configuration,
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
exceptionSelector engineapi.PolicyExceptionSelector,
|
||||
) engineapi.Engine {
|
||||
return &engine{
|
||||
configuration: configuration,
|
||||
contextLoader: contextLoader,
|
||||
configuration: configuration,
|
||||
contextLoader: contextLoader,
|
||||
exceptionSelector: exceptionSelector,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,14 +31,14 @@ func (e *engine) Validate(
|
|||
ctx context.Context,
|
||||
policyContext engineapi.PolicyContext,
|
||||
) *engineapi.EngineResponse {
|
||||
return doValidate(ctx, e.contextLoader, policyContext, e.configuration)
|
||||
return doValidate(ctx, e.contextLoader, e.exceptionSelector, policyContext, e.configuration)
|
||||
}
|
||||
|
||||
func (e *engine) Mutate(
|
||||
ctx context.Context,
|
||||
policyContext engineapi.PolicyContext,
|
||||
) *engineapi.EngineResponse {
|
||||
return doMutate(ctx, e.contextLoader, policyContext)
|
||||
return doMutate(ctx, e.contextLoader, e.exceptionSelector, policyContext, e.configuration)
|
||||
}
|
||||
|
||||
func (e *engine) VerifyAndPatchImages(
|
||||
|
@ -43,20 +46,20 @@ func (e *engine) VerifyAndPatchImages(
|
|||
rclient registryclient.Client,
|
||||
policyContext engineapi.PolicyContext,
|
||||
) (*engineapi.EngineResponse, *engineapi.ImageVerificationMetadata) {
|
||||
return doVerifyAndPatchImages(ctx, e.contextLoader, rclient, policyContext, e.configuration)
|
||||
return doVerifyAndPatchImages(ctx, e.contextLoader, e.exceptionSelector, rclient, policyContext, e.configuration)
|
||||
}
|
||||
|
||||
func (e *engine) ApplyBackgroundChecks(
|
||||
policyContext engineapi.PolicyContext,
|
||||
) *engineapi.EngineResponse {
|
||||
return doApplyBackgroundChecks(e.contextLoader, policyContext)
|
||||
return doApplyBackgroundChecks(e.contextLoader, e.exceptionSelector, policyContext, e.configuration)
|
||||
}
|
||||
|
||||
func (e *engine) GenerateResponse(
|
||||
policyContext engineapi.PolicyContext,
|
||||
gr kyvernov1beta1.UpdateRequest,
|
||||
) *engineapi.EngineResponse {
|
||||
return doGenerateResponse(e.contextLoader, policyContext, gr)
|
||||
return doGenerateResponse(e.contextLoader, e.exceptionSelector, policyContext, gr, e.configuration)
|
||||
}
|
||||
|
||||
func (e *engine) ContextLoader(
|
||||
|
|
103
pkg/engine/exceptions.go
Normal file
103
pkg/engine/exceptions.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
matched "github.com/kyverno/kyverno/pkg/utils/match"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func findExceptions(
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policy kyvernov1.PolicyInterface,
|
||||
rule string,
|
||||
) ([]*kyvernov2alpha1.PolicyException, error) {
|
||||
if selector == nil {
|
||||
return nil, nil
|
||||
}
|
||||
polexs, err := selector.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []*kyvernov2alpha1.PolicyException
|
||||
policyName, err := cache.MetaNamespaceKeyFunc(policy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compute policy key: %w", err)
|
||||
}
|
||||
for _, polex := range polexs {
|
||||
if polex.Contains(policyName, rule) {
|
||||
result = append(result, polex)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// matchesException checks if an exception applies to the resource being admitted
|
||||
func matchesException(
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
subresourceGVKToAPIResource map[string]*metav1.APIResource,
|
||||
cfg config.Configuration,
|
||||
) (*kyvernov2alpha1.PolicyException, error) {
|
||||
candidates, err := findExceptions(selector, policyContext.Policy(), rule.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
err := matched.CheckMatchesResources(
|
||||
policyContext.NewResource(),
|
||||
candidate.Spec.Match,
|
||||
policyContext.NamespaceLabels(),
|
||||
subresourceGVKToAPIResource,
|
||||
policyContext.SubResource(),
|
||||
policyContext.AdmissionInfo(),
|
||||
cfg.GetExcludeGroupRole(),
|
||||
)
|
||||
// if there's no error it means a match
|
||||
if err == nil {
|
||||
return candidate, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// hasPolicyExceptions returns nil when there are no matching exceptions.
|
||||
// A rule response is returned when an exception is matched, or there is an error.
|
||||
func hasPolicyExceptions(
|
||||
log logr.Logger,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
ctx engineapi.PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
subresourceGVKToAPIResource map[string]*metav1.APIResource,
|
||||
cfg config.Configuration,
|
||||
) *engineapi.RuleResponse {
|
||||
// if matches, check if there is a corresponding policy exception
|
||||
exception, err := matchesException(selector, ctx, rule, subresourceGVKToAPIResource, cfg)
|
||||
// if we found an exception
|
||||
if err == nil && exception != nil {
|
||||
key, err := cache.MetaNamespaceKeyFunc(exception)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
||||
return &engineapi.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "failed to find matched exception " + key,
|
||||
Status: engineapi.RuleStatusError,
|
||||
}
|
||||
}
|
||||
log.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
||||
return &engineapi.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "rule skipped due to policy exception " + key,
|
||||
Status: engineapi.RuleStatusSkip,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -5,6 +5,7 @@ import (
|
|||
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
|
@ -13,18 +14,22 @@ import (
|
|||
// GenerateResponse checks for validity of generate rule on the resource
|
||||
func doGenerateResponse(
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
gr kyvernov1beta1.UpdateRequest,
|
||||
cfg config.Configuration,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
policyStartTime := time.Now()
|
||||
return filterGenerateRules(contextLoader, policyContext, gr.Spec.Policy, policyStartTime)
|
||||
return filterGenerateRules(contextLoader, selector, policyContext, gr.Spec.Policy, policyStartTime, cfg)
|
||||
}
|
||||
|
||||
func filterGenerateRules(
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
policyNameKey string,
|
||||
startTime time.Time,
|
||||
cfg config.Configuration,
|
||||
) *engineapi.EngineResponse {
|
||||
newResource := policyContext.NewResource()
|
||||
kind := newResource.GetKind()
|
||||
|
@ -54,13 +59,13 @@ func filterGenerateRules(
|
|||
},
|
||||
},
|
||||
}
|
||||
if policyContext.ExcludeResourceFunc()(kind, namespace, name) {
|
||||
if cfg.ToFilter(kind, namespace, name) {
|
||||
logging.WithName("Generate").Info("resource excluded", "kind", kind, "namespace", namespace, "name", name)
|
||||
return resp
|
||||
}
|
||||
|
||||
for _, rule := range autogen.ComputeRules(policyContext.Policy()) {
|
||||
if ruleResp := filterRule(contextLoader, rule, policyContext); ruleResp != nil {
|
||||
if ruleResp := filterRule(contextLoader, selector, rule, policyContext, cfg); ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import (
|
|||
func doVerifyAndPatchImages(
|
||||
ctx context.Context,
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
rclient registryclient.Client,
|
||||
policyContext engineapi.PolicyContext,
|
||||
cfg config.Configuration,
|
||||
|
@ -73,12 +74,12 @@ func doVerifyAndPatchImages(
|
|||
kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...)
|
||||
subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, policyContext)
|
||||
|
||||
if !matches(logger, rule, policyContext, subresourceGVKToAPIResource) {
|
||||
if !matches(logger, rule, policyContext, subresourceGVKToAPIResource, cfg) {
|
||||
return
|
||||
}
|
||||
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(policyContext, rule, subresourceGVKToAPIResource, logger)
|
||||
ruleResp := hasPolicyExceptions(logger, selector, policyContext, rule, subresourceGVKToAPIResource, cfg)
|
||||
if ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
return
|
||||
|
|
|
@ -170,11 +170,11 @@ func testVerifyAndPatchImages(
|
|||
return doVerifyAndPatchImages(
|
||||
ctx,
|
||||
LegacyContextLoaderFactory(rclient, cmResolver),
|
||||
nil,
|
||||
rclient,
|
||||
pContext,
|
||||
cfg,
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
func Test_CosignMockAttest(t *testing.T) {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
"github.com/kyverno/kyverno/pkg/engine/mutate"
|
||||
"github.com/kyverno/kyverno/pkg/logging"
|
||||
|
@ -24,7 +25,9 @@ import (
|
|||
func doMutate(
|
||||
ctx context.Context,
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
startTime := time.Now()
|
||||
policy := policyContext.Policy()
|
||||
|
@ -62,8 +65,8 @@ func doMutate(
|
|||
func(ctx context.Context, span trace.Span) {
|
||||
logger := logger.WithValues("rule", rule.Name)
|
||||
var excludeResource []string
|
||||
if len(policyContext.ExcludeGroupRole()) > 0 {
|
||||
excludeResource = policyContext.ExcludeGroupRole()
|
||||
if len(cfg.GetExcludeGroupRole()) > 0 {
|
||||
excludeResource = cfg.GetExcludeGroupRole()
|
||||
}
|
||||
|
||||
kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...)
|
||||
|
@ -75,7 +78,7 @@ func doMutate(
|
|||
}
|
||||
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(policyContext, &computeRules[i], subresourceGVKToAPIResource, logger)
|
||||
ruleResp := hasPolicyExceptions(logger, selector, policyContext, &computeRules[i], subresourceGVKToAPIResource, cfg)
|
||||
if ruleResp != nil {
|
||||
resp.PolicyResponse.Rules = append(resp.PolicyResponse.Rules, *ruleResp)
|
||||
return
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
kyverno "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/cmd/cli/kubectl-kyverno/utils/store"
|
||||
client "github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginecontext "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/registryclient"
|
||||
|
@ -28,7 +29,9 @@ func testMutate(
|
|||
return doMutate(
|
||||
ctx,
|
||||
LegacyContextLoaderFactory(rclient, nil),
|
||||
nil,
|
||||
pContext,
|
||||
config.NewDefaultConfiguration(),
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,6 @@ import (
|
|||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov1beta1 "github.com/kyverno/kyverno/api/kyverno/v1beta1"
|
||||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
|
@ -14,16 +13,8 @@ import (
|
|||
admissionv1 "k8s.io/api/admission/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
type PolicyExceptionLister interface {
|
||||
// List lists all PolicyExceptions in the indexer.
|
||||
// Objects returned here must be treated as read-only.
|
||||
List(selector labels.Selector) (ret []*kyvernov2alpha1.PolicyException, err error)
|
||||
}
|
||||
|
||||
// PolicyContext contains the contexts for engine to process
|
||||
type PolicyContext struct {
|
||||
// policy is the policy to be processed
|
||||
|
@ -54,11 +45,6 @@ type PolicyContext struct {
|
|||
// Dynamic client - used for api lookups
|
||||
client dclient.Interface
|
||||
|
||||
// Config handler
|
||||
excludeGroupRole []string
|
||||
|
||||
excludeResourceFunc engineapi.ExcludeFunc
|
||||
|
||||
// jsonContext is the variable context
|
||||
jsonContext enginectx.Interface
|
||||
|
||||
|
@ -75,9 +61,6 @@ type PolicyContext struct {
|
|||
// This is used to determine if a resource is a subresource. It is only used when the policy context is populated
|
||||
// by kyverno CLI. In all other cases when connected to a cluster, this is empty.
|
||||
subresourcesInPolicy []engineapi.SubResource
|
||||
|
||||
// peLister list all policy exceptions
|
||||
peLister PolicyExceptionLister
|
||||
}
|
||||
|
||||
// engineapi.PolicyContext interface
|
||||
|
@ -110,10 +93,6 @@ func (c *PolicyContext) SubresourcesInPolicy() []engineapi.SubResource {
|
|||
return c.subresourcesInPolicy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) ExcludeGroupRole() []string {
|
||||
return c.excludeGroupRole
|
||||
}
|
||||
|
||||
func (c *PolicyContext) AdmissionOperation() bool {
|
||||
return c.admissionOperation
|
||||
}
|
||||
|
@ -142,31 +121,6 @@ func (c PolicyContext) Copy() engineapi.PolicyContext {
|
|||
return c.copy()
|
||||
}
|
||||
|
||||
func (c *PolicyContext) FindExceptions(rule string) ([]*kyvernov2alpha1.PolicyException, error) {
|
||||
if c.peLister == nil {
|
||||
return nil, nil
|
||||
}
|
||||
polexs, err := c.peLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var result []*kyvernov2alpha1.PolicyException
|
||||
policyName, err := cache.MetaNamespaceKeyFunc(c.policy)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to compute policy key: %w", err)
|
||||
}
|
||||
for _, polex := range polexs {
|
||||
if polex.Contains(policyName, rule) {
|
||||
result = append(result, polex)
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (c *PolicyContext) ExcludeResourceFunc() engineapi.ExcludeFunc {
|
||||
return c.excludeResourceFunc
|
||||
}
|
||||
|
||||
// Mutators
|
||||
|
||||
func (c *PolicyContext) WithPolicy(policy kyvernov1.PolicyInterface) *PolicyContext {
|
||||
|
@ -215,23 +169,7 @@ func (c *PolicyContext) WithClient(client dclient.Interface) *PolicyContext {
|
|||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithExcludeGroupRole(excludeGroupRole ...string) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.excludeGroupRole = excludeGroupRole
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithExcludeResourceFunc(excludeResourceFunc engineapi.ExcludeFunc) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.excludeResourceFunc = excludeResourceFunc
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithConfiguration(configuration config.Configuration) *PolicyContext {
|
||||
return c.WithExcludeResourceFunc(configuration.ToFilter).WithExcludeGroupRole(configuration.GetExcludeGroupRole()...)
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithAdmissionOperation(admissionOperation bool) *PolicyContext {
|
||||
func (c *PolicyContext) withAdmissionOperation(admissionOperation bool) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.admissionOperation = admissionOperation
|
||||
return copy
|
||||
|
@ -249,24 +187,15 @@ func (c *PolicyContext) WithSubresourcesInPolicy(subresourcesInPolicy []engineap
|
|||
return copy
|
||||
}
|
||||
|
||||
func (c *PolicyContext) WithExceptions(peLister PolicyExceptionLister) *PolicyContext {
|
||||
copy := c.copy()
|
||||
copy.peLister = peLister
|
||||
return copy
|
||||
}
|
||||
|
||||
func (c PolicyContext) copy() *PolicyContext {
|
||||
return &c
|
||||
}
|
||||
|
||||
// Constructors
|
||||
|
||||
func NewPolicyContextWithJsonContext(jsonContext enginectx.Interface) *PolicyContext {
|
||||
return &PolicyContext{
|
||||
jsonContext: jsonContext,
|
||||
excludeGroupRole: []string{},
|
||||
excludeResourceFunc: func(string, string, string) bool {
|
||||
return false
|
||||
},
|
||||
jsonContext: jsonContext,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -279,7 +208,6 @@ func NewPolicyContextFromAdmissionRequest(
|
|||
admissionInfo kyvernov1beta1.RequestInfo,
|
||||
configuration config.Configuration,
|
||||
client dclient.Interface,
|
||||
polexLister PolicyExceptionLister,
|
||||
) (*PolicyContext, error) {
|
||||
ctx, err := newVariablesContext(request, &admissionInfo)
|
||||
if err != nil {
|
||||
|
@ -297,12 +225,10 @@ func NewPolicyContextFromAdmissionRequest(
|
|||
WithNewResource(newResource).
|
||||
WithOldResource(oldResource).
|
||||
WithAdmissionInfo(admissionInfo).
|
||||
WithConfiguration(configuration).
|
||||
WithClient(client).
|
||||
WithAdmissionOperation(true).
|
||||
withAdmissionOperation(true).
|
||||
WithRequestResource(*requestResource).
|
||||
WithSubresource(request.SubResource).
|
||||
WithExceptions(polexLister)
|
||||
WithSubresource(request.SubResource)
|
||||
return policyContext, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
"github.com/go-logr/logr"
|
||||
gojmespath "github.com/jmespath/go-jmespath"
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
kyvernov2alpha1 "github.com/kyverno/kyverno/api/kyverno/v2alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/autogen"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
|
@ -23,7 +22,6 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/tracing"
|
||||
"github.com/kyverno/kyverno/pkg/utils/api"
|
||||
datautils "github.com/kyverno/kyverno/pkg/utils/data"
|
||||
matched "github.com/kyverno/kyverno/pkg/utils/match"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
appsv1 "k8s.io/api/apps/v1"
|
||||
batchv1 "k8s.io/api/batch/v1"
|
||||
|
@ -31,12 +29,12 @@ import (
|
|||
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func doValidate(
|
||||
ctx context.Context,
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
policyContext engineapi.PolicyContext,
|
||||
cfg config.Configuration,
|
||||
) (resp *engineapi.EngineResponse) {
|
||||
|
@ -50,7 +48,7 @@ func doValidate(
|
|||
logger.V(4).Info("finished policy processing", "processingTime", resp.PolicyResponse.ProcessingTime.String(), "validationRulesApplied", resp.PolicyResponse.RulesAppliedCount)
|
||||
}()
|
||||
|
||||
resp = validateResource(ctx, contextLoader, logger, policyContext, cfg)
|
||||
resp = validateResource(ctx, contextLoader, selector, logger, policyContext, cfg)
|
||||
resp.NamespaceLabels = policyContext.NamespaceLabels()
|
||||
return
|
||||
}
|
||||
|
@ -104,6 +102,7 @@ func buildResponse(ctx engineapi.PolicyContext, resp *engineapi.EngineResponse,
|
|||
func validateResource(
|
||||
ctx context.Context,
|
||||
contextLoader engineapi.ContextLoaderFactory,
|
||||
selector engineapi.PolicyExceptionSelector,
|
||||
log logr.Logger,
|
||||
enginectx engineapi.PolicyContext,
|
||||
cfg config.Configuration,
|
||||
|
@ -149,11 +148,11 @@ func validateResource(
|
|||
kindsInPolicy := append(rule.MatchResources.GetKinds(), rule.ExcludeResources.GetKinds()...)
|
||||
subresourceGVKToAPIResource := GetSubresourceGVKToAPIResourceMap(kindsInPolicy, enginectx)
|
||||
|
||||
if !matches(log, rule, enginectx, subresourceGVKToAPIResource) {
|
||||
if !matches(log, rule, enginectx, subresourceGVKToAPIResource, cfg) {
|
||||
return nil
|
||||
}
|
||||
// check if there is a corresponding policy exception
|
||||
ruleResp := hasPolicyExceptions(enginectx, rule, subresourceGVKToAPIResource, log)
|
||||
ruleResp := hasPolicyExceptions(log, selector, enginectx, rule, subresourceGVKToAPIResource, cfg)
|
||||
if ruleResp != nil {
|
||||
return ruleResp
|
||||
}
|
||||
|
@ -595,14 +594,20 @@ func isEmptyUnstructured(u *unstructured.Unstructured) bool {
|
|||
}
|
||||
|
||||
// matches checks if either the new or old resource satisfies the filter conditions defined in the rule
|
||||
func matches(logger logr.Logger, rule *kyvernov1.Rule, ctx engineapi.PolicyContext, subresourceGVKToAPIResource map[string]*metav1.APIResource) bool {
|
||||
err := MatchesResourceDescription(subresourceGVKToAPIResource, ctx.NewResource(), *rule, ctx.AdmissionInfo(), ctx.ExcludeGroupRole(), ctx.NamespaceLabels(), "", ctx.SubResource())
|
||||
func matches(
|
||||
logger logr.Logger,
|
||||
rule *kyvernov1.Rule,
|
||||
ctx engineapi.PolicyContext,
|
||||
subresourceGVKToAPIResource map[string]*metav1.APIResource,
|
||||
cfg config.Configuration,
|
||||
) bool {
|
||||
err := MatchesResourceDescription(subresourceGVKToAPIResource, ctx.NewResource(), *rule, ctx.AdmissionInfo(), cfg.GetExcludeGroupRole(), ctx.NamespaceLabels(), "", ctx.SubResource())
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
|
||||
err := MatchesResourceDescription(subresourceGVKToAPIResource, ctx.OldResource(), *rule, ctx.AdmissionInfo(), ctx.ExcludeGroupRole(), ctx.NamespaceLabels(), "", ctx.SubResource())
|
||||
err := MatchesResourceDescription(subresourceGVKToAPIResource, ctx.OldResource(), *rule, ctx.AdmissionInfo(), cfg.GetExcludeGroupRole(), ctx.NamespaceLabels(), "", ctx.SubResource())
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
@ -790,57 +795,3 @@ func (v *validator) substituteDeny() error {
|
|||
v.deny = i.(*kyvernov1.Deny)
|
||||
return nil
|
||||
}
|
||||
|
||||
// matchesException checks if an exception applies to the resource being admitted
|
||||
func matchesException(
|
||||
policyContext engineapi.PolicyContext,
|
||||
rule *kyvernov1.Rule,
|
||||
subresourceGVKToAPIResource map[string]*metav1.APIResource,
|
||||
) (*kyvernov2alpha1.PolicyException, error) {
|
||||
candidates, err := policyContext.FindExceptions(rule.Name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, candidate := range candidates {
|
||||
err := matched.CheckMatchesResources(
|
||||
policyContext.NewResource(),
|
||||
candidate.Spec.Match,
|
||||
policyContext.NamespaceLabels(),
|
||||
subresourceGVKToAPIResource,
|
||||
policyContext.SubResource(),
|
||||
policyContext.AdmissionInfo(),
|
||||
policyContext.ExcludeGroupRole(),
|
||||
)
|
||||
// if there's no error it means a match
|
||||
if err == nil {
|
||||
return candidate, nil
|
||||
}
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// hasPolicyExceptions returns nil when there are no matching exceptions.
|
||||
// A rule response is returned when an exception is matched, or there is an error.
|
||||
func hasPolicyExceptions(ctx engineapi.PolicyContext, rule *kyvernov1.Rule, subresourceGVKToAPIResource map[string]*metav1.APIResource, log logr.Logger) *engineapi.RuleResponse {
|
||||
// if matches, check if there is a corresponding policy exception
|
||||
exception, err := matchesException(ctx, rule, subresourceGVKToAPIResource)
|
||||
// if we found an exception
|
||||
if err == nil && exception != nil {
|
||||
key, err := cache.MetaNamespaceKeyFunc(exception)
|
||||
if err != nil {
|
||||
log.Error(err, "failed to compute policy exception key", "namespace", exception.GetNamespace(), "name", exception.GetName())
|
||||
return &engineapi.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "failed to find matched exception " + key,
|
||||
Status: engineapi.RuleStatusError,
|
||||
}
|
||||
}
|
||||
log.V(3).Info("policy rule skipped due to policy exception", "exception", key)
|
||||
return &engineapi.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Message: "rule skipped due to policy exception " + key,
|
||||
Status: engineapi.RuleStatusSkip,
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ func testValidate(ctx context.Context, rclient registryclient.Client, pContext *
|
|||
return doValidate(
|
||||
ctx,
|
||||
LegacyContextLoaderFactory(rclient, nil),
|
||||
nil,
|
||||
pContext,
|
||||
cfg,
|
||||
)
|
||||
|
|
|
@ -146,7 +146,11 @@ func runTestCase(t *testing.T, tc TestCase) bool {
|
|||
}
|
||||
|
||||
policyContext := engine.NewPolicyContext().WithPolicy(policy).WithNewResource(*resource)
|
||||
eng := engine.NewEngine(config.NewDefaultConfiguration(), engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil))
|
||||
eng := engine.NewEngine(
|
||||
config.NewDefaultConfiguration(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil),
|
||||
nil,
|
||||
)
|
||||
er := eng.Mutate(
|
||||
context.TODO(),
|
||||
policyContext,
|
||||
|
|
|
@ -54,8 +54,12 @@ func NewFakeHandlers(ctx context.Context, policyCache policycache.Cache) webhook
|
|||
urGenerator: updaterequest.NewFake(),
|
||||
eventGen: event.NewFake(),
|
||||
openApiManager: openapi.NewFake(),
|
||||
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, dclient, rbLister, crbLister, peLister),
|
||||
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, dclient, rbLister, crbLister),
|
||||
urUpdater: webhookutils.NewUpdateRequestUpdater(kyvernoclient, urLister),
|
||||
engine: engine.NewEngine(configuration, engine.LegacyContextLoaderFactory(rclient, configMapResolver)),
|
||||
engine: engine.NewEngine(
|
||||
configuration,
|
||||
engine.LegacyContextLoaderFactory(rclient, configMapResolver),
|
||||
peLister,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import (
|
|||
kyvernov1beta1listers "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1beta1"
|
||||
"github.com/kyverno/kyverno/pkg/clients/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
engineapi "github.com/kyverno/kyverno/pkg/engine/api"
|
||||
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/event"
|
||||
|
@ -51,11 +50,10 @@ type handlers struct {
|
|||
pCache policycache.Cache
|
||||
|
||||
// listers
|
||||
nsLister corev1listers.NamespaceLister
|
||||
rbLister rbacv1listers.RoleBindingLister
|
||||
crbLister rbacv1listers.ClusterRoleBindingLister
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
polexLister engine.PolicyExceptionLister
|
||||
nsLister corev1listers.NamespaceLister
|
||||
rbLister rbacv1listers.RoleBindingLister
|
||||
crbLister rbacv1listers.ClusterRoleBindingLister
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister
|
||||
|
||||
urGenerator webhookgenerate.Generator
|
||||
eventGen event.Interface
|
||||
|
@ -78,7 +76,6 @@ func NewHandlers(
|
|||
rbLister rbacv1listers.RoleBindingLister,
|
||||
crbLister rbacv1listers.ClusterRoleBindingLister,
|
||||
urLister kyvernov1beta1listers.UpdateRequestNamespaceLister,
|
||||
polexLister engine.PolicyExceptionLister,
|
||||
urGenerator webhookgenerate.Generator,
|
||||
eventGen event.Interface,
|
||||
openApiManager openapi.ValidateInterface,
|
||||
|
@ -96,11 +93,10 @@ func NewHandlers(
|
|||
rbLister: rbLister,
|
||||
crbLister: crbLister,
|
||||
urLister: urLister,
|
||||
polexLister: polexLister,
|
||||
urGenerator: urGenerator,
|
||||
eventGen: eventGen,
|
||||
openApiManager: openApiManager,
|
||||
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, client, rbLister, crbLister, polexLister),
|
||||
pcBuilder: webhookutils.NewPolicyContextBuilder(configuration, client, rbLister, crbLister),
|
||||
urUpdater: webhookutils.NewUpdateRequestUpdater(kyvernoClient, urLister),
|
||||
admissionReports: admissionReports,
|
||||
}
|
||||
|
|
|
@ -1052,6 +1052,7 @@ func TestValidate_failure_action_overrides(t *testing.T) {
|
|||
eng := engine.NewEngine(
|
||||
config.NewDefaultConfiguration(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil),
|
||||
nil,
|
||||
)
|
||||
for i, tc := range testcases {
|
||||
t.Run(fmt.Sprintf("case %d", i), func(t *testing.T) {
|
||||
|
@ -1128,6 +1129,7 @@ func Test_RuleSelector(t *testing.T) {
|
|||
eng := engine.NewEngine(
|
||||
config.NewDefaultConfiguration(),
|
||||
engine.LegacyContextLoaderFactory(registryclient.NewOrDie(), nil),
|
||||
nil,
|
||||
)
|
||||
resp := eng.Validate(
|
||||
context.TODO(),
|
||||
|
|
|
@ -21,7 +21,6 @@ type policyContextBuilder struct {
|
|||
client dclient.Interface
|
||||
rbLister rbacv1listers.RoleBindingLister
|
||||
crbLister rbacv1listers.ClusterRoleBindingLister
|
||||
polexLister engine.PolicyExceptionLister
|
||||
}
|
||||
|
||||
func NewPolicyContextBuilder(
|
||||
|
@ -29,14 +28,12 @@ func NewPolicyContextBuilder(
|
|||
client dclient.Interface,
|
||||
rbLister rbacv1listers.RoleBindingLister,
|
||||
crbLister rbacv1listers.ClusterRoleBindingLister,
|
||||
polexLister engine.PolicyExceptionLister,
|
||||
) PolicyContextBuilder {
|
||||
return &policyContextBuilder{
|
||||
configuration: configuration,
|
||||
client: client,
|
||||
rbLister: rbLister,
|
||||
crbLister: crbLister,
|
||||
polexLister: polexLister,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,5 +47,5 @@ func (b *policyContextBuilder) Build(request *admissionv1.AdmissionRequest) (*en
|
|||
userRequestInfo.Roles = roles
|
||||
userRequestInfo.ClusterRoles = clusterRoles
|
||||
}
|
||||
return engine.NewPolicyContextFromAdmissionRequest(request, userRequestInfo, b.configuration, b.client, b.polexLister)
|
||||
return engine.NewPolicyContextFromAdmissionRequest(request, userRequestInfo, b.configuration, b.client)
|
||||
}
|
||||
|
|
|
@ -15,19 +15,23 @@ cleanupController:
|
|||
resources:
|
||||
- pods
|
||||
|
||||
reportsController:
|
||||
extraArgs:
|
||||
- --enablePolicyException
|
||||
|
||||
backgroundController:
|
||||
rbac:
|
||||
clusterRole:
|
||||
extraResources:
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- configmaps
|
||||
- secrets
|
||||
- roles
|
||||
- rolebindings
|
||||
- limitranges
|
||||
- namespaces
|
||||
- nodes
|
||||
- nodes/status
|
||||
- pods
|
||||
- apiGroups:
|
||||
- '*'
|
||||
resources:
|
||||
- configmaps
|
||||
- secrets
|
||||
- roles
|
||||
- rolebindings
|
||||
- limitranges
|
||||
- namespaces
|
||||
- nodes
|
||||
- nodes/status
|
||||
- pods
|
||||
|
|
|
@ -2,6 +2,7 @@ apiVersion: kyverno.io/v2alpha1
|
|||
kind: PolicyException
|
||||
metadata:
|
||||
name: mynewpolex
|
||||
namespace: kyverno
|
||||
spec:
|
||||
exceptions:
|
||||
- policyName: require-labels
|
||||
|
|
Loading…
Add table
Reference in a new issue