mirror of
https://github.com/kyverno/kyverno.git
synced 2025-03-28 02:18:15 +00:00
Support PSa integration by controlName
only (#4710)
* Remove "restrictedField" and "values" from podSecurity.exclude Signed-off-by: ShutingZhao <shuting@nirmata.com> * Remove commented code Signed-off-by: ShutingZhao <shuting@nirmata.com> * Add unit tests for restricted_runAsNonRoot Signed-off-by: ShutingZhao <shuting@nirmata.com> * Add baseline unit tests Signed-off-by: ShutingZhao <shuting@nirmata.com> * Add unit tests for restricted controls Signed-off-by: ShutingZhao <shuting@nirmata.com> * Removes PSa tests at the engine level Signed-off-by: ShutingZhao <shuting@nirmata.com> * - Update API docs; - Add unit tests for wildcard images Signed-off-by: ShutingZhao <shuting@nirmata.com> * Remove autogen conversion for PSa policies Signed-off-by: ShutingZhao <shuting@nirmata.com> * copy pod with DeepCopy() Signed-off-by: ShutingZhao <shuting@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: Charles-Edouard Brétéché <charled.breteche@gmail.com>
This commit is contained in:
parent
56c74272bb
commit
34c6920129
17 changed files with 8368 additions and 13113 deletions
|
@ -345,19 +345,11 @@ type PodSecurityStandard struct {
|
|||
// See: https://kubernetes.io/docs/concepts/security/pod-security-standards/
|
||||
ControlName string `json:"controlName" yaml:"controlName"`
|
||||
|
||||
// Images is a list of matching image patterns.
|
||||
// Images selects matching containers and applies the container level PSS.
|
||||
// Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
// Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
// +optional
|
||||
Images []string `json:"images,omitempty" yaml:"images,omitempty"`
|
||||
|
||||
// RestrictedField selects the field for the given Pod Security Standard control.
|
||||
// When not set, all restricted fields for the control are selected.
|
||||
// +optional
|
||||
RestrictedField string `json:"restrictedField,omitempty" yaml:"restrictedField,omitempty"`
|
||||
|
||||
// Values defines the allowed values that can be excluded.
|
||||
// +optional
|
||||
Values []string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
// DeserializeAnyPattern deserialize apiextensions.JSON to []interface{}
|
||||
|
|
|
@ -958,11 +958,6 @@ func (in *PodSecurityStandard) DeepCopyInto(out *PodSecurityStandard) {
|
|||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Values != nil {
|
||||
in, out := &in.Values, &out.Values
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PodSecurityStandard.
|
||||
|
|
|
@ -1475,15 +1475,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -3172,15 +3164,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -4821,15 +4805,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -6493,15 +6469,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -9010,15 +8978,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -10707,15 +10667,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -12356,15 +12308,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -14028,15 +13972,7 @@ spec:
|
|||
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image patterns. Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field for the given Pod Security Standard control. When not set, all restricted fields for the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values that can be excluded.
|
||||
description: Images selects matching containers and applies the container level PSS. Each image is the image name consisting of the registry address, repository, image, and tag. Empty list matches no containers, PSS checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
|
|
@ -2320,22 +2320,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -5118,22 +5108,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -7715,22 +7695,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -10473,22 +10443,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
|
|
@ -2321,22 +2321,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -5120,22 +5110,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -7718,22 +7698,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -10476,22 +10446,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
|
3075
config/install.yaml
3075
config/install.yaml
File diff suppressed because it is too large
Load diff
|
@ -2335,22 +2335,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -5133,22 +5123,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -7730,22 +7710,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -10488,22 +10458,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -14263,22 +14223,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -17062,22 +17012,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -19660,22 +19600,12 @@ spec:
|
|||
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching image
|
||||
patterns. Each image is the image name consisting
|
||||
of the registry address, repository, image,
|
||||
and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the
|
||||
control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each image
|
||||
is the image name consisting of the registry
|
||||
address, repository, image, and tag. Empty list
|
||||
matches no containers, PSS checks are applied
|
||||
at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
@ -22418,22 +22348,12 @@ spec:
|
|||
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
|
||||
type: string
|
||||
images:
|
||||
description: Images is a list of matching
|
||||
image patterns. Each image is the image
|
||||
name consisting of the registry address,
|
||||
repository, image, and tag.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
restrictedField:
|
||||
description: RestrictedField selects the field
|
||||
for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for
|
||||
the control are selected.
|
||||
type: string
|
||||
values:
|
||||
description: Values defines the allowed values
|
||||
that can be excluded.
|
||||
description: Images selects matching containers
|
||||
and applies the container level PSS. Each
|
||||
image is the image name consisting of the
|
||||
registry address, repository, image, and
|
||||
tag. Empty list matches no containers, PSS
|
||||
checks are applied at the pod level only.
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
|
|
|
@ -2658,33 +2658,9 @@ See: <a href="https://kubernetes.io/docs/concepts/security/pod-security-standard
|
|||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Images is a list of matching image patterns.
|
||||
Each image is the image name consisting of the registry address, repository, image, and tag.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>restrictedField</code><br/>
|
||||
<em>
|
||||
string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>RestrictedField selects the field for the given Pod Security Standard control.
|
||||
When not set, all restricted fields for the control are selected.</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<code>values</code><br/>
|
||||
<em>
|
||||
[]string
|
||||
</em>
|
||||
</td>
|
||||
<td>
|
||||
<em>(Optional)</em>
|
||||
<p>Values defines the allowed values that can be excluded.</p>
|
||||
<p>Images selects matching containers and applies the container level PSS.
|
||||
Each image is the image name consisting of the registry address, repository, image, and tag.
|
||||
Empty list matches no containers, PSS checks are applied at the pod level only.</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
@ -607,37 +607,6 @@ func Test_Deny(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func Test_ValidatePodSecurity(t *testing.T) {
|
||||
dir, err := os.Getwd()
|
||||
baseDir := filepath.Dir(filepath.Dir(dir))
|
||||
assert.NilError(t, err)
|
||||
file, err := ioutil.ReadFile(baseDir + "/test/policy/validate/enforce-baseline-exclude-selinuxoptions.yaml")
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
policies, err := yamlutils.GetPolicy(file)
|
||||
if err != nil {
|
||||
t.Log(err)
|
||||
}
|
||||
|
||||
policy := policies[0]
|
||||
spec := policy.GetSpec()
|
||||
|
||||
rulePatches, errs := GenerateRulePatches(spec, PodControllers)
|
||||
if len(errs) != 0 {
|
||||
t.Log(errs)
|
||||
}
|
||||
expectedPatches := [][]byte{
|
||||
[]byte(`{"path":"/spec/rules/1","op":"add","value":{"name":"autogen-enforce-baseline-exclude-se-linux-options","match":{"any":[{"resources":{"kinds":["DaemonSet","Deployment","Job","StatefulSet"],"namespaces":["privileged-pss-with-kyverno"]}}],"resources":{}},"validate":{"podSecurity":{"level":"baseline","version":"v1.24","exclude":[{"controlName":"SELinux","images":["nginx"],"restrictedField":"spec.template.spec.containers[*].securityContext.seLinuxOptions.role","values":["baz"]},{"controlName":"SELinux","images":["nodejs"],"restrictedField":"spec.template.spec.initContainers[*].securityContext.seLinuxOptions.role","values":["init-bazo"]}]}}}}`),
|
||||
[]byte(`{"path":"/spec/rules/2","op":"add","value":{"name":"autogen-cronjob-enforce-baseline-exclude-se-linux-options","match":{"any":[{"resources":{"kinds":["CronJob"],"namespaces":["privileged-pss-with-kyverno"]}}],"resources":{}},"validate":{"podSecurity":{"level":"baseline","version":"v1.24","exclude":[{"controlName":"SELinux","images":["nginx"],"restrictedField":"spec.jobTemplate.spec.template.spec.containers[*].securityContext.seLinuxOptions.role","values":["baz"]},{"controlName":"SELinux","images":["nodejs"],"restrictedField":"spec.jobTemplate.spec.template.spec.initContainers[*].securityContext.seLinuxOptions.role","values":["init-bazo"]}]}}}}`),
|
||||
}
|
||||
|
||||
for i, ep := range expectedPatches {
|
||||
assert.Equal(t, string(rulePatches[i]), string(ep),
|
||||
fmt.Sprintf("unexpected patch: %s\nexpected: %s", rulePatches[i], ep))
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ComputeRules(t *testing.T) {
|
||||
intPtr := func(i int) *int { return &i }
|
||||
testCases := []struct {
|
||||
|
|
|
@ -26,7 +26,6 @@ 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/pod-security-admission/api"
|
||||
"sigs.k8s.io/controller-runtime/pkg/log"
|
||||
)
|
||||
|
||||
|
@ -511,37 +510,20 @@ func (v *validator) validatePodSecurity() *response.RuleResponse {
|
|||
if err != nil {
|
||||
return ruleError(v.rule, response.Validation, "Error while getting new resource", err)
|
||||
}
|
||||
// Get pod security admission version
|
||||
var apiVersion api.Version
|
||||
|
||||
// Version set to "latest" by default
|
||||
if v.podSecurity.Version == "" || v.podSecurity.Version == "latest" {
|
||||
apiVersion = api.LatestVersion()
|
||||
} else {
|
||||
parsedApiVersion, err := api.ParseVersion(v.podSecurity.Version)
|
||||
if err != nil {
|
||||
return ruleError(v.rule, response.Validation, "failed to parse pod security api version", err)
|
||||
}
|
||||
apiVersion = api.MajorMinorVersion(parsedApiVersion.Major(), parsedApiVersion.Minor())
|
||||
}
|
||||
level := &api.LevelVersion{
|
||||
Level: v.podSecurity.Level,
|
||||
Version: apiVersion,
|
||||
}
|
||||
pod := &corev1.Pod{
|
||||
Spec: *podSpec,
|
||||
ObjectMeta: *metadata,
|
||||
}
|
||||
allowed, pssChecks, err := pss.EvaluatePod(v.podSecurity, pod, level)
|
||||
allowed, pssChecks, err := pss.EvaluatePod(v.podSecurity, pod)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Failed to evaluate validation rule `%s`: %v", v.rule.Name, err)
|
||||
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusError, nil)
|
||||
return ruleError(v.rule, response.Validation, "failed to parse pod security api version", err)
|
||||
}
|
||||
if allowed {
|
||||
msg := fmt.Sprintf("Validation rule '%s' passed.", v.rule.Name)
|
||||
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusPass, nil)
|
||||
} else {
|
||||
msg := fmt.Sprintf(`Validation rule '%s' failed. It violates PodSecurity "%s:%s": %s`, v.rule.Name, level.Level, level.Version, pss.FormatChecksPrint(pssChecks))
|
||||
msg := fmt.Sprintf(`Validation rule '%s' failed. It violates PodSecurity "%s:%s": %s`, v.rule.Name, v.podSecurity.Level, v.podSecurity.Version, pss.FormatChecksPrint(pssChecks))
|
||||
return ruleResponse(*v.rule, response.Validation, msg, response.RuleStatusFail, nil)
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,30 +1,14 @@
|
|||
package pss
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
enginectx "github.com/kyverno/kyverno/pkg/engine/context"
|
||||
"github.com/kyverno/kyverno/pkg/utils"
|
||||
"github.com/pkg/errors"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
"k8s.io/pod-security-admission/api"
|
||||
"k8s.io/pod-security-admission/policy"
|
||||
)
|
||||
|
||||
func FormatChecksPrint(checks []PSSCheckResult) string {
|
||||
var str string
|
||||
for _, check := range checks {
|
||||
str += fmt.Sprintf("(%+v)\n", check.CheckResult)
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// Evaluate Pod's specified containers only and get PSSCheckResults
|
||||
func evaluatePSS(level *api.LevelVersion, pod *corev1.Pod) (results []PSSCheckResult) {
|
||||
func evaluatePSS(level *api.LevelVersion, pod corev1.Pod) (results []pssCheckResult) {
|
||||
checks := policy.DefaultChecks()
|
||||
|
||||
for _, check := range checks {
|
||||
|
@ -34,12 +18,12 @@ func evaluatePSS(level *api.LevelVersion, pod *corev1.Pod) (results []PSSCheckRe
|
|||
// check version
|
||||
for _, versionCheck := range check.Versions {
|
||||
checkResult := versionCheck.CheckPod(&pod.ObjectMeta, &pod.Spec)
|
||||
// Append only if the checkResult is not already in PSSCheckResults
|
||||
// Append only if the checkResult is not already in pssCheckResult
|
||||
if !checkResult.Allowed {
|
||||
results = append(results, PSSCheckResult{
|
||||
ID: check.ID,
|
||||
CheckResult: checkResult,
|
||||
RestrictedFields: getRestrictedFields(check),
|
||||
results = append(results, pssCheckResult{
|
||||
id: check.ID,
|
||||
checkResult: checkResult,
|
||||
restrictedFields: getRestrictedFields(check),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -47,322 +31,73 @@ func evaluatePSS(level *api.LevelVersion, pod *corev1.Pod) (results []PSSCheckRe
|
|||
return results
|
||||
}
|
||||
|
||||
// When we specify the controlName only we want to exclude all restrictedFields for this control.
|
||||
// Remove all PSSChecks related to this control
|
||||
func trimExemptedChecks(pssChecks []PSSCheckResult, rule *kyvernov1.PodSecurity) []PSSCheckResult {
|
||||
// Keep in memory the number of checks that have been removed
|
||||
// to avoid panics when removing a new check.
|
||||
removedChecks := 0
|
||||
for checkIndex, check := range pssChecks {
|
||||
for _, exclude := range rule.Exclude {
|
||||
// Translate PSS control to check_id and remove it from PSSChecks if it's specified in exclude block
|
||||
for _, CheckID := range PSS_controls_to_check_id[exclude.ControlName] {
|
||||
if check.ID == CheckID && exclude.RestrictedField == "" && checkIndex <= len(pssChecks) {
|
||||
index := checkIndex - removedChecks
|
||||
pssChecks = append(pssChecks[:index], pssChecks[index+1:]...)
|
||||
removedChecks++
|
||||
}
|
||||
func exemptKyvernoExclusion(defaultCheckResults, excludeCheckResults []pssCheckResult, exclude kyvernov1.PodSecurityStandard) []pssCheckResult {
|
||||
defaultCheckResultsMap := make(map[string]pssCheckResult, len(defaultCheckResults))
|
||||
|
||||
for _, result := range defaultCheckResults {
|
||||
defaultCheckResultsMap[result.id] = result
|
||||
}
|
||||
|
||||
for _, excludeResult := range excludeCheckResults {
|
||||
for _, checkID := range PSS_controls_to_check_id[exclude.ControlName] {
|
||||
if excludeResult.id == checkID {
|
||||
delete(defaultCheckResultsMap, checkID)
|
||||
}
|
||||
}
|
||||
}
|
||||
return pssChecks
|
||||
|
||||
var newDefaultCheckResults []pssCheckResult
|
||||
for _, result := range defaultCheckResultsMap {
|
||||
newDefaultCheckResults = append(newDefaultCheckResults, result)
|
||||
}
|
||||
|
||||
return newDefaultCheckResults
|
||||
}
|
||||
|
||||
func forbiddenValuesExempted(ctx enginectx.Interface, pod *corev1.Pod, check PSSCheckResult, exclude kyvernov1.PodSecurityStandard, restrictedField string) (bool, error) {
|
||||
if err := enginectx.AddJSONObject(ctx, pod); err != nil {
|
||||
return false, errors.Wrap(err, "failed to add podSpec to engine context")
|
||||
func parseVersion(rule *kyvernov1.PodSecurity) (*api.LevelVersion, error) {
|
||||
// Get pod security admission version
|
||||
var apiVersion api.Version
|
||||
|
||||
// Version set to "latest" by default
|
||||
if rule.Version == "" || rule.Version == "latest" {
|
||||
apiVersion = api.LatestVersion()
|
||||
} else {
|
||||
parsedApiVersion, err := api.ParseVersion(rule.Version)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
apiVersion = api.MajorMinorVersion(parsedApiVersion.Major(), parsedApiVersion.Minor())
|
||||
}
|
||||
value, err := ctx.Query(restrictedField)
|
||||
return &api.LevelVersion{
|
||||
Level: rule.Level,
|
||||
Version: apiVersion,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// EvaluatePod applies PSS checks to the pod and exempts controls specified in the rule
|
||||
func EvaluatePod(rule *kyvernov1.PodSecurity, pod *corev1.Pod) (bool, []pssCheckResult, error) {
|
||||
level, err := parseVersion(rule)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, fmt.Sprintf("failed to query value with the given path %s", exclude.RestrictedField))
|
||||
return false, nil, err
|
||||
}
|
||||
if !allowedValues(value, exclude, PSS_controls[check.ID]) {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func checkContainer(ctx enginectx.Interface, pod *corev1.Pod, check PSSCheckResult, exclude []kyvernov1.PodSecurityStandard, restrictedField restrictedField, containerName string, containerTypePrefix string) (bool, error) {
|
||||
matchedOnce := false
|
||||
// Container.Name with double quotes
|
||||
formatedContainerName := fmt.Sprintf(`"%s"`, containerName)
|
||||
if !strings.Contains(check.CheckResult.ForbiddenDetail, formatedContainerName) {
|
||||
return true, nil
|
||||
}
|
||||
for _, exclude := range exclude {
|
||||
if !strings.Contains(exclude.RestrictedField, containerTypePrefix) {
|
||||
continue
|
||||
}
|
||||
defaultCheckResults := evaluatePSS(level, *pod)
|
||||
|
||||
// Get values of this container only.
|
||||
// spec.containers[*].securityContext.privileged -> spec.containers[?name=="nginx"].securityContext.privileged
|
||||
newRestrictedField := strings.Replace(restrictedField.path, "*", fmt.Sprintf(`?name=='%s'`, containerName), 1)
|
||||
|
||||
// No need to check if exclude.Images contains container.Image
|
||||
// Since we only have containers matching the exclude.images with getPodWithMatchingContainers()
|
||||
exempted, err := forbiddenValuesExempted(ctx, pod, check, exclude, newRestrictedField)
|
||||
if err != nil || !exempted {
|
||||
return false, nil
|
||||
}
|
||||
matchedOnce = true
|
||||
}
|
||||
// If container name is in check.Forbidden but isn't exempted by an exclude then pod creation is forbidden
|
||||
if strings.Contains(check.CheckResult.ForbiddenDetail, formatedContainerName) && !matchedOnce {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func checkContainerLevelFields(ctx enginectx.Interface, pod *corev1.Pod, check PSSCheckResult, exclude []kyvernov1.PodSecurityStandard, restrictedField restrictedField) (bool, error) {
|
||||
if strings.Contains(restrictedField.path, "spec.containers[*]") {
|
||||
for _, container := range pod.Spec.Containers {
|
||||
allowed, err := checkContainer(ctx, pod, check, exclude, restrictedField, container.Name, "spec.containers[*]")
|
||||
if err != nil || !allowed {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(restrictedField.path, "spec.initContainers[*]") {
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
allowed, err := checkContainer(ctx, pod, check, exclude, restrictedField, container.Name, "spec.initContainers[*]")
|
||||
if err != nil || !allowed {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if strings.Contains(restrictedField.path, "spec.ephemeralContainers[*]") {
|
||||
for _, container := range pod.Spec.EphemeralContainers {
|
||||
allowed, err := checkContainer(ctx, pod, check, exclude, restrictedField, container.Name, "spec.ephemeralContainers[*]")
|
||||
if err != nil || !allowed {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func checkHostNamespacesControl(check PSSCheckResult, restrictedField string) bool {
|
||||
hostNamespace := strings.Trim(restrictedField, "spec.")
|
||||
return strings.Contains(check.CheckResult.ForbiddenDetail, hostNamespace)
|
||||
}
|
||||
|
||||
func checkPodLevelFields(ctx enginectx.Interface, pod *corev1.Pod, check PSSCheckResult, rule *kyvernov1.PodSecurity, restrictedField restrictedField) (bool, error) {
|
||||
// Specific checks for controls with multiple pod-level restrictedFields
|
||||
// TO DO: SELinux control
|
||||
if check.ID == "hostNamespaces" {
|
||||
if !checkHostNamespacesControl(check, restrictedField.path) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
matchedOnce := false
|
||||
for _, exclude := range rule.Exclude {
|
||||
if !strings.Contains(exclude.RestrictedField, restrictedField.path) {
|
||||
continue
|
||||
}
|
||||
spec, matching := getPodWithMatchingContainers(exclude, pod)
|
||||
|
||||
exempted, err := forbiddenValuesExempted(ctx, pod, check, exclude, exclude.RestrictedField)
|
||||
if err != nil || !exempted {
|
||||
return false, nil
|
||||
switch {
|
||||
// exclude pod level checks
|
||||
case spec != nil:
|
||||
excludeCheckResults := evaluatePSS(level, *spec)
|
||||
defaultCheckResults = exemptKyvernoExclusion(defaultCheckResults, excludeCheckResults, exclude)
|
||||
|
||||
// exclude container level checks
|
||||
default:
|
||||
excludeCheckResults := evaluatePSS(level, *matching)
|
||||
defaultCheckResults = exemptKyvernoExclusion(defaultCheckResults, excludeCheckResults, exclude)
|
||||
}
|
||||
matchedOnce = true
|
||||
}
|
||||
if !matchedOnce {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func exemptProfile(checks []PSSCheckResult, rule *kyvernov1.PodSecurity, pod *corev1.Pod) (bool, error) {
|
||||
ctx := enginectx.NewContext()
|
||||
|
||||
// 1. Iterate over check.RestrictedFields
|
||||
// 2. Check if it's a `container-level` or `pod-level` restrictedField
|
||||
// - `container-level`: container has a disallowed check (container name in check.ForbiddenDetail) && exempted by an exclude rule ? continue : pod creation is forbbiden
|
||||
// - `pod-level`: Exempted by an exclude rule ? good : pod creation is forbbiden
|
||||
for _, check := range checks {
|
||||
for _, restrictedField := range check.RestrictedFields {
|
||||
// Is a container-level restrictedField
|
||||
|
||||
// RestrictedField.path can contain:
|
||||
// - containers[*]
|
||||
// - initContainers[*]
|
||||
// - ephemeralContainers[*]
|
||||
// So we check if it contains `ontainers[*]` to know if there is a CheckResult related to containers.
|
||||
if strings.Contains(restrictedField.path, "ontainers[*]") {
|
||||
allowed, err := checkContainerLevelFields(ctx, pod, check, rule.Exclude, restrictedField)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, err.Error())
|
||||
}
|
||||
if !allowed {
|
||||
return false, nil
|
||||
}
|
||||
} else {
|
||||
// Is a pod-level restrictedField
|
||||
if !strings.HasPrefix(check.CheckResult.ForbiddenDetail, "pod") && containsContainerLevelControl(check.RestrictedFields) {
|
||||
continue
|
||||
}
|
||||
allowed, err := checkPodLevelFields(ctx, pod, check, rule, restrictedField)
|
||||
if err != nil {
|
||||
return false, errors.Wrap(err, err.Error())
|
||||
}
|
||||
if !allowed {
|
||||
return false, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Check if the pod creation is allowed after exempting some PSS controls
|
||||
func EvaluatePod(rule *kyvernov1.PodSecurity, pod *corev1.Pod, level *api.LevelVersion) (bool, []PSSCheckResult, error) {
|
||||
// 1. Evaluate containers that match images specified in exclude
|
||||
podWithMatchingContainers := getPodWithMatchingContainers(rule.Exclude, pod)
|
||||
pssChecks := evaluatePSS(level, &podWithMatchingContainers)
|
||||
pssChecks = trimExemptedChecks(pssChecks, rule)
|
||||
|
||||
// 2. Check if all PSSCheckResults are exempted by exclude values
|
||||
allowed, err := exemptProfile(pssChecks, rule, &podWithMatchingContainers)
|
||||
if err != nil {
|
||||
return false, pssChecks, err
|
||||
}
|
||||
// Good to have: remove checks that are exempted and return only forbidden ones
|
||||
if !allowed {
|
||||
return false, pssChecks, nil
|
||||
}
|
||||
|
||||
// 3. Check the remaining containers
|
||||
podWithNotMatchingContainers := getPodWithNotMatchingContainers(rule.Exclude, pod, &podWithMatchingContainers)
|
||||
pssChecks = evaluatePSS(level, &podWithNotMatchingContainers)
|
||||
if len(pssChecks) > 0 {
|
||||
return false, pssChecks, nil
|
||||
}
|
||||
return true, pssChecks, nil
|
||||
}
|
||||
|
||||
func appendAllowedValues(controls []restrictedField, exclude *kyvernov1.PodSecurityStandard) {
|
||||
for _, control := range controls {
|
||||
if control.path == exclude.RestrictedField {
|
||||
for _, allowedValue := range control.allowedValues {
|
||||
switch v := allowedValue.(type) {
|
||||
case string:
|
||||
if !utils.ContainsString(exclude.Values, v) {
|
||||
exclude.Values = append(exclude.Values, v)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func allowedValuesSlice(excludeValues []interface{}, exclude kyvernov1.PodSecurityStandard) bool {
|
||||
for _, values := range excludeValues {
|
||||
v := reflect.TypeOf(values)
|
||||
switch v.Kind() {
|
||||
case reflect.Slice:
|
||||
for _, value := range values.([]interface{}) {
|
||||
if reflect.TypeOf(value).Kind() == reflect.Float64 {
|
||||
if !utils.ContainsString(exclude.Values, fmt.Sprintf("%.f", value)) {
|
||||
return false
|
||||
}
|
||||
} else if reflect.TypeOf(value).Kind() == reflect.String {
|
||||
if !utils.ContainsString(exclude.Values, value.(string)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
for key, value := range values.(map[string]interface{}) {
|
||||
if exclude.RestrictedField == "spec.volumes[*]" {
|
||||
if key == "name" {
|
||||
continue
|
||||
}
|
||||
matchedOnce := false
|
||||
for _, excludeValue := range exclude.Values {
|
||||
// Remove `spec.volumes[*].` prefix
|
||||
if strings.TrimPrefix(excludeValue, "spec.volumes[*].") == key {
|
||||
matchedOnce = true
|
||||
}
|
||||
}
|
||||
if !matchedOnce {
|
||||
return false
|
||||
}
|
||||
}
|
||||
// "HostPath volume" control: check the path of the hostPath volume since the type is optional
|
||||
// volumes:
|
||||
// - name: test-volume
|
||||
// hostPath:
|
||||
// # directory location on host
|
||||
// path: /data <--- Check the path
|
||||
// # this field is optional
|
||||
// type: Directory
|
||||
if exclude.RestrictedField == "spec.volumes[*].hostPath" {
|
||||
if key != "path" {
|
||||
continue
|
||||
}
|
||||
if !utils.ContainsString(exclude.Values, value.(string)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
case reflect.String:
|
||||
if !utils.ContainsString(exclude.Values, values.(string)) {
|
||||
return false
|
||||
}
|
||||
|
||||
case reflect.Bool:
|
||||
if !utils.ContainsString(exclude.Values, strconv.FormatBool(values.(bool))) {
|
||||
return false
|
||||
}
|
||||
case reflect.Float64:
|
||||
if !utils.ContainsString(exclude.Values, fmt.Sprintf("%.f", values)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func allowedValues(resourceValue interface{}, exclude kyvernov1.PodSecurityStandard, controls []restrictedField) bool {
|
||||
appendAllowedValues(controls, &exclude)
|
||||
|
||||
v := reflect.TypeOf(resourceValue)
|
||||
switch v.Kind() {
|
||||
case reflect.Bool:
|
||||
if !utils.ContainsString(exclude.Values, strconv.FormatBool(resourceValue.(bool))) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
case reflect.String:
|
||||
if !utils.ContainsString(exclude.Values, resourceValue.(string)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
case reflect.Float64:
|
||||
if !utils.ContainsString(exclude.Values, fmt.Sprintf("%.f", resourceValue)) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
case reflect.Map:
|
||||
// `AppArmor` control
|
||||
for key, value := range resourceValue.(map[string]interface{}) {
|
||||
if !strings.Contains(key, "container.apparmor.security.beta.kubernetes.io/") {
|
||||
continue
|
||||
}
|
||||
// For allowed value: "localhost/*"
|
||||
if strings.Contains(value.(string), "localhost/") {
|
||||
continue
|
||||
}
|
||||
if !utils.ContainsString(exclude.Values, value.(string)) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
case reflect.Slice:
|
||||
exempted := allowedValuesSlice(resourceValue.([]interface{}), exclude)
|
||||
if !exempted {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
|
||||
return len(defaultCheckResults) == 0, defaultCheckResults, nil
|
||||
}
|
||||
|
|
5188
pkg/pss/evaluate_test.go
Normal file
5188
pkg/pss/evaluate_test.go
Normal file
File diff suppressed because it is too large
Load diff
|
@ -7,10 +7,10 @@ type restrictedField struct {
|
|||
allowedValues []interface{}
|
||||
}
|
||||
|
||||
type PSSCheckResult struct {
|
||||
ID string
|
||||
CheckResult policy.CheckResult
|
||||
RestrictedFields []restrictedField
|
||||
type pssCheckResult struct {
|
||||
id string
|
||||
checkResult policy.CheckResult
|
||||
restrictedFields []restrictedField
|
||||
}
|
||||
|
||||
// Translate PSS control to CheckResult.ID so that we can use PSS control in Kyverno policy
|
||||
|
@ -18,10 +18,12 @@ type PSSCheckResult struct {
|
|||
// For CheckResult.ID see: https://github.com/kubernetes/pod-security-admission/tree/master/policy
|
||||
var PSS_controls_to_check_id = map[string][]string{
|
||||
// Controls with 2 different controls for each level
|
||||
// container-level control
|
||||
"Capabilities": {
|
||||
"capabilities_baseline",
|
||||
"capabilities_restricted",
|
||||
},
|
||||
// Container and Pod-level control
|
||||
"Seccomp": {
|
||||
"seccompProfile_baseline",
|
||||
"seccompProfile_restricted",
|
||||
|
@ -38,9 +40,6 @@ var PSS_controls_to_check_id = map[string][]string{
|
|||
"/proc Mount Type": {
|
||||
"procMount",
|
||||
},
|
||||
"procMount": {
|
||||
"hostPorts",
|
||||
},
|
||||
|
||||
// Container and pod-level controls
|
||||
"HostProcess": {
|
||||
|
@ -67,10 +66,10 @@ var PSS_controls_to_check_id = map[string][]string{
|
|||
},
|
||||
|
||||
// === Restricted
|
||||
// Container and pod-level controls
|
||||
"Privilege Escalation": {
|
||||
"allowPrivilegeEscalation",
|
||||
},
|
||||
// Container and pod-level controls
|
||||
"Running as Non-root": {
|
||||
"runAsNonRoot",
|
||||
},
|
||||
|
|
137
pkg/pss/utils.go
137
pkg/pss/utils.go
|
@ -1,125 +1,51 @@
|
|||
package pss
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"fmt"
|
||||
|
||||
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
|
||||
"github.com/kyverno/kyverno/pkg/utils"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/pod-security-admission/policy"
|
||||
)
|
||||
|
||||
func containsContainer(containers interface{}, containerName string) bool {
|
||||
switch v := containers.(type) {
|
||||
case []interface{}:
|
||||
for _, container := range v {
|
||||
switch v := container.(type) {
|
||||
case corev1.Container:
|
||||
if v.Name == containerName {
|
||||
return true
|
||||
}
|
||||
case corev1.EphemeralContainer:
|
||||
if v.Name == containerName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
case []corev1.Container:
|
||||
for _, container := range v {
|
||||
if container.Name == containerName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
case []corev1.EphemeralContainer:
|
||||
for _, container := range v {
|
||||
if container.Name == containerName {
|
||||
return true
|
||||
}
|
||||
}
|
||||
// getPodWithMatchingContainers extracts matching container/pod info by the given exclude rule
|
||||
// and returns pod manifests containing spec and container info respectively
|
||||
func getPodWithMatchingContainers(exclude kyvernov1.PodSecurityStandard, pod *corev1.Pod) (podSpec, matching *corev1.Pod) {
|
||||
if len(exclude.Images) == 0 {
|
||||
podSpec = pod.DeepCopy()
|
||||
podSpec.Spec.Containers = []corev1.Container{{Name: "fake"}}
|
||||
podSpec.Spec.InitContainers = nil
|
||||
podSpec.Spec.EphemeralContainers = nil
|
||||
return podSpec, nil
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Get copy of pod with containers (containers, initContainers, ephemeralContainers) matching the exclude.image
|
||||
func getPodWithMatchingContainers(exclude []kyvernov1.PodSecurityStandard, pod *corev1.Pod) (podCopy corev1.Pod) {
|
||||
podCopy = *pod
|
||||
podCopy.Spec.Containers = []corev1.Container{}
|
||||
podCopy.Spec.InitContainers = []corev1.Container{}
|
||||
podCopy.Spec.EphemeralContainers = []corev1.EphemeralContainer{}
|
||||
|
||||
matchingImages := exclude.Images
|
||||
matching = &corev1.Pod{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: pod.GetName(),
|
||||
Namespace: pod.GetNamespace(),
|
||||
},
|
||||
}
|
||||
for _, container := range pod.Spec.Containers {
|
||||
for _, excludeRule := range exclude {
|
||||
// Ignore all restrictedFields when we only specify the `controlName` with no `restrictedField`
|
||||
controlNameOnly := excludeRule.RestrictedField == ""
|
||||
if !utils.ContainsString(excludeRule.Images, container.Image) {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(excludeRule.RestrictedField, "spec.containers[*]") || controlNameOnly {
|
||||
// Add to matchingContainers if either it's empty or is unique
|
||||
if len(podCopy.Spec.Containers) == 0 || !containsContainer(podCopy.Spec.Containers, container.Name) {
|
||||
podCopy.Spec.Containers = append(podCopy.Spec.Containers, container)
|
||||
}
|
||||
}
|
||||
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
|
||||
matching.Spec.Containers = append(matching.Spec.Containers, container)
|
||||
}
|
||||
}
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
for _, excludeRule := range exclude {
|
||||
// Ignore all restrictedFields when we only specify the `controlName` with no `restrictedField`
|
||||
controlNameOnly := excludeRule.RestrictedField == ""
|
||||
if !utils.ContainsString(excludeRule.Images, container.Image) {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(excludeRule.RestrictedField, "spec.initContainers[*]") || controlNameOnly {
|
||||
// Add to matchingContainers if either it's empty or is unique
|
||||
if len(podCopy.Spec.InitContainers) == 0 || !containsContainer(podCopy.Spec.InitContainers, container.Name) {
|
||||
podCopy.Spec.InitContainers = append(podCopy.Spec.InitContainers, container)
|
||||
}
|
||||
}
|
||||
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
|
||||
matching.Spec.InitContainers = append(matching.Spec.InitContainers, container)
|
||||
}
|
||||
}
|
||||
for _, container := range pod.Spec.EphemeralContainers {
|
||||
for _, excludeRule := range exclude {
|
||||
// Ignore all restrictedFields when we only specify the `controlName` with no `restrictedField`
|
||||
controlNameOnly := excludeRule.RestrictedField == ""
|
||||
if !utils.ContainsString(excludeRule.Images, container.Image) {
|
||||
continue
|
||||
}
|
||||
if strings.Contains(excludeRule.RestrictedField, "spec.ephemeralContainers[*]") || controlNameOnly {
|
||||
// Add to matchingContainers if either it's empty or is unique
|
||||
if len(podCopy.Spec.EphemeralContainers) == 0 || !containsContainer(podCopy.Spec.EphemeralContainers, container.Name) {
|
||||
podCopy.Spec.EphemeralContainers = append(podCopy.Spec.EphemeralContainers, container)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return podCopy
|
||||
}
|
||||
|
||||
// Get containers NOT matching images specified in Exclude values
|
||||
func getPodWithNotMatchingContainers(exclude []kyvernov1.PodSecurityStandard, pod *corev1.Pod, podWithMatchingContainers *corev1.Pod) (podCopy corev1.Pod) {
|
||||
// Only copy containers because we have already evaluated the pod-level controls
|
||||
// e.g.: spec.securityContext.hostProcess
|
||||
podCopy.Spec.Containers = []corev1.Container{}
|
||||
podCopy.Spec.InitContainers = []corev1.Container{}
|
||||
podCopy.Spec.EphemeralContainers = []corev1.EphemeralContainer{}
|
||||
|
||||
// Append containers that are not in podWithMatchingContainers already evaluated in EvaluatePod()
|
||||
for _, container := range pod.Spec.Containers {
|
||||
if !containsContainer(podWithMatchingContainers.Spec.Containers, container.Name) {
|
||||
podCopy.Spec.Containers = append(podCopy.Spec.Containers, container)
|
||||
}
|
||||
}
|
||||
for _, container := range pod.Spec.InitContainers {
|
||||
if !containsContainer(podWithMatchingContainers.Spec.InitContainers, container.Name) {
|
||||
podCopy.Spec.InitContainers = append(podCopy.Spec.InitContainers, container)
|
||||
}
|
||||
}
|
||||
for _, container := range pod.Spec.EphemeralContainers {
|
||||
if !containsContainer(podWithMatchingContainers.Spec.EphemeralContainers, container.Name) {
|
||||
podCopy.Spec.EphemeralContainers = append(podCopy.Spec.EphemeralContainers, container)
|
||||
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
|
||||
matching.Spec.EphemeralContainers = append(matching.Spec.EphemeralContainers, container)
|
||||
}
|
||||
}
|
||||
return podCopy
|
||||
|
||||
return nil, matching
|
||||
}
|
||||
|
||||
// Get restrictedFields from Check.ID
|
||||
|
@ -134,11 +60,10 @@ func getRestrictedFields(check policy.Check) []restrictedField {
|
|||
return nil
|
||||
}
|
||||
|
||||
func containsContainerLevelControl(restrictedFields []restrictedField) bool {
|
||||
for _, restrictedField := range restrictedFields {
|
||||
if strings.Contains(restrictedField.path, "ontainers[*]") {
|
||||
return true
|
||||
}
|
||||
func FormatChecksPrint(checks []pssCheckResult) string {
|
||||
var str string
|
||||
for _, check := range checks {
|
||||
str += fmt.Sprintf("(%+v)\n", check.checkResult)
|
||||
}
|
||||
return false
|
||||
return str
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ func contains(list []string, element string, fn func(string, string) bool) bool
|
|||
|
||||
// ContainsNamepace check if namespace satisfies any list of pattern(regex)
|
||||
func ContainsNamepace(patterns []string, ns string) bool {
|
||||
return contains(patterns, ns, compareNamespaces)
|
||||
return contains(patterns, ns, comparePatterns)
|
||||
}
|
||||
|
||||
// ContainsString checks if the string is contained in the list
|
||||
|
@ -91,7 +91,11 @@ func ContainsString(list []string, element string) bool {
|
|||
return contains(list, element, compareString)
|
||||
}
|
||||
|
||||
func compareNamespaces(pattern, ns string) bool {
|
||||
func ContainsWildcardPatterns(patterns []string, key string) bool {
|
||||
return contains(patterns, key, comparePatterns)
|
||||
}
|
||||
|
||||
func comparePatterns(pattern, ns string) bool {
|
||||
return wildcard.Match(pattern, ns)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
apiVersion: kyverno.io/v1
|
||||
kind: ClusterPolicy
|
||||
metadata:
|
||||
name: enforce-baseline-exclude-se-linux-options
|
||||
spec:
|
||||
validationFailureAction: enforce
|
||||
rules:
|
||||
- name: enforce-baseline-exclude-se-linux-options
|
||||
match:
|
||||
any:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
namespaces:
|
||||
- privileged-pss-with-kyverno
|
||||
validate:
|
||||
podSecurity:
|
||||
level: baseline
|
||||
version: v1.24
|
||||
exclude:
|
||||
- controlName: "SELinux"
|
||||
restrictedField: spec.containers[*].securityContext.seLinuxOptions.role
|
||||
images:
|
||||
- nginx
|
||||
values:
|
||||
- baz
|
||||
- controlName: "SELinux"
|
||||
restrictedField: spec.initContainers[*].securityContext.seLinuxOptions.role
|
||||
images:
|
||||
- nodejs
|
||||
values:
|
||||
- init-bazo
|
Loading…
Add table
Reference in a new issue