mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-21 07:12:42 +00:00
Implement Reporting and Background scan for ImageVerificationPolicy (#12432)
Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>
This commit is contained in:
parent
c0ab93b95b
commit
f869638edf
13 changed files with 234 additions and 15 deletions
|
@ -83,6 +83,7 @@ func createReportControllers(
|
|||
kyvernoV1.Policies(),
|
||||
kyvernoV1.ClusterPolicies(),
|
||||
policiesV1alpha1.ValidatingPolicies(),
|
||||
policiesV1alpha1.ImageVerificationPolicies(),
|
||||
vapInformer,
|
||||
)
|
||||
warmups = append(warmups, func(ctx context.Context) error {
|
||||
|
@ -103,6 +104,7 @@ func createReportControllers(
|
|||
kyvernoV1.Policies(),
|
||||
kyvernoV1.ClusterPolicies(),
|
||||
policiesV1alpha1.ValidatingPolicies(),
|
||||
policiesV1alpha1.ImageVerificationPolicies(),
|
||||
vapInformer,
|
||||
),
|
||||
aggregationWorkers,
|
||||
|
@ -117,6 +119,7 @@ func createReportControllers(
|
|||
kyvernoV1.Policies(),
|
||||
kyvernoV1.ClusterPolicies(),
|
||||
policiesV1alpha1.ValidatingPolicies(),
|
||||
policiesV1alpha1.ImageVerificationPolicies(),
|
||||
policiesV1alpha1.CELPolicyExceptions(),
|
||||
kyvernoV2.PolicyExceptions(),
|
||||
vapInformer,
|
||||
|
|
43
pkg/cel/engine/ivpolprovider.go
Normal file
43
pkg/cel/engine/ivpolprovider.go
Normal file
|
@ -0,0 +1,43 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/kyverno/kyverno/api/policies.kyverno.io/v1alpha1"
|
||||
"github.com/kyverno/kyverno/pkg/cel/autogen"
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
"k8s.io/apimachinery/pkg/util/sets"
|
||||
)
|
||||
|
||||
func NewIVPOLProvider(policies []v1alpha1.ImageVerificationPolicy) (ImageVerifyPolProviderFunc, error) {
|
||||
compiled := make([]CompiledImageVerificationPolicy, 0, len(policies))
|
||||
for _, policy := range policies {
|
||||
p := policy
|
||||
actions := sets.New(policy.Spec.ValidationAction...)
|
||||
if len(actions) == 0 {
|
||||
actions.Insert(admissionregistrationv1.Deny)
|
||||
}
|
||||
compiled = append(compiled, CompiledImageVerificationPolicy{
|
||||
Actions: actions,
|
||||
Policy: &p,
|
||||
})
|
||||
|
||||
autogeneratedIvPols, err := autogen.GetAutogenRulesImageVerify(&p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, ap := range autogeneratedIvPols {
|
||||
compiled = append(compiled, CompiledImageVerificationPolicy{
|
||||
Actions: actions,
|
||||
Policy: &v1alpha1.ImageVerificationPolicy{
|
||||
Spec: ap.Spec,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
provider := func(context.Context) ([]CompiledImageVerificationPolicy, error) {
|
||||
return compiled, nil
|
||||
}
|
||||
return provider, nil
|
||||
}
|
|
@ -5,8 +5,14 @@ import (
|
|||
"github.com/kyverno/kyverno/pkg/utils/slices"
|
||||
)
|
||||
|
||||
func RemoveNoneBackgroundPolicies(policies []v1alpha1.ValidatingPolicy) []v1alpha1.ValidatingPolicy {
|
||||
func RemoveNoneBackgroundValidatingPolicies(policies []v1alpha1.ValidatingPolicy) []v1alpha1.ValidatingPolicy {
|
||||
return slices.Filter(policies, func(vp v1alpha1.ValidatingPolicy) bool {
|
||||
return vp.Spec.BackgroundEnabled()
|
||||
})
|
||||
}
|
||||
|
||||
func RemoveNoneBackgroundImageVerificationPolicies(policies []v1alpha1.ImageVerificationPolicy) []v1alpha1.ImageVerificationPolicy {
|
||||
return slices.Filter(policies, func(vp v1alpha1.ImageVerificationPolicy) bool {
|
||||
return vp.Spec.BackgroundEnabled()
|
||||
})
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ func TestRemoveNoneBackgroundPolicies(t *testing.T) {
|
|||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := RemoveNoneBackgroundPolicies(tt.policies)
|
||||
got := RemoveNoneBackgroundValidatingPolicies(tt.policies)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
|
|
|
@ -53,6 +53,7 @@ type controller struct {
|
|||
polLister kyvernov1listers.PolicyLister
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
vpolLister policiesv1alpha1listers.ValidatingPolicyLister
|
||||
ivpolLister policiesv1alpha1listers.ImageVerificationPolicyLister
|
||||
vapLister admissionregistrationv1listers.ValidatingAdmissionPolicyLister
|
||||
ephrLister cache.GenericLister
|
||||
cephrLister cache.GenericLister
|
||||
|
@ -74,6 +75,7 @@ func NewController(
|
|||
polInformer kyvernov1informers.PolicyInformer,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
vpolInformer policiesv1alpha1informers.ValidatingPolicyInformer,
|
||||
ivpolInformer policiesv1alpha1informers.ImageVerificationPolicyInformer,
|
||||
vapInformer admissionregistrationv1informers.ValidatingAdmissionPolicyInformer,
|
||||
) controllers.Controller {
|
||||
ephrInformer := metadataFactory.ForResource(reportsv1.SchemeGroupVersion.WithResource("ephemeralreports"))
|
||||
|
@ -144,6 +146,17 @@ func NewController(
|
|||
logger.Error(err, "failed to register event handlers")
|
||||
}
|
||||
}
|
||||
if ivpolInformer != nil {
|
||||
c.ivpolLister = ivpolInformer.Lister()
|
||||
if _, err := controllerutils.AddEventHandlersT(
|
||||
ivpolInformer.Informer(),
|
||||
func(_ metav1.Object) { enqueueAll() },
|
||||
func(_, _ metav1.Object) { enqueueAll() },
|
||||
func(_ metav1.Object) { enqueueAll() },
|
||||
); err != nil {
|
||||
logger.Error(err, "failed to register event handlers")
|
||||
}
|
||||
}
|
||||
if vapInformer != nil {
|
||||
c.vapLister = vapInformer.Lister()
|
||||
if _, err := controllerutils.AddEventHandlersT(
|
||||
|
@ -230,6 +243,20 @@ func (c *controller) createVPolMap() (sets.Set[string], error) {
|
|||
return results, nil
|
||||
}
|
||||
|
||||
func (c *controller) createIVPolMap() (sets.Set[string], error) {
|
||||
results := sets.New[string]()
|
||||
if c.ivpolLister != nil {
|
||||
ivpols, err := c.ivpolLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, ivpol := range ivpols {
|
||||
results.Insert(cache.MetaObjectToName(ivpol).String())
|
||||
}
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (c *controller) findOwnedEphemeralReports(ctx context.Context, namespace, name string) ([]reportsv1.ReportInterface, error) {
|
||||
selector, err := reportutils.SelectorResourceUidEquals(types.UID(name))
|
||||
if err != nil {
|
||||
|
@ -454,10 +481,15 @@ func (c *controller) backReconcile(ctx context.Context, logger logr.Logger, _, n
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ivpolMap, err := c.createIVPolMap()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
maps := maps{
|
||||
pol: policyMap,
|
||||
vap: vapMap,
|
||||
vpol: vpolMap,
|
||||
pol: policyMap,
|
||||
vap: vapMap,
|
||||
vpol: vpolMap,
|
||||
ivpol: ivpolMap,
|
||||
}
|
||||
reports = append(reports, ephemeralReports...)
|
||||
merged := map[string]policyreportv1alpha2.PolicyReportResult{}
|
||||
|
|
|
@ -59,7 +59,7 @@ func TestController(t *testing.T) {
|
|||
metaClient.CreateFake(&metav1.PartialObjectMetadata{ObjectMeta: kyvernoPolr.ObjectMeta}, metav1.CreateOptions{})
|
||||
metaClient.CreateFake(&metav1.PartialObjectMetadata{ObjectMeta: notKyvernoPolr.ObjectMeta}, metav1.CreateOptions{})
|
||||
|
||||
controller := aggregate.NewController(client, nil, metaFactory, polInformer, cpolInformer, nil, nil)
|
||||
controller := aggregate.NewController(client, nil, metaFactory, polInformer, cpolInformer, nil, nil, nil)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
|
|
@ -16,9 +16,10 @@ import (
|
|||
)
|
||||
|
||||
type maps struct {
|
||||
pol map[string]policyMapEntry
|
||||
vap sets.Set[string]
|
||||
vpol sets.Set[string]
|
||||
pol map[string]policyMapEntry
|
||||
vap sets.Set[string]
|
||||
vpol sets.Set[string]
|
||||
ivpol sets.Set[string]
|
||||
}
|
||||
|
||||
func mergeReports(maps maps, accumulator map[string]policyreportv1alpha2.PolicyReportResult, uid types.UID, reports ...reportsv1.ReportInterface) {
|
||||
|
@ -37,6 +38,15 @@ func mergeReports(maps maps, accumulator map[string]policyreportv1alpha2.PolicyR
|
|||
accumulator[key] = result
|
||||
}
|
||||
}
|
||||
case reportutils.SourceImageVerificationPolicy:
|
||||
if maps.ivpol != nil && maps.ivpol.Has(result.Policy) {
|
||||
key := result.Source + "/" + result.Policy + "/" + string(uid)
|
||||
if rule, exists := accumulator[key]; !exists {
|
||||
accumulator[key] = result
|
||||
} else if rule.Timestamp.Seconds < result.Timestamp.Seconds {
|
||||
accumulator[key] = result
|
||||
}
|
||||
}
|
||||
case reportutils.SourceValidatingAdmissionPolicy:
|
||||
if maps.vap != nil && maps.vap.Has(result.Policy) {
|
||||
key := result.Source + "/" + result.Policy + "/" + string(uid)
|
||||
|
|
|
@ -65,6 +65,7 @@ type controller struct {
|
|||
polLister kyvernov1listers.PolicyLister
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
vpolLister policiesv1alpha1listers.ValidatingPolicyLister
|
||||
ivpolLister policiesv1alpha1listers.ImageVerificationPolicyLister
|
||||
polexLister kyvernov2listers.PolicyExceptionLister
|
||||
celpolexListener policiesv1alpha1listers.CELPolicyExceptionLister
|
||||
vapLister admissionregistrationv1listers.ValidatingAdmissionPolicyLister
|
||||
|
@ -97,6 +98,7 @@ func NewController(
|
|||
polInformer kyvernov1informers.PolicyInformer,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
vpolInformer policiesv1alpha1informers.ValidatingPolicyInformer,
|
||||
ivpolInformer policiesv1alpha1informers.ImageVerificationPolicyInformer,
|
||||
celpolexlInformer policiesv1alpha1informers.CELPolicyExceptionInformer,
|
||||
polexInformer kyvernov2informers.PolicyExceptionInformer,
|
||||
vapInformer admissionregistrationv1informers.ValidatingAdmissionPolicyInformer,
|
||||
|
@ -143,6 +145,12 @@ func NewController(
|
|||
logger.Error(err, "failed to register event handlers")
|
||||
}
|
||||
}
|
||||
if ivpolInformer != nil {
|
||||
c.ivpolLister = ivpolInformer.Lister()
|
||||
if _, err := controllerutils.AddEventHandlersT(ivpolInformer.Informer(), c.addIVP, c.updateIVP, c.deleteIVP); err != nil {
|
||||
logger.Error(err, "failed to register event handlers")
|
||||
}
|
||||
}
|
||||
if celpolexlInformer != nil {
|
||||
c.celpolexListener = celpolexlInformer.Lister()
|
||||
if _, err := controllerutils.AddEventHandlersT(celpolexlInformer.Informer(), c.addCELException, c.updateCELException, c.deleteCELPolicy); err != nil {
|
||||
|
@ -245,6 +253,20 @@ func (c *controller) deleteVP(obj *policiesv1alpha1.ValidatingPolicy) {
|
|||
c.enqueueResources()
|
||||
}
|
||||
|
||||
func (c *controller) addIVP(obj *policiesv1alpha1.ImageVerificationPolicy) {
|
||||
c.enqueueResources()
|
||||
}
|
||||
|
||||
func (c *controller) updateIVP(old, obj *policiesv1alpha1.ImageVerificationPolicy) {
|
||||
if old.GetResourceVersion() != obj.GetResourceVersion() {
|
||||
c.enqueueResources()
|
||||
}
|
||||
}
|
||||
|
||||
func (c *controller) deleteIVP(obj *policiesv1alpha1.ImageVerificationPolicy) {
|
||||
c.enqueueResources()
|
||||
}
|
||||
|
||||
func (c *controller) addVAP(obj *admissionregistrationv1.ValidatingAdmissionPolicy) {
|
||||
c.enqueueResources()
|
||||
}
|
||||
|
@ -418,6 +440,8 @@ func (c *controller) reconcileReport(
|
|||
key = cache.MetaObjectToName(policy.AsValidatingAdmissionPolicy()).String()
|
||||
} else if policy.AsValidatingPolicy() != nil {
|
||||
key = cache.MetaObjectToName(policy.AsValidatingPolicy()).String()
|
||||
} else if policy.AsImageVerificationPolicy() != nil {
|
||||
key = cache.MetaObjectToName(policy.AsImageVerificationPolicy()).String()
|
||||
}
|
||||
policyNameToLabel[key] = reportutils.PolicyLabel(policy)
|
||||
}
|
||||
|
@ -586,10 +610,20 @@ func (c *controller) reconcile(ctx context.Context, log logr.Logger, key, namesp
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, vpol := range policy.RemoveNoneBackgroundPolicies(vpols) {
|
||||
for _, vpol := range policy.RemoveNoneBackgroundValidatingPolicies(vpols) {
|
||||
policies = append(policies, engineapi.NewValidatingPolicy(&vpol))
|
||||
}
|
||||
}
|
||||
if c.ivpolLister != nil {
|
||||
// load validating policies
|
||||
ivpols, err := utils.FetchImageVerificationPolicies(c.ivpolLister)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, vpol := range policy.RemoveNoneBackgroundImageVerificationPolicies(ivpols) {
|
||||
policies = append(policies, engineapi.NewImageVerificationPolicy(&vpol))
|
||||
}
|
||||
}
|
||||
if c.vapLister != nil {
|
||||
// load validating admission policies
|
||||
vapPolicies, err := utils.FetchValidatingAdmissionPolicies(c.vapLister)
|
||||
|
|
|
@ -79,10 +79,11 @@ type controller struct {
|
|||
client dclient.Interface
|
||||
|
||||
// listers
|
||||
polLister kyvernov1listers.PolicyLister
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
vpolLister policiesv1alpha1listers.ValidatingPolicyLister
|
||||
vapLister admissionregistrationv1listers.ValidatingAdmissionPolicyLister
|
||||
polLister kyvernov1listers.PolicyLister
|
||||
cpolLister kyvernov1listers.ClusterPolicyLister
|
||||
vpolLister policiesv1alpha1listers.ValidatingPolicyLister
|
||||
ivpolLister policiesv1alpha1listers.ImageVerificationPolicyLister
|
||||
vapLister admissionregistrationv1listers.ValidatingAdmissionPolicyLister
|
||||
|
||||
// queue
|
||||
queue workqueue.TypedRateLimitingInterface[any]
|
||||
|
@ -97,6 +98,7 @@ func NewController(
|
|||
polInformer kyvernov1informers.PolicyInformer,
|
||||
cpolInformer kyvernov1informers.ClusterPolicyInformer,
|
||||
vpolInformer policiesv1alpha1informers.ValidatingPolicyInformer,
|
||||
ivpolInformer policiesv1alpha1informers.ImageVerificationPolicyInformer,
|
||||
vapInformer admissionregistrationv1informers.ValidatingAdmissionPolicyInformer,
|
||||
) Controller {
|
||||
c := controller{
|
||||
|
@ -115,6 +117,12 @@ func NewController(
|
|||
logger.Error(err, "failed to register event handlers")
|
||||
}
|
||||
}
|
||||
if ivpolInformer != nil {
|
||||
c.ivpolLister = ivpolInformer.Lister()
|
||||
if _, _, err := controllerutils.AddDefaultEventHandlers(logger, ivpolInformer.Informer(), c.queue); err != nil {
|
||||
logger.Error(err, "failed to register event handlers")
|
||||
}
|
||||
}
|
||||
if vapInformer != nil {
|
||||
c.vapLister = vapInformer.Lister()
|
||||
if _, _, err := controllerutils.AddDefaultEventHandlers(logger, vapInformer.Informer(), c.queue); err != nil {
|
||||
|
@ -280,6 +288,20 @@ func (c *controller) updateDynamicWatchers(ctx context.Context) error {
|
|||
}
|
||||
}
|
||||
}
|
||||
if c.ivpolLister != nil {
|
||||
ivpols, err := utils.FetchImageVerificationPolicies(c.ivpolLister)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// fetch kinds from image verification admission policies
|
||||
for _, policy := range ivpols {
|
||||
kinds := admissionpolicy.GetKinds(policy.Spec.MatchConstraints)
|
||||
for _, kind := range kinds {
|
||||
group, version, kind, subresource := kubeutils.ParseKindSelector(kind)
|
||||
c.addGVKToGVRMapping(group, version, kind, subresource, gvkToGvr)
|
||||
}
|
||||
}
|
||||
}
|
||||
dynamicWatchers := map[schema.GroupVersionResource]*watcher{}
|
||||
for gvk, gvr := range gvkToGvr {
|
||||
logger := logger.WithValues("gvr", gvr, "gvk", gvk)
|
||||
|
|
|
@ -82,13 +82,15 @@ func (s *scanner) ScanResource(
|
|||
exceptions []*policiesv1alpha1.CELPolicyException,
|
||||
policies ...engineapi.GenericPolicy,
|
||||
) map[*engineapi.GenericPolicy]ScanResult {
|
||||
var kpols, vpols, vaps []engineapi.GenericPolicy
|
||||
var kpols, vpols, ivpols, vaps []engineapi.GenericPolicy
|
||||
// split policies per nature
|
||||
for _, policy := range policies {
|
||||
if pol := policy.AsKyvernoPolicy(); pol != nil {
|
||||
kpols = append(kpols, policy)
|
||||
} else if pol := policy.AsValidatingPolicy(); pol != nil {
|
||||
vpols = append(vpols, policy)
|
||||
} else if pol := policy.AsImageVerificationPolicy(); pol != nil {
|
||||
ivpols = append(vpols, policy)
|
||||
} else if pol := policy.AsValidatingAdmissionPolicy(); pol != nil {
|
||||
vaps = append(vaps, policy)
|
||||
}
|
||||
|
@ -195,6 +197,57 @@ func (s *scanner) ScanResource(
|
|||
results[&vpols[i]] = ScanResult{&response, err}
|
||||
}
|
||||
}
|
||||
|
||||
// evaluate image verification policies
|
||||
for i, policy := range ivpols {
|
||||
if pol := policy.AsImageVerificationPolicy(); pol != nil {
|
||||
// create provider
|
||||
provider, err := celengine.NewIVPOLProvider([]policiesv1alpha1.ImageVerificationPolicy{*pol})
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to create image verification policy provider")
|
||||
results[&vpols[i]] = ScanResult{nil, err}
|
||||
continue
|
||||
}
|
||||
// create engine
|
||||
engine := celengine.NewImageVerifyEngine(
|
||||
provider,
|
||||
func(name string) *corev1.Namespace { return ns },
|
||||
matching.NewMatcher(),
|
||||
s.client.GetKubeClient().CoreV1().Secrets(""),
|
||||
nil,
|
||||
)
|
||||
// create context provider
|
||||
context, err := celpolicy.NewContextProvider(s.client, nil, gctxstore.New())
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to create cel context provider")
|
||||
results[&vpols[i]] = ScanResult{nil, err}
|
||||
continue
|
||||
}
|
||||
request := celengine.Request(
|
||||
context,
|
||||
resource.GroupVersionKind(),
|
||||
gvr,
|
||||
subResource,
|
||||
resource.GetName(),
|
||||
resource.GetNamespace(),
|
||||
admissionv1.Create,
|
||||
authenticationv1.UserInfo{},
|
||||
&resource,
|
||||
nil,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
engineResponse, _, err := engine.HandleMutating(ctx, request)
|
||||
response := engineapi.EngineResponse{
|
||||
Resource: resource,
|
||||
PolicyResponse: engineapi.PolicyResponse{
|
||||
// TODO: policies at index 0
|
||||
Rules: []engineapi.RuleResponse{engineResponse.Policies[0].Result},
|
||||
},
|
||||
}.WithPolicy(vpols[i])
|
||||
results[&vpols[i]] = ScanResult{&response, err}
|
||||
}
|
||||
}
|
||||
// evaluate validating admission policies
|
||||
for i, policy := range vaps {
|
||||
if pol := policy.AsValidatingAdmissionPolicy(); pol != nil {
|
||||
|
|
|
@ -163,6 +163,18 @@ func FetchValidatingPolicies(vpolLister policiesv1alpha1listers.ValidatingPolicy
|
|||
return policies, nil
|
||||
}
|
||||
|
||||
func FetchImageVerificationPolicies(ivpolLister policiesv1alpha1listers.ImageVerificationPolicyLister) ([]policiesv1alpha1.ImageVerificationPolicy, error) {
|
||||
var policies []policiesv1alpha1.ImageVerificationPolicy
|
||||
if pols, err := ivpolLister.List(labels.Everything()); err != nil {
|
||||
return nil, err
|
||||
} else {
|
||||
for _, pol := range pols {
|
||||
policies = append(policies, *pol)
|
||||
}
|
||||
}
|
||||
return policies, nil
|
||||
}
|
||||
|
||||
func FetchCELPolicyExceptions(celexLister policiesv1alpha1listers.CELPolicyExceptionLister, namespace string) ([]*policiesv1alpha1.CELPolicyException, error) {
|
||||
exceptions, err := celexLister.CELPolicyExceptions(namespace).List(labels.Everything())
|
||||
if err != nil {
|
||||
|
|
|
@ -147,6 +147,9 @@ func ToPolicyReportResult(pol engineapi.GenericPolicy, ruleResult engineapi.Rule
|
|||
if pol.AsValidatingPolicy() != nil {
|
||||
result.Source = SourceValidatingPolicy
|
||||
}
|
||||
if pol.AsImageVerificationPolicy() != nil {
|
||||
result.Source = SourceImageVerificationPolicy
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -8,4 +8,5 @@ const (
|
|||
SourceKyverno = kyverno.ValueKyvernoApp
|
||||
SourceValidatingAdmissionPolicy = "ValidatingAdmissionPolicy"
|
||||
SourceValidatingPolicy = "KyvernoValidatingPolicy"
|
||||
SourceImageVerificationPolicy = "KyvernoImageVerificationPolicy"
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue