mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-29 02:45:06 +00:00
namespace selector (#1532)
* updated crd with namespace selector Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added logic for validate Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added condition in utils for namespace labels Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added function for extracting namespace label using lister Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added logic for generate Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added lister in generate Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * commented generate controller changes Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added ns lister Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added ns label in apply.go Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added ns label in generation.go Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added ns label in mutation.go Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * added ns label for validation Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com> * using dynaminc informer Signed-off-by: NoSkillGirl <singhpooja240393@gmail.com>
This commit is contained in:
parent
f2478921e9
commit
32522e7827
22 changed files with 642 additions and 52 deletions
|
@ -140,6 +140,58 @@ spec:
|
|||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names for the user.
|
||||
|
@ -260,6 +312,58 @@ spec:
|
|||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names for the user.
|
||||
|
@ -1259,6 +1363,58 @@ spec:
|
|||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names for the user.
|
||||
|
@ -1379,6 +1535,58 @@ spec:
|
|||
description: matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels map is equivalent to an element of matchExpressions, whose key field is "key", the operator is "In", and the values array contains only "value". The requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names for the user.
|
||||
|
|
|
@ -274,6 +274,7 @@ func main() {
|
|||
reportReqGen,
|
||||
kubeInformer.Rbac().V1().RoleBindings(),
|
||||
kubeInformer.Rbac().V1().ClusterRoleBindings(),
|
||||
kubeInformer.Core().V1().Namespaces(),
|
||||
log.Log.WithName("ValidateAuditHandler"),
|
||||
configData,
|
||||
rCache,
|
||||
|
@ -321,6 +322,7 @@ func main() {
|
|||
kubeInformer.Rbac().V1().ClusterRoleBindings(),
|
||||
kubeInformer.Rbac().V1().Roles(),
|
||||
kubeInformer.Rbac().V1().ClusterRoles(),
|
||||
kubeInformer.Core().V1().Namespaces(),
|
||||
eventGenerator,
|
||||
pCacheController.Cache,
|
||||
webhookCfg,
|
||||
|
|
|
@ -197,6 +197,58 @@ spec:
|
|||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names
|
||||
|
@ -379,6 +431,58 @@ spec:
|
|||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names
|
||||
|
|
|
@ -198,6 +198,58 @@ spec:
|
|||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names
|
||||
|
@ -380,6 +432,58 @@ spec:
|
|||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
namespaceSelector:
|
||||
description: 'NamespaceSelector is a label selector for namespace.
|
||||
Label keys and values in `matchLabels` support the wildcard
|
||||
characters `*` (matches zero or many characters) and `?`
|
||||
(matches one character). Wildcards allows writing label
|
||||
selectors like ["storage.k8s.io/*": "*"]. Note that using
|
||||
["*" : "*"] matches any key and value but does not match
|
||||
an empty label set.'
|
||||
properties:
|
||||
matchExpressions:
|
||||
description: matchExpressions is a list of label
|
||||
selector requirements. The requirements are ANDed.
|
||||
items:
|
||||
description: A label selector requirement is a
|
||||
selector that contains values, a key, and an
|
||||
operator that relates the key and values.
|
||||
properties:
|
||||
key:
|
||||
description: key is the label key that the
|
||||
selector applies to.
|
||||
type: string
|
||||
operator:
|
||||
description: operator represents a key's relationship
|
||||
to a set of values. Valid operators are
|
||||
In, NotIn, Exists and DoesNotExist.
|
||||
type: string
|
||||
values:
|
||||
description: values is an array of string
|
||||
values. If the operator is In or NotIn,
|
||||
the values array must be non-empty. If the
|
||||
operator is Exists or DoesNotExist, the
|
||||
values array must be empty. This array is
|
||||
replaced during a strategic merge patch.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- key
|
||||
- operator
|
||||
type: object
|
||||
type: array
|
||||
matchLabels:
|
||||
additionalProperties:
|
||||
type: string
|
||||
description: matchLabels is a map of {key,value}
|
||||
pairs. A single {key,value} in the matchLabels
|
||||
map is equivalent to an element of matchExpressions,
|
||||
whose key field is "key", the operator is "In",
|
||||
and the values array contains only "value". The
|
||||
requirements are ANDed.
|
||||
type: object
|
||||
type: object
|
||||
type: object
|
||||
roles:
|
||||
description: Roles is the list of namespaced role names
|
||||
|
|
|
@ -238,6 +238,14 @@ type ResourceDescription struct {
|
|||
// using ["*" : "*"] matches any key and value but does not match an empty label set.
|
||||
// +optional
|
||||
Selector *metav1.LabelSelector `json:"selector,omitempty" yaml:"selector,omitempty"`
|
||||
|
||||
// NamespaceSelector is a label selector for the resource namespace. Label keys and values
|
||||
// in `matchLabels` support the wildcard characters `*` (matches zero or many characters)
|
||||
// and `?` (matches one character).Wildcards allows writing label selectors like
|
||||
// ["storage.k8s.io/*": "*"]. Note that using ["*" : "*"] matches any key and value but
|
||||
// does not match an empty label set.
|
||||
// +optional
|
||||
NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty" yaml:"namespaceSelector,omitempty"`
|
||||
}
|
||||
|
||||
// Mutation defines how resource are modified.
|
||||
|
|
|
@ -1,5 +1,16 @@
|
|||
package common
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
enginutils "github.com/kyverno/kyverno/pkg/engine/utils"
|
||||
v1 "k8s.io/api/core/v1"
|
||||
"k8s.io/client-go/informers"
|
||||
listerv1 "k8s.io/client-go/listers/core/v1"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
// Policy Reporting Modes
|
||||
const (
|
||||
Enforce = "enforce" // blocks the request on failure
|
||||
|
@ -11,3 +22,43 @@ const (
|
|||
PolicyViolation = "POLICYVIOLATION"
|
||||
PolicyReport = "POLICYREPORT"
|
||||
)
|
||||
|
||||
// GetNamespaceSelectorsFromGenericInformer - extracting the namespacelabels when generic informer is passed
|
||||
func GetNamespaceSelectorsFromGenericInformer(kind, namespaceOfResource string, nsInformer informers.GenericInformer, logger logr.Logger) map[string]string {
|
||||
namespaceLabels := make(map[string]string)
|
||||
if kind != "Namespace" {
|
||||
runtimeNamespaceObj, err := nsInformer.Lister().Get(namespaceOfResource)
|
||||
namespaceObj := runtimeNamespaceObj.(*v1.Namespace)
|
||||
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to get the namespace", "name", namespaceOfResource)
|
||||
}
|
||||
return GetNamespaceLabels(namespaceObj, logger)
|
||||
}
|
||||
|
||||
return namespaceLabels
|
||||
}
|
||||
|
||||
// GetNamespaceSelectorsFromNamespaceLister - extract the namespacelabels when namespace lister is passed
|
||||
func GetNamespaceSelectorsFromNamespaceLister(kind, namespaceOfResource string, nsLister listerv1.NamespaceLister, logger logr.Logger) map[string]string {
|
||||
namespaceLabels := make(map[string]string)
|
||||
if kind != "Namespace" {
|
||||
namespaceObj, err := nsLister.Get(namespaceOfResource)
|
||||
if err != nil {
|
||||
log.Log.Error(err, "failed to get the namespace", "name", namespaceOfResource)
|
||||
}
|
||||
return GetNamespaceLabels(namespaceObj, logger)
|
||||
}
|
||||
return namespaceLabels
|
||||
}
|
||||
|
||||
// GetNamespaceLabels - from namespace obj
|
||||
func GetNamespaceLabels(namespaceObj *v1.Namespace, logger logr.Logger) map[string]string {
|
||||
namespaceObj.Kind = "Namespace"
|
||||
namespaceRaw, err := json.Marshal(namespaceObj)
|
||||
namespaceUnstructured, err := enginutils.ConvertToUnstructured(namespaceRaw)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to convert object resource to unstructured format")
|
||||
}
|
||||
return namespaceUnstructured.GetLabels()
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package engine
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Generate checks for validity of generate rule on the resource
|
||||
|
@ -60,14 +61,15 @@ func filterRule(rule kyverno.Rule, policyContext *PolicyContext) *response.RuleR
|
|||
ctx := policyContext.JSONContext
|
||||
resCache := policyContext.ResourceCache
|
||||
excludeGroupRole := policyContext.ExcludeGroupRole
|
||||
namespaceLabels := policyContext.NamespaceLabels
|
||||
|
||||
logger := log.Log.WithName("Generate").WithValues("policy", policy.Name,
|
||||
"kind", newResource.GetKind(), "namespace", newResource.GetNamespace(), "name", newResource.GetName())
|
||||
|
||||
if err := MatchesResourceDescription(newResource, rule, admissionInfo, excludeGroupRole); err != nil {
|
||||
if err := MatchesResourceDescription(newResource, rule, admissionInfo, excludeGroupRole, namespaceLabels); err != nil {
|
||||
|
||||
// if the oldResource matched, return "false" to delete GR for it
|
||||
if err := MatchesResourceDescription(oldResource, rule, admissionInfo, excludeGroupRole); err == nil {
|
||||
if err := MatchesResourceDescription(oldResource, rule, admissionInfo, excludeGroupRole, namespaceLabels); err == nil {
|
||||
return &response.RuleResponse{
|
||||
Name: rule.Name,
|
||||
Type: "Generation",
|
||||
|
|
|
@ -62,7 +62,7 @@ func Mutate(policyContext *PolicyContext) (resp *response.EngineResponse) {
|
|||
excludeResource = policyContext.ExcludeGroupRole
|
||||
}
|
||||
|
||||
if err := MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource); err != nil {
|
||||
if err := MatchesResourceDescription(patchedResource, rule, policyContext.AdmissionInfo, excludeResource, policyContext.NamespaceLabels); err != nil {
|
||||
logger.V(4).Info("rule not matched", "reason", err.Error())
|
||||
continue
|
||||
}
|
||||
|
|
|
@ -36,4 +36,7 @@ type PolicyContext struct {
|
|||
|
||||
// JSONContext is the variable context
|
||||
JSONContext *context.Context
|
||||
|
||||
// NamespaceLabels stores the label of namespace to be processed by namespace selector
|
||||
NamespaceLabels map[string]string
|
||||
}
|
||||
|
|
|
@ -108,7 +108,7 @@ func checkSelector(labelSelector *metav1.LabelSelector, resourceLabels map[strin
|
|||
// should be: AND across attributes but an OR inside attributes that of type list
|
||||
// To filter out the targeted resources with UserInfo, the check
|
||||
// should be: OR (across & inside) attributes
|
||||
func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription, userInfo kyverno.UserInfo, admissionInfo kyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string) []error {
|
||||
func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription, userInfo kyverno.UserInfo, admissionInfo kyverno.RequestInfo, resource unstructured.Unstructured, dynamicConfig []string, namespaceLabels map[string]string) []error {
|
||||
var errs []error
|
||||
|
||||
if len(conditionBlock.Kinds) > 0 {
|
||||
|
@ -146,6 +146,17 @@ func doesResourceMatchConditionBlock(conditionBlock kyverno.ResourceDescription,
|
|||
}
|
||||
}
|
||||
|
||||
if conditionBlock.NamespaceSelector != nil && namespaceLabels != nil && resource.GetKind() != "Namespace" && resource.GetKind() != "" {
|
||||
hasPassed, err := checkSelector(conditionBlock.NamespaceSelector, namespaceLabels)
|
||||
if err != nil {
|
||||
errs = append(errs, fmt.Errorf("failed to parse namespace selector: %v", err))
|
||||
} else {
|
||||
if !hasPassed {
|
||||
errs = append(errs, fmt.Errorf("namespace selector does not match"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
keys := append(admissionInfo.AdmissionUserInfo.Groups, admissionInfo.AdmissionUserInfo.Username)
|
||||
var userInfoErrors []error
|
||||
var checkedItem int
|
||||
|
@ -220,7 +231,7 @@ func matchSubjects(ruleSubjects []rbacv1.Subject, userInfo authenticationv1.User
|
|||
}
|
||||
|
||||
//MatchesResourceDescription checks if the resource matches resource description of the rule or not
|
||||
func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef kyverno.RequestInfo, dynamicConfig []string) error {
|
||||
func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef kyverno.Rule, admissionInfoRef kyverno.RequestInfo, dynamicConfig []string, namespaceLabels map[string]string) error {
|
||||
|
||||
rule := *ruleRef.DeepCopy()
|
||||
resource := *resourceRef.DeepCopy()
|
||||
|
@ -235,7 +246,7 @@ func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef k
|
|||
// checking if resource matches the rule
|
||||
if !reflect.DeepEqual(rule.MatchResources.ResourceDescription, kyverno.ResourceDescription{}) ||
|
||||
!reflect.DeepEqual(rule.MatchResources.UserInfo, kyverno.UserInfo{}) {
|
||||
matchErrs := doesResourceMatchConditionBlock(rule.MatchResources.ResourceDescription, rule.MatchResources.UserInfo, admissionInfo, resource, dynamicConfig)
|
||||
matchErrs := doesResourceMatchConditionBlock(rule.MatchResources.ResourceDescription, rule.MatchResources.UserInfo, admissionInfo, resource, dynamicConfig, namespaceLabels)
|
||||
reasonsForFailure = append(reasonsForFailure, matchErrs...)
|
||||
} else {
|
||||
reasonsForFailure = append(reasonsForFailure, fmt.Errorf("match cannot be empty"))
|
||||
|
@ -244,7 +255,7 @@ func MatchesResourceDescription(resourceRef unstructured.Unstructured, ruleRef k
|
|||
// checking if resource has been excluded
|
||||
if !reflect.DeepEqual(rule.ExcludeResources.ResourceDescription, kyverno.ResourceDescription{}) ||
|
||||
!reflect.DeepEqual(rule.ExcludeResources.UserInfo, kyverno.UserInfo{}) {
|
||||
excludeErrs := doesResourceMatchConditionBlock(rule.ExcludeResources.ResourceDescription, rule.ExcludeResources.UserInfo, admissionInfo, resource, dynamicConfig)
|
||||
excludeErrs := doesResourceMatchConditionBlock(rule.ExcludeResources.ResourceDescription, rule.ExcludeResources.UserInfo, admissionInfo, resource, dynamicConfig, namespaceLabels)
|
||||
if excludeErrs == nil {
|
||||
reasonsForFailure = append(reasonsForFailure, fmt.Errorf("resource excluded"))
|
||||
}
|
||||
|
|
|
@ -70,7 +70,7 @@ func TestMatchesResourceDescription(t *testing.T) {
|
|||
resource, _ := utils.ConvertToUnstructured(tc.Resource)
|
||||
|
||||
for _, rule := range policy.Spec.Rules {
|
||||
err := MatchesResourceDescription(*resource, rule, tc.AdmissionInfo, []string{})
|
||||
err := MatchesResourceDescription(*resource, rule, tc.AdmissionInfo, []string{}, nil)
|
||||
if err != nil {
|
||||
if !tc.areErrorsExpected {
|
||||
t.Errorf("Testcase %d Unexpected error: %v", i+1, err)
|
||||
|
@ -138,7 +138,7 @@ func TestResourceDescriptionMatch_MultipleKind(t *testing.T) {
|
|||
}
|
||||
rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}}
|
||||
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}); err != nil {
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil {
|
||||
t.Errorf("Testcase has failed due to the following:%v", err)
|
||||
}
|
||||
|
||||
|
@ -199,7 +199,7 @@ func TestResourceDescriptionMatch_Name(t *testing.T) {
|
|||
}
|
||||
rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}}
|
||||
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}); err != nil {
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil {
|
||||
t.Errorf("Testcase has failed due to the following:%v", err)
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +259,7 @@ func TestResourceDescriptionMatch_Name_Regex(t *testing.T) {
|
|||
}
|
||||
rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}}
|
||||
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}); err != nil {
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil {
|
||||
t.Errorf("Testcase has failed due to the following:%v", err)
|
||||
}
|
||||
}
|
||||
|
@ -327,7 +327,7 @@ func TestResourceDescriptionMatch_Label_Expression_NotMatch(t *testing.T) {
|
|||
}
|
||||
rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}}
|
||||
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}); err != nil {
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil {
|
||||
t.Errorf("Testcase has failed due to the following:%v", err)
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +396,7 @@ func TestResourceDescriptionMatch_Label_Expression_Match(t *testing.T) {
|
|||
}
|
||||
rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription}}
|
||||
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}); err != nil {
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err != nil {
|
||||
t.Errorf("Testcase has failed due to the following:%v", err)
|
||||
}
|
||||
}
|
||||
|
@ -476,7 +476,7 @@ func TestResourceDescriptionExclude_Label_Expression_Match(t *testing.T) {
|
|||
rule := kyverno.Rule{MatchResources: kyverno.MatchResources{ResourceDescription: resourceDescription},
|
||||
ExcludeResources: kyverno.ExcludeResources{ResourceDescription: resourceDescriptionExclude}}
|
||||
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}); err == nil {
|
||||
if err := MatchesResourceDescription(*resource, rule, kyverno.RequestInfo{}, []string{}, nil); err == nil {
|
||||
t.Errorf("Testcase has failed due to the following:\n Function has returned no error, even though it was supposed to fail")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -171,13 +171,13 @@ func validateResourceWithRule(log logr.Logger, ctx *PolicyContext, rule kyverno.
|
|||
|
||||
// matches checks if either the new or old resource satisfies the filter conditions defined in the rule
|
||||
func matches(logger logr.Logger, rule kyverno.Rule, ctx *PolicyContext) bool {
|
||||
err := MatchesResourceDescription(ctx.NewResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole)
|
||||
err := MatchesResourceDescription(ctx.NewResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if !reflect.DeepEqual(ctx.OldResource, unstructured.Unstructured{}) {
|
||||
err := MatchesResourceDescription(ctx.OldResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole)
|
||||
err := MatchesResourceDescription(ctx.OldResource, rule, ctx.AdmissionInfo, ctx.ExcludeGroupRole, ctx.NamespaceLabels)
|
||||
if err == nil {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
pkgcommon "github.com/kyverno/kyverno/pkg/common"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
dclient "github.com/kyverno/kyverno/pkg/dclient"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
|
@ -44,7 +45,8 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
|||
}
|
||||
|
||||
// 2 - Apply the generate policy on the resource
|
||||
genResources, err = c.applyGenerate(*resource, *gr)
|
||||
namespaceLabels := pkgcommon.GetNamespaceSelectorsFromGenericInformer(resource.GetKind(), resource.GetNamespace(), c.nsInformer, logger)
|
||||
genResources, err = c.applyGenerate(*resource, *gr, namespaceLabels)
|
||||
|
||||
if err != nil {
|
||||
// Need not update the stauts when policy doesn't apply on resource, because all the generate requests are removed by the cleanup controller
|
||||
|
@ -64,7 +66,7 @@ func (c *Controller) processGR(gr *kyverno.GenerateRequest) error {
|
|||
|
||||
const doesNotApply = "policy does not apply to resource"
|
||||
|
||||
func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest) ([]kyverno.ResourceSpec, error) {
|
||||
func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyverno.GenerateRequest, namespaceLabels map[string]string) ([]kyverno.ResourceSpec, error) {
|
||||
logger := c.log.WithValues("name", gr.Name, "policy", gr.Spec.Policy, "kind", gr.Spec.Resource.Kind, "apiVersion", gr.Spec.Resource.APIVersion, "namespace", gr.Spec.Resource.Namespace, "name", gr.Spec.Resource.Name)
|
||||
// Get the list of rules to be applied
|
||||
// get policy
|
||||
|
@ -129,6 +131,7 @@ func (c *Controller) applyGenerate(resource unstructured.Unstructured, gr kyvern
|
|||
ExcludeResourceFunc: c.Config.ToFilter,
|
||||
ResourceCache: c.resCache,
|
||||
JSONContext: ctx,
|
||||
NamespaceLabels: namespaceLabels,
|
||||
}
|
||||
|
||||
// check if the policy still applies to the resource
|
||||
|
|
|
@ -60,6 +60,12 @@ type Controller struct {
|
|||
// dynamic shared informer factory
|
||||
dynamicInformer dynamicinformer.DynamicSharedInformerFactory
|
||||
|
||||
// // nsLister can list/get namespaces from the shared informer's store
|
||||
// nsLister listerv1.NamespaceLister
|
||||
|
||||
// // nsListerSynced returns true if the namespace store has been synced at least once
|
||||
// nsListerSynced cache.InformerSynced
|
||||
|
||||
//TODO: list of generic informers
|
||||
// only support Namespaces for re-evaluation on resource updates
|
||||
nsInformer informers.GenericInformer
|
||||
|
@ -128,6 +134,9 @@ func NewController(
|
|||
UpdateFunc: c.updateGenericResource,
|
||||
})
|
||||
|
||||
// c.nsLister = namespaces.Lister()
|
||||
// c.nsListerSynced = namespaces.Informer().HasSynced
|
||||
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import (
|
|||
// applyPolicy applies policy on a resource
|
||||
func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructured,
|
||||
logger logr.Logger, excludeGroupRole []string, resCache resourcecache.ResourceCache,
|
||||
client *client.Client) (responses []*response.EngineResponse) {
|
||||
client *client.Client, namespaceLabels map[string]string) (responses []*response.EngineResponse) {
|
||||
|
||||
startTime := time.Now()
|
||||
defer func() {
|
||||
|
@ -45,7 +45,7 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
|||
logger.Error(err, "enable to add transform resource to ctx")
|
||||
}
|
||||
|
||||
engineResponseMutation, err = mutation(policy, resource, logger, resCache, ctx)
|
||||
engineResponseMutation, err = mutation(policy, resource, logger, resCache, ctx, namespaceLabels)
|
||||
if err != nil {
|
||||
logger.Error(err, "failed to process mutation rule")
|
||||
}
|
||||
|
@ -65,13 +65,14 @@ func applyPolicy(policy kyverno.ClusterPolicy, resource unstructured.Unstructure
|
|||
return engineResponses
|
||||
}
|
||||
|
||||
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, log logr.Logger, resCache resourcecache.ResourceCache, jsonContext *context.Context) (*response.EngineResponse, error) {
|
||||
func mutation(policy kyverno.ClusterPolicy, resource unstructured.Unstructured, log logr.Logger, resCache resourcecache.ResourceCache, jsonContext *context.Context, namespaceLabels map[string]string) (*response.EngineResponse, error) {
|
||||
|
||||
policyContext := &engine.PolicyContext{
|
||||
Policy: policy,
|
||||
NewResource: resource,
|
||||
ResourceCache: resCache,
|
||||
JSONContext: jsonContext,
|
||||
Policy: policy,
|
||||
NewResource: resource,
|
||||
ResourceCache: resCache,
|
||||
JSONContext: jsonContext,
|
||||
NamespaceLabels: namespaceLabels,
|
||||
}
|
||||
|
||||
engineResponse := engine.Mutate(policyContext)
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/common"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
|
@ -84,7 +85,8 @@ func (pc *PolicyController) applyPolicy(policy *kyverno.ClusterPolicy, resource
|
|||
logger.V(4).Info("policy and resource already processed", "policyResourceVersion", policy.ResourceVersion, "resourceResourceVersion", resource.GetResourceVersion(), "kind", resource.GetKind(), "namespace", resource.GetNamespace(), "name", resource.GetName())
|
||||
}
|
||||
|
||||
engineResponse := applyPolicy(*policy, resource, logger, pc.configHandler.GetExcludeGroupRole(), pc.resCache, pc.client)
|
||||
namespaceLabels := common.GetNamespaceSelectorsFromNamespaceLister(resource.GetKind(), resource.GetNamespace(), pc.nsLister, logger)
|
||||
engineResponse := applyPolicy(*policy, resource, logger, pc.configHandler.GetExcludeGroupRole(), pc.resCache, pc.client, namespaceLabels)
|
||||
engineResponses = append(engineResponses, engineResponse...)
|
||||
|
||||
// post-processing, register the resource as processed
|
||||
|
|
|
@ -4,11 +4,12 @@ import (
|
|||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/jmespath/go-jmespath"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/kyverno/common"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
dclient "github.com/kyverno/kyverno/pkg/dclient"
|
||||
|
@ -200,11 +201,19 @@ func doMatchAndExcludeConflict(rule kyverno.Rule) bool {
|
|||
excludeNamespaces[namespace] = true
|
||||
}
|
||||
|
||||
excludeMatchExpressions := make(map[string]bool)
|
||||
excludeSelectorMatchExpressions := make(map[string]bool)
|
||||
if rule.ExcludeResources.ResourceDescription.Selector != nil {
|
||||
for _, matchExpression := range rule.ExcludeResources.ResourceDescription.Selector.MatchExpressions {
|
||||
matchExpressionRaw, _ := json.Marshal(matchExpression)
|
||||
excludeMatchExpressions[string(matchExpressionRaw)] = true
|
||||
excludeSelectorMatchExpressions[string(matchExpressionRaw)] = true
|
||||
}
|
||||
}
|
||||
|
||||
excludeNamespaceSelectorMatchExpressions := make(map[string]bool)
|
||||
if rule.ExcludeResources.ResourceDescription.NamespaceSelector != nil {
|
||||
for _, matchExpression := range rule.ExcludeResources.ResourceDescription.NamespaceSelector.MatchExpressions {
|
||||
matchExpressionRaw, _ := json.Marshal(matchExpression)
|
||||
excludeNamespaceSelectorMatchExpressions[string(matchExpressionRaw)] = true
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -276,14 +285,14 @@ func doMatchAndExcludeConflict(rule kyverno.Rule) bool {
|
|||
}
|
||||
|
||||
if rule.MatchResources.ResourceDescription.Selector != nil && rule.ExcludeResources.ResourceDescription.Selector != nil {
|
||||
if len(excludeMatchExpressions) > 0 {
|
||||
if len(excludeSelectorMatchExpressions) > 0 {
|
||||
if len(rule.MatchResources.ResourceDescription.Selector.MatchExpressions) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, matchExpression := range rule.MatchResources.ResourceDescription.Selector.MatchExpressions {
|
||||
matchExpressionRaw, _ := json.Marshal(matchExpression)
|
||||
if !excludeMatchExpressions[string(matchExpressionRaw)] {
|
||||
if !excludeSelectorMatchExpressions[string(matchExpressionRaw)] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -302,11 +311,43 @@ func doMatchAndExcludeConflict(rule kyverno.Rule) bool {
|
|||
}
|
||||
}
|
||||
|
||||
if rule.MatchResources.ResourceDescription.NamespaceSelector != nil && rule.ExcludeResources.ResourceDescription.NamespaceSelector != nil {
|
||||
if len(excludeNamespaceSelectorMatchExpressions) > 0 {
|
||||
if len(rule.MatchResources.ResourceDescription.NamespaceSelector.MatchExpressions) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, matchExpression := range rule.MatchResources.ResourceDescription.NamespaceSelector.MatchExpressions {
|
||||
matchExpressionRaw, _ := json.Marshal(matchExpression)
|
||||
if !excludeNamespaceSelectorMatchExpressions[string(matchExpressionRaw)] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(rule.ExcludeResources.ResourceDescription.NamespaceSelector.MatchLabels) > 0 {
|
||||
if len(rule.MatchResources.ResourceDescription.NamespaceSelector.MatchLabels) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
for label, value := range rule.MatchResources.ResourceDescription.NamespaceSelector.MatchLabels {
|
||||
if rule.ExcludeResources.ResourceDescription.NamespaceSelector.MatchLabels[label] != value {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rule.MatchResources.ResourceDescription.Selector == nil && rule.ExcludeResources.ResourceDescription.Selector != nil) ||
|
||||
(rule.MatchResources.ResourceDescription.Selector != nil && rule.ExcludeResources.ResourceDescription.Selector == nil) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (rule.MatchResources.ResourceDescription.NamespaceSelector == nil && rule.ExcludeResources.ResourceDescription.NamespaceSelector != nil) ||
|
||||
(rule.MatchResources.ResourceDescription.NamespaceSelector != nil && rule.ExcludeResources.ResourceDescription.NamespaceSelector == nil) {
|
||||
return false
|
||||
}
|
||||
|
||||
if rule.MatchResources.Annotations != nil && rule.ExcludeResources.Annotations != nil {
|
||||
if !(reflect.DeepEqual(rule.MatchResources.Annotations, rule.ExcludeResources.Annotations)) {
|
||||
return false
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/common"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
|
@ -55,6 +56,9 @@ func (ws *WebhookServer) HandleGenerate(request *v1beta1.AdmissionRequest, polic
|
|||
for _, policy := range policies {
|
||||
var rules []response.RuleResponse
|
||||
policyContext.Policy = *policy
|
||||
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
|
||||
policyContext.NamespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, ws.nsLister, logger)
|
||||
}
|
||||
engineResponse := engine.Generate(policyContext)
|
||||
for _, rule := range engineResponse.PolicyResponse.Rules {
|
||||
if !rule.Success {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/common"
|
||||
"github.com/kyverno/kyverno/pkg/engine"
|
||||
"github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/engine/response"
|
||||
|
@ -55,6 +56,9 @@ func (ws *WebhookServer) HandleMutation(
|
|||
logger.V(3).Info("evaluating policy", "policy", policy.Name)
|
||||
|
||||
policyContext.Policy = *policy
|
||||
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
|
||||
policyContext.NamespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, ws.nsLister, logger)
|
||||
}
|
||||
engineResponse := engine.Mutate(policyContext)
|
||||
policyPatches := engineResponse.GetPatches()
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ import (
|
|||
kyvernoclient "github.com/kyverno/kyverno/pkg/client/clientset/versioned"
|
||||
kyvernoinformer "github.com/kyverno/kyverno/pkg/client/informers/externalversions/kyverno/v1"
|
||||
kyvernolister "github.com/kyverno/kyverno/pkg/client/listers/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/common"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
context2 "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
|
@ -33,7 +34,9 @@ import (
|
|||
webhookgenerate "github.com/kyverno/kyverno/pkg/webhooks/generate"
|
||||
v1beta1 "k8s.io/api/admission/v1beta1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
informers "k8s.io/client-go/informers/core/v1"
|
||||
rbacinformer "k8s.io/client-go/informers/rbac/v1"
|
||||
listerv1 "k8s.io/client-go/listers/core/v1"
|
||||
rbaclister "k8s.io/client-go/listers/rbac/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
@ -107,6 +110,11 @@ type WebhookServer struct {
|
|||
// generate request generator
|
||||
grGenerator *webhookgenerate.Generator
|
||||
|
||||
nsLister listerv1.NamespaceLister
|
||||
|
||||
// nsListerSynced returns true if the namespace store has been synced at least once
|
||||
nsListerSynced cache.InformerSynced
|
||||
|
||||
auditHandler AuditHandler
|
||||
|
||||
log logr.Logger
|
||||
|
@ -135,6 +143,7 @@ func NewWebhookServer(
|
|||
crbInformer rbacinformer.ClusterRoleBindingInformer,
|
||||
rInformer rbacinformer.RoleInformer,
|
||||
crInformer rbacinformer.ClusterRoleInformer,
|
||||
namespace informers.NamespaceInformer,
|
||||
eventGen event.Interface,
|
||||
pCache policycache.Interface,
|
||||
webhookRegistrationClient *webhookconfig.Register,
|
||||
|
@ -165,16 +174,18 @@ func NewWebhookServer(
|
|||
tlsConfig.Certificates = []tls.Certificate{pair}
|
||||
|
||||
ws := &WebhookServer{
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
|
||||
grSynced: grInformer.Informer().HasSynced,
|
||||
pLister: pInformer.Lister(),
|
||||
pSynced: pInformer.Informer().HasSynced,
|
||||
rbLister: rbInformer.Lister(),
|
||||
rbSynced: rbInformer.Informer().HasSynced,
|
||||
rLister: rInformer.Lister(),
|
||||
rSynced: rInformer.Informer().HasSynced,
|
||||
client: client,
|
||||
kyvernoClient: kyvernoClient,
|
||||
grLister: grInformer.Lister().GenerateRequests(config.KyvernoNamespace),
|
||||
grSynced: grInformer.Informer().HasSynced,
|
||||
pLister: pInformer.Lister(),
|
||||
pSynced: pInformer.Informer().HasSynced,
|
||||
rbLister: rbInformer.Lister(),
|
||||
rbSynced: rbInformer.Informer().HasSynced,
|
||||
rLister: rInformer.Lister(),
|
||||
rSynced: rInformer.Informer().HasSynced,
|
||||
nsLister: namespace.Lister(),
|
||||
nsListerSynced: namespace.Informer().HasSynced,
|
||||
|
||||
crbLister: crbInformer.Lister(),
|
||||
crLister: crInformer.Lister(),
|
||||
|
@ -458,7 +469,12 @@ func (ws *WebhookServer) resourceValidation(request *v1beta1.AdmissionRequest) *
|
|||
logger.Error(err, "failed to load service account in context")
|
||||
}
|
||||
|
||||
ok, msg := HandleValidation(request, policies, nil, ctx, userRequestInfo, ws.statusListener, ws.eventGen, ws.prGenerator, ws.log, ws.configHandler, ws.resCache, ws.client)
|
||||
namespaceLabels := make(map[string]string)
|
||||
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
|
||||
namespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, ws.nsLister, logger)
|
||||
}
|
||||
|
||||
ok, msg := HandleValidation(request, policies, nil, ctx, userRequestInfo, ws.statusListener, ws.eventGen, ws.prGenerator, ws.log, ws.configHandler, ws.resCache, ws.client, namespaceLabels)
|
||||
if !ok {
|
||||
logger.Info("admission request denied")
|
||||
return &v1beta1.AdmissionResponse{
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/common"
|
||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/config"
|
||||
|
@ -20,7 +22,9 @@ import (
|
|||
"k8s.io/api/admission/v1beta1"
|
||||
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
|
||||
"k8s.io/apimachinery/pkg/util/wait"
|
||||
informers "k8s.io/client-go/informers/core/v1"
|
||||
rbacinformer "k8s.io/client-go/informers/rbac/v1"
|
||||
listerv1 "k8s.io/client-go/listers/core/v1"
|
||||
rbaclister "k8s.io/client-go/listers/rbac/v1"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
"k8s.io/client-go/util/workqueue"
|
||||
|
@ -48,10 +52,12 @@ type auditHandler struct {
|
|||
statusListener policystatus.Listener
|
||||
prGenerator policyreport.GeneratorInterface
|
||||
|
||||
rbLister rbaclister.RoleBindingLister
|
||||
rbSynced cache.InformerSynced
|
||||
crbLister rbaclister.ClusterRoleBindingLister
|
||||
crbSynced cache.InformerSynced
|
||||
rbLister rbaclister.RoleBindingLister
|
||||
rbSynced cache.InformerSynced
|
||||
crbLister rbaclister.ClusterRoleBindingLister
|
||||
crbSynced cache.InformerSynced
|
||||
nsLister listerv1.NamespaceLister
|
||||
nsListerSynced cache.InformerSynced
|
||||
|
||||
log logr.Logger
|
||||
configHandler config.Interface
|
||||
|
@ -65,6 +71,7 @@ func NewValidateAuditHandler(pCache policycache.Interface,
|
|||
prGenerator policyreport.GeneratorInterface,
|
||||
rbInformer rbacinformer.RoleBindingInformer,
|
||||
crbInformer rbacinformer.ClusterRoleBindingInformer,
|
||||
namespaces informers.NamespaceInformer,
|
||||
log logr.Logger,
|
||||
dynamicConfig config.Interface,
|
||||
resCache resourcecache.ResourceCache,
|
||||
|
@ -79,6 +86,8 @@ func NewValidateAuditHandler(pCache policycache.Interface,
|
|||
rbSynced: rbInformer.Informer().HasSynced,
|
||||
crbLister: crbInformer.Lister(),
|
||||
crbSynced: crbInformer.Informer().HasSynced,
|
||||
nsLister: namespaces.Lister(),
|
||||
nsListerSynced: namespaces.Informer().HasSynced,
|
||||
log: log,
|
||||
prGenerator: prGenerator,
|
||||
configHandler: dynamicConfig,
|
||||
|
@ -175,7 +184,12 @@ func (h *auditHandler) process(request *v1beta1.AdmissionRequest) error {
|
|||
return errors.Wrap(err, "failed to load service account in context")
|
||||
}
|
||||
|
||||
HandleValidation(request, policies, nil, ctx, userRequestInfo, h.statusListener, h.eventGen, h.prGenerator, logger, h.configHandler, h.resCache, h.client)
|
||||
namespaceLabels := make(map[string]string)
|
||||
if request.Kind.Kind != "Namespace" && request.Namespace != "" {
|
||||
namespaceLabels = common.GetNamespaceSelectorsFromNamespaceLister(request.Kind.Kind, request.Namespace, h.nsLister, logger)
|
||||
}
|
||||
|
||||
HandleValidation(request, policies, nil, ctx, userRequestInfo, h.statusListener, h.eventGen, h.prGenerator, logger, h.configHandler, h.resCache, h.client, namespaceLabels)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
package webhooks
|
||||
|
||||
import (
|
||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
"reflect"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
client "github.com/kyverno/kyverno/pkg/dclient"
|
||||
|
||||
"github.com/go-logr/logr"
|
||||
kyverno "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
v1 "github.com/kyverno/kyverno/pkg/api/kyverno/v1"
|
||||
|
@ -38,7 +39,8 @@ func HandleValidation(
|
|||
log logr.Logger,
|
||||
dynamicConfig config.Interface,
|
||||
resCache resourcecache.ResourceCache,
|
||||
client *client.Client) (bool, string) {
|
||||
client *client.Client,
|
||||
namespaceLabels map[string]string) (bool, string) {
|
||||
|
||||
if len(policies) == 0 {
|
||||
return true, ""
|
||||
|
@ -85,6 +87,7 @@ func HandleValidation(
|
|||
for _, policy := range policies {
|
||||
logger.V(3).Info("evaluating policy", "policy", policy.Name)
|
||||
policyContext.Policy = *policy
|
||||
policyContext.NamespaceLabels = namespaceLabels
|
||||
engineResponse := engine.Validate(policyContext)
|
||||
if reflect.DeepEqual(engineResponse, response.EngineResponse{}) {
|
||||
// we get an empty response if old and new resources created the same response
|
||||
|
|
Loading…
Add table
Reference in a new issue