mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +00:00
fix: add podSecurity validation checks for exceptions (#9817)
Signed-off-by: Mariam Fahmy <mariam.fahmy@nirmata.com>
This commit is contained in:
parent
511df7a466
commit
07a6bf42f5
9 changed files with 135 additions and 30 deletions
|
@ -5,6 +5,7 @@ import (
|
|||
"fmt"
|
||||
|
||||
"github.com/kyverno/kyverno/pkg/engine/variables/regex"
|
||||
"github.com/kyverno/kyverno/pkg/pss/utils"
|
||||
"github.com/sigstore/k8s-manifest-sigstore/pkg/k8smanifest"
|
||||
admissionv1 "k8s.io/api/admission/v1"
|
||||
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
|
||||
|
@ -469,6 +470,28 @@ type PodSecurityStandard struct {
|
|||
Values []string `json:"values,omitempty" yaml:"values,omitempty"`
|
||||
}
|
||||
|
||||
func (pss *PodSecurityStandard) Validate(path *field.Path) (errs field.ErrorList) {
|
||||
// container level control must specify images
|
||||
if containsString(utils.PSS_container_level_control, pss.ControlName) {
|
||||
if len(pss.Images) == 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("controlName"), pss.ControlName, "exclude.images must be specified for the container level control"))
|
||||
}
|
||||
} else if containsString(utils.PSS_pod_level_control, pss.ControlName) {
|
||||
if len(pss.Images) != 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("controlName"), pss.ControlName, "exclude.images must not be specified for the pod level control"))
|
||||
}
|
||||
}
|
||||
|
||||
if pss.RestrictedField != "" && len(pss.Values) == 0 {
|
||||
errs = append(errs, field.Forbidden(path.Child("values"), "values is required"))
|
||||
}
|
||||
|
||||
if pss.RestrictedField == "" && len(pss.Values) != 0 {
|
||||
errs = append(errs, field.Forbidden(path.Child("restrictedField"), "restrictedField is required"))
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
// CEL allows validation checks using the Common Expression Language (https://kubernetes.io/docs/reference/using-api/cel/).
|
||||
type CEL struct {
|
||||
// Expressions is a list of CELExpression types.
|
||||
|
|
|
@ -396,16 +396,7 @@ func (r *Rule) ValidatePSaControlNames(path *field.Path) (errs field.ErrorList)
|
|||
}
|
||||
|
||||
for idx, exclude := range podSecurity.Exclude {
|
||||
// container level control must specify images
|
||||
if containsString(utils.PSS_container_level_control, exclude.ControlName) {
|
||||
if len(exclude.Images) == 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("podSecurity").Child("exclude").Index(idx).Child("controlName"), exclude.ControlName, "exclude.images must be specified for the container level control"))
|
||||
}
|
||||
} else if containsString(utils.PSS_pod_level_control, exclude.ControlName) {
|
||||
if len(exclude.Images) != 0 {
|
||||
errs = append(errs, field.Invalid(path.Child("podSecurity").Child("exclude").Index(idx).Child("controlName"), exclude.ControlName, "exclude.images must not be specified for the pod level control"))
|
||||
}
|
||||
}
|
||||
errs = append(errs, exclude.Validate(path.Child("podSecurity").Child("exclude").Index(idx))...)
|
||||
|
||||
if containsString([]string{"Seccomp", "Capabilities"}, exclude.ControlName) {
|
||||
continue
|
||||
|
|
|
@ -100,6 +100,11 @@ func (p *PolicyExceptionSpec) Validate(path *field.Path) (errs field.ErrorList)
|
|||
for i, e := range p.Exceptions {
|
||||
errs = append(errs, e.Validate(exceptionsPath.Index(i))...)
|
||||
}
|
||||
|
||||
podSecuityPath := path.Child("podSecurity")
|
||||
for i, p := range p.PodSecurity {
|
||||
errs = append(errs, p.Validate(podSecuityPath.Index(i))...)
|
||||
}
|
||||
return errs
|
||||
}
|
||||
|
||||
|
|
|
@ -68,20 +68,6 @@ func (v *Validate) Validate(ctx context.Context) (string, error) {
|
|||
}
|
||||
}
|
||||
|
||||
if v.rule.PodSecurity != nil {
|
||||
if len(v.rule.PodSecurity.Exclude) != 0 {
|
||||
for _, exclude := range v.rule.PodSecurity.Exclude {
|
||||
if exclude.RestrictedField != "" && len(exclude.Values) == 0 {
|
||||
return "", fmt.Errorf("podSecurity.exclude.values is required")
|
||||
}
|
||||
|
||||
if exclude.RestrictedField == "" && len(exclude.Values) != 0 {
|
||||
return "", fmt.Errorf("podSecurity.exclude.restrictedField is required")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if v.rule.CEL != nil {
|
||||
for _, expression := range v.rule.CEL.Expressions {
|
||||
if expression.Expression == "" {
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
apiVersion: chainsaw.kyverno.io/v1alpha1
|
||||
kind: Test
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: invalid-pod-security-exceptions
|
||||
spec:
|
||||
steps:
|
||||
- name: Apply the first policy exception
|
||||
try:
|
||||
- script:
|
||||
content: kubectl apply -f exception-1.yaml
|
||||
check:
|
||||
($error != null): true
|
||||
# This check ensures the contents of stderr are exactly as shown.
|
||||
($stderr): |-
|
||||
Error from server: error when creating "exception-1.yaml": admission webhook "kyverno-svc.kyverno.svc" denied the request: [spec.podSecurity[0].controlName: Invalid value: "Capabilities": exclude.images must be specified for the container level control, spec.podSecurity[3].controlName: Invalid value: "Privilege Escalation": exclude.images must be specified for the container level control]
|
||||
- name: Apply the second policy exception
|
||||
try:
|
||||
- script:
|
||||
content: kubectl apply -f exception-2.yaml
|
||||
check:
|
||||
($error != null): true
|
||||
# This check ensures the contents of stderr are exactly as shown.
|
||||
($stderr): |-
|
||||
Error from server: error when creating "exception-2.yaml": admission webhook "kyverno-svc.kyverno.svc" denied the request: spec.podSecurity[0].values: Forbidden: values is required
|
||||
- name: Apply the third policy exception
|
||||
try:
|
||||
- script:
|
||||
content: kubectl apply -f exception-3.yaml
|
||||
check:
|
||||
($error != null): true
|
||||
# This check ensures the contents of stderr are exactly as shown.
|
||||
($stderr): |-
|
||||
Error from server: error when creating "exception-3.yaml": admission webhook "kyverno-svc.kyverno.svc" denied the request: spec.podSecurity[0].restrictedField: Forbidden: restrictedField is required
|
|
@ -0,0 +1,23 @@
|
|||
apiVersion: kyverno.io/v2
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: exception-1
|
||||
spec:
|
||||
exceptions:
|
||||
- policyName: psa
|
||||
ruleNames:
|
||||
- restricted
|
||||
match:
|
||||
all:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
podSecurity:
|
||||
- controlName: Capabilities
|
||||
- controlName: Host Namespaces
|
||||
- controlName: HostPath Volumes
|
||||
- controlName: Privilege Escalation
|
||||
- controlName: Running as Non-root
|
||||
- controlName: Seccomp
|
||||
- controlName: Volume Types
|
|
@ -0,0 +1,20 @@
|
|||
apiVersion: kyverno.io/v2
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: exception-2
|
||||
spec:
|
||||
exceptions:
|
||||
- policyName: psa
|
||||
ruleNames:
|
||||
- restricted
|
||||
match:
|
||||
all:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
podSecurity:
|
||||
- controlName: "/proc Mount Type"
|
||||
images:
|
||||
- nginx
|
||||
restrictedField: "spec.containers[*].securityContext.procMount"
|
|
@ -0,0 +1,21 @@
|
|||
apiVersion: kyverno.io/v2
|
||||
kind: PolicyException
|
||||
metadata:
|
||||
creationTimestamp: null
|
||||
name: exception-3
|
||||
spec:
|
||||
exceptions:
|
||||
- policyName: psa
|
||||
ruleNames:
|
||||
- restricted
|
||||
match:
|
||||
all:
|
||||
- resources:
|
||||
kinds:
|
||||
- Pod
|
||||
podSecurity:
|
||||
- controlName: "/proc Mount Type"
|
||||
images:
|
||||
- nginx
|
||||
values:
|
||||
- "bar"
|
|
@ -10,14 +10,16 @@ spec:
|
|||
- script:
|
||||
content: kubectl apply -f policy-1.yaml
|
||||
check:
|
||||
# This check ensures that the string "undefined field 'automountServiceAccountToken';" is found
|
||||
# in stderr or else fails
|
||||
(contains($stderr, 'podSecurity.exclude.values is required')): true
|
||||
($error != null): true
|
||||
# This check ensures the contents of stderr are exactly as shown.
|
||||
($stderr): |-
|
||||
Error from server: error when creating "policy-1.yaml": admission webhook "validate-policy.kyverno.svc" denied the request: spec.rules[0].podSecurity.exclude[0].values: Forbidden: values is required
|
||||
- name: Apply the second policy
|
||||
try:
|
||||
- script:
|
||||
content: kubectl apply -f policy-2.yaml
|
||||
check:
|
||||
# This check ensures that the string "podSecurity.exclude.restrictedField is required" is found
|
||||
# in stderr or else fails
|
||||
(contains($stderr, 'podSecurity.exclude.restrictedField is required')): true
|
||||
($error != null): true
|
||||
# This check ensures the contents of stderr are exactly as shown.
|
||||
($stderr): |-
|
||||
Error from server: error when creating "policy-2.yaml": admission webhook "validate-policy.kyverno.svc" denied the request: spec.rules[0].podSecurity.exclude[0].restrictedField: Forbidden: restrictedField is required
|
||||
|
|
Loading…
Reference in a new issue