1
0
Fork 0
mirror of https://github.com/kyverno/kyverno.git synced 2024-12-14 11:57:48 +00:00

Add PSa policy validations (#4735)

* Validate PSa control names

Signed-off-by: ShutingZhao <shuting@nirmata.com>

* Add validation checks for the PSa rule

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:
shuting 2022-09-29 12:03:13 +08:00 committed by GitHub
parent a1182859ad
commit 1d83e86c12
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 1664 additions and 681 deletions

View file

@ -344,6 +344,7 @@ type PodSecurity struct {
type PodSecurityStandard struct {
// ControlName specifies the name of the Pod Security Standard control.
// See: https://kubernetes.io/docs/concepts/security/pod-security-standards/
// +kubebuilder:validation:Enum=HostProcess;Host Namespaces;Privileged Containers;Capabilities;HostPath Volumes;Host Ports;AppArmor;SELinux;/proc Mount Type;Seccomp;Sysctls;Volume Types;Privilege Escalation;Running as Non-root;Running as Non-root user
ControlName string `json:"controlName" yaml:"controlName"`
// Images selects matching containers and applies the container level PSS.

View file

@ -2,6 +2,7 @@ package v1
import (
"encoding/json"
"fmt"
"testing"
"gotest.tools/assert"
@ -328,6 +329,391 @@ func Test_Validate_NamespacedPolicy_MutateRuleTargetNamespace(t *testing.T) {
}
}
func Test_ValidatePSaControlNames(t *testing.T) {
path := field.NewPath("dummy")
testcases := []struct {
description string
rule []byte
errors func(r *Rule) field.ErrorList
}{
{
description: "baseline_with_restricted_control_name",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "baseline",
"version": "v1.24",
"exclude": [
{
"controlName": "Running as Non-root",
"images": [
"nginx",
"nodejs"
]
},
{
"controlName": "Seccomp",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
errors: func(r *Rule) (errs field.ErrorList) {
return append(errs,
field.Invalid(path.Child("podSecurity").Child("exclude").Index(0).Child("controlName"), "Running as Non-root", "Invalid control name defined at the given level"),
)
},
},
{
description: "baseline_with_baseline_control_name",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "baseline",
"version": "v1.24",
"exclude": [
{
"controlName": "/proc Mount Type",
"images": [
"nginx",
"nodejs"
]
},
{
"controlName": "Seccomp",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
},
{
description: "restricted_with_baseline_control_name",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "restricted",
"version": "v1.24",
"exclude": [
{
"controlName": "/proc Mount Type",
"images": [
"nginx",
"nodejs"
]
},
{
"controlName": "Seccomp",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
errors: func(r *Rule) (errs field.ErrorList) {
return append(errs,
field.Invalid(path.Child("podSecurity").Child("exclude").Index(0).Child("controlName"), "/proc Mount Type", "Invalid control name defined at the given level"),
)
},
},
{
description: "restricted_with_restricted_control_name",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "restricted",
"version": "v1.24",
"exclude": [
{
"controlName": "Privilege Escalation",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
},
{
description: "container_level_control_with_images",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "restricted",
"version": "v1.24",
"exclude": [
{
"controlName": "Privilege Escalation"
}
]
}
}
}`),
errors: func(r *Rule) (errs field.ErrorList) {
return append(errs,
field.Invalid(path.Child("podSecurity").Child("exclude").Index(0).Child("controlName"), "Privilege Escalation", "exclude.images must be specified for the container level control"),
)
},
},
{
description: "container_level_control_without_images",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "restricted",
"version": "v1.24",
"exclude": [
{
"controlName": "Privilege Escalation",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
},
{
description: "pod_level_control_with_images",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "baseline",
"version": "v1.24",
"exclude": [
{
"controlName": "Host Namespaces",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
errors: func(r *Rule) (errs field.ErrorList) {
return append(errs,
field.Invalid(path.Child("podSecurity").Child("exclude").Index(0).Child("controlName"), "Host Namespaces", "exclude.images must not be specified for the pod level control"),
)
},
},
{
description: "pod_level_control_without_images",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "baseline",
"version": "v1.24",
"exclude": [
{
"controlName": "Host Namespaces"
}
]
}
}
}`),
},
{
description: "mixed_level_controls_without_images",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "baseline",
"version": "v1.24",
"exclude": [
{
"controlName": "SELinux"
}
]
}
}
}`),
},
{
description: "mixed_level_controls_with_images",
rule: []byte(`
{
"name": "enforce-baseline-exclude-all-hostProcesses-all-containers-nginx",
"match": {
"any": [
{
"resources": {
"kinds": [
"Pod"
]
}
}
]
},
"validate": {
"podSecurity": {
"level": "baseline",
"version": "v1.24",
"exclude": [
{
"controlName": "SELinux",
"images": [
"nginx",
"nodejs"
]
}
]
}
}
}`),
},
}
for _, testcase := range testcases {
var rule Rule
err := json.Unmarshal(testcase.rule, &rule)
assert.NilError(t, err)
errs := rule.ValidatePSaControlNames(path)
var expectedErrs field.ErrorList
if testcase.errors != nil {
expectedErrs = testcase.errors(&rule)
}
fmt.Println("====errs", errs)
assert.Equal(t, len(errs), len(expectedErrs))
for i := range errs {
assert.Equal(t, errs[i].Error(), expectedErrs[i].Error())
}
}
}
func Test_Validate_ClusterPolicy_MutateRuleTargetNamespace(t *testing.T) {
path := field.NewPath("dummy")
testcases := []struct {

View file

@ -5,6 +5,7 @@ import (
"fmt"
"reflect"
"github.com/kyverno/kyverno/pkg/pss/utils"
wildcard "github.com/kyverno/kyverno/pkg/utils/wildcard"
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
apiextv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
@ -139,6 +140,10 @@ func (r *Rule) IsMutateExisting() bool {
return r.Mutation.Targets != nil
}
func (r *Rule) IsPodSecurity() bool {
return r.Validation.PodSecurity != nil
}
// IsCloneSyncGenerate checks if the generate rule has the clone block with sync=true
func (r *Rule) GetCloneSyncForGenerate() (clone bool, sync bool) {
if !r.HasGenerate() {
@ -359,6 +364,38 @@ func (r *Rule) ValidateMutationRuleTargetNamespace(path *field.Path, namespaced
return errs
}
func (r *Rule) ValidatePSaControlNames(path *field.Path) (errs field.ErrorList) {
if r.IsPodSecurity() {
podSecurity := r.Validation.PodSecurity
forbiddenControls := utils.PSS_baseline_control_names
if podSecurity.Level == "baseline" {
forbiddenControls = utils.PSS_restricted_control_names
}
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"))
}
}
if containsString([]string{"Seccomp", "Capabilities"}, exclude.ControlName) {
continue
}
if containsString(forbiddenControls, exclude.ControlName) {
errs = append(errs, field.Invalid(path.Child("podSecurity").Child("exclude").Index(idx).Child("controlName"), exclude.ControlName, "Invalid control name defined at the given level"))
}
}
}
return errs
}
// Validate implements programmatic validation
func (r *Rule) Validate(path *field.Path, namespaced bool, policyNamespace string, clusterResources sets.String) (errs field.ErrorList) {
errs = append(errs, r.ValidateRuleType(path)...)
@ -366,5 +403,6 @@ func (r *Rule) Validate(path *field.Path, namespaced bool, policyNamespace strin
errs = append(errs, r.MatchResources.Validate(path.Child("match"), namespaced, clusterResources)...)
errs = append(errs, r.ExcludeResources.Validate(path.Child("exclude"), namespaced, clusterResources)...)
errs = append(errs, r.ValidateMutationRuleTargetNamespace(path, namespaced, policyNamespace)...)
errs = append(errs, r.ValidatePSaControlNames(path)...)
return errs
}

View file

@ -45,3 +45,12 @@ func ValidatePolicyName(path *field.Path, name string) (errs field.ErrorList) {
}
return errs
}
func containsString(list []string, key string) bool {
for _, val := range list {
if val == key {
return true
}
}
return false
}

View file

@ -2460,6 +2460,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -4180,6 +4196,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -5852,6 +5884,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -7547,6 +7595,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -9815,6 +9879,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -11535,6 +11615,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -13207,6 +13303,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.
@ -14902,6 +15014,22 @@ spec:
properties:
controlName:
description: 'ControlName specifies the name of the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
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.

View file

@ -2367,6 +2367,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -5208,6 +5224,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -7844,6 +7876,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -10645,6 +10693,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers

View file

@ -2368,6 +2368,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -5210,6 +5226,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -7847,6 +7879,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -10648,6 +10696,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers

View file

@ -3653,6 +3653,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -6494,6 +6510,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -9130,6 +9162,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -11931,6 +11979,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -15380,6 +15444,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -18222,6 +18302,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -20859,6 +20955,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -23660,6 +23772,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers

View file

@ -3647,6 +3647,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -6488,6 +6504,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -9124,6 +9156,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -11925,6 +11973,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -15371,6 +15435,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -18213,6 +18293,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -20850,6 +20946,22 @@ spec:
controlName:
description: 'ControlName specifies the name of
the Pod Security Standard control. See: https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers
@ -23651,6 +23763,22 @@ spec:
description: 'ControlName specifies the name
of the Pod Security Standard control. See:
https://kubernetes.io/docs/concepts/security/pod-security-standards/'
enum:
- HostProcess
- Host Namespaces
- Privileged Containers
- Capabilities
- HostPath Volumes
- Host Ports
- AppArmor
- SELinux
- /proc Mount Type
- Seccomp
- Sysctls
- Volume Types
- Privilege Escalation
- Running as Non-root
- Running as Non-root user
type: string
images:
description: Images selects matching containers

View file

@ -1,14 +1,19 @@
package pss
import (
"fmt"
kyvernov1 "github.com/kyverno/kyverno/api/kyverno/v1"
pssutils "github.com/kyverno/kyverno/pkg/pss/utils"
"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/api"
"k8s.io/pod-security-admission/policy"
)
// 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 []pssutils.PSSCheckResult) {
checks := policy.DefaultChecks()
for _, check := range checks {
@ -20,10 +25,10 @@ func evaluatePSS(level *api.LevelVersion, pod corev1.Pod) (results []pssCheckRes
checkResult := versionCheck.CheckPod(&pod.ObjectMeta, &pod.Spec)
// 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, pssutils.PSSCheckResult{
ID: check.ID,
CheckResult: checkResult,
RestrictedFields: GetRestrictedFields(check),
})
}
}
@ -31,22 +36,22 @@ func evaluatePSS(level *api.LevelVersion, pod corev1.Pod) (results []pssCheckRes
return results
}
func exemptKyvernoExclusion(defaultCheckResults, excludeCheckResults []pssCheckResult, exclude kyvernov1.PodSecurityStandard) []pssCheckResult {
defaultCheckResultsMap := make(map[string]pssCheckResult, len(defaultCheckResults))
func exemptKyvernoExclusion(defaultCheckResults, excludeCheckResults []pssutils.PSSCheckResult, exclude kyvernov1.PodSecurityStandard) []pssutils.PSSCheckResult {
defaultCheckResultsMap := make(map[string]pssutils.PSSCheckResult, len(defaultCheckResults))
for _, result := range defaultCheckResults {
defaultCheckResultsMap[result.id] = result
defaultCheckResultsMap[result.ID] = result
}
for _, excludeResult := range excludeCheckResults {
for _, checkID := range PSS_controls_to_check_id[exclude.ControlName] {
if excludeResult.id == checkID {
for _, checkID := range pssutils.PSS_controls_to_check_id[exclude.ControlName] {
if excludeResult.ID == checkID {
delete(defaultCheckResultsMap, checkID)
}
}
}
var newDefaultCheckResults []pssCheckResult
var newDefaultCheckResults []pssutils.PSSCheckResult
for _, result := range defaultCheckResultsMap {
newDefaultCheckResults = append(newDefaultCheckResults, result)
}
@ -75,7 +80,7 @@ func parseVersion(rule *kyvernov1.PodSecurity) (*api.LevelVersion, error) {
}
// 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) {
func EvaluatePod(rule *kyvernov1.PodSecurity, pod *corev1.Pod) (bool, []pssutils.PSSCheckResult, error) {
level, err := parseVersion(rule)
if err != nil {
return false, nil, err
@ -84,7 +89,7 @@ func EvaluatePod(rule *kyvernov1.PodSecurity, pod *corev1.Pod) (bool, []pssCheck
defaultCheckResults := evaluatePSS(level, *pod)
for _, exclude := range rule.Exclude {
spec, matching := getPodWithMatchingContainers(exclude, pod)
spec, matching := GetPodWithMatchingContainers(exclude, pod)
switch {
// exclude pod level checks
@ -101,3 +106,61 @@ func EvaluatePod(rule *kyvernov1.PodSecurity, pod *corev1.Pod) (bool, []pssCheck
return len(defaultCheckResults) == 0, defaultCheckResults, nil
}
// 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
}
matchingImages := exclude.Images
matching = &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: pod.GetName(),
Namespace: pod.GetNamespace(),
},
}
for _, container := range pod.Spec.Containers {
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
matching.Spec.Containers = append(matching.Spec.Containers, container)
}
}
for _, container := range pod.Spec.InitContainers {
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
matching.Spec.InitContainers = append(matching.Spec.InitContainers, container)
}
}
for _, container := range pod.Spec.EphemeralContainers {
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
matching.Spec.EphemeralContainers = append(matching.Spec.EphemeralContainers, container)
}
}
return nil, matching
}
// Get restrictedFields from Check.ID
func GetRestrictedFields(check policy.Check) []pssutils.RestrictedField {
for _, control := range pssutils.PSS_controls_to_check_id {
for _, checkID := range control {
if check.ID == checkID {
return pssutils.PSS_controls[checkID]
}
}
}
return nil
}
func FormatChecksPrint(checks []pssutils.PSSCheckResult) string {
var str string
for _, check := range checks {
str += fmt.Sprintf("(%+v)\n", check.CheckResult)
}
return str
}

View file

@ -1,599 +0,0 @@
package pss
import "k8s.io/pod-security-admission/policy"
type restrictedField struct {
path string
allowedValues []interface{}
}
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
// For PSS controls see: https://kubernetes.io/docs/concepts/security/pod-security-standards/
// 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",
},
// === Baseline
// Container-level controls
"Privileged Containers": {
"privileged",
},
"Host Ports": {
"hostPorts",
},
"/proc Mount Type": {
"procMount",
},
// Container and pod-level controls
"HostProcess": {
"windowsHostProcess",
},
"SELinux": {
"seLinuxOptions",
},
// Pod-level controls
"Host Namespaces": {
"hostNamespaces",
},
"HostPath Volumes": {
"hostPathVolumes",
},
"Sysctls": {
"sysctls",
},
// Metadata-level control
"AppArmor": {
"appArmorProfile",
},
// === Restricted
"Privilege Escalation": {
"allowPrivilegeEscalation",
},
// Container and pod-level controls
"Running as Non-root": {
"runAsNonRoot",
},
"Running as Non-root user": {
"runAsUser",
},
// Pod-level controls
"Volume Types": {
"restrictedVolumes",
},
}
var PSS_controls = map[string][]restrictedField{
// Control name as key, same as ID field in CheckResult
// === Baseline
// Container-level controls
"privileged": {
{
// type:
// - container-level
// - pod-container-level
// - pod level
path: "spec.containers[*].securityContext.privileged",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.initContainers[*].securityContext.privileged",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.ephemeralContainers[*].securityContext.privileged",
allowedValues: []interface{}{
false,
nil,
},
},
},
"hostPorts": {
{
path: "spec.containers[*].ports[*].hostPort",
allowedValues: []interface{}{
false,
0,
},
},
{
path: "spec.initContainers[*].ports[*].hostPort",
allowedValues: []interface{}{
false,
0,
},
},
{
path: "spec.ephemeralContainers[*].ports[*].hostPort",
allowedValues: []interface{}{
false,
0,
},
},
},
"procMount": {
{
path: "spec.containers[*].securityContext.procMount",
allowedValues: []interface{}{
nil,
"Default",
},
},
{
path: "spec.initContainers[*].securityContext.procMount",
allowedValues: []interface{}{
nil,
"Default",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.procMount",
allowedValues: []interface{}{
nil,
"Default",
},
},
},
"capabilities_baseline": {
{
path: "spec.containers[*].securityContext.capabilities.add",
allowedValues: []interface{}{
nil,
"AUDIT_WRITE",
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"MKNOD",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
},
},
{
path: "spec.initContainers[*].securityContext.capabilities.add",
allowedValues: []interface{}{
nil,
"AUDIT_WRITE",
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"MKNOD",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.capabilities.add",
allowedValues: []interface{}{
nil,
"AUDIT_WRITE",
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"MKNOD",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
},
},
},
// Container and pod-level controls
"windowsHostProcess": {
{
path: "spec.securityContext.windowsOptions.hostProcess",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.containers[*].securityContext.windowsOptions.hostProcess",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.initContainers[*].securityContext.windowsOptions.hostProcess",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.ephemeralContainers[*].securityContext.windowsOptions.hostProcess",
allowedValues: []interface{}{
false,
nil,
},
},
},
"seLinuxOptions": {
// type
{
path: "spec.securityContext.seLinuxOptions.type",
allowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
{
path: "spec.containers[*].securityContext.seLinuxOptions.type",
allowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
{
path: "spec.initContainers[*].securityContext.seLinuxOptions.type",
allowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.seLinuxOptions.type",
allowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
// user
{
path: "spec.securityContext.seLinuxOptions.user",
allowedValues: []interface{}{
"",
},
},
{
path: "spec.containers[*].securityContext.seLinuxOptions.user",
allowedValues: []interface{}{
"",
},
},
{
path: "spec.initContainers[*].securityContext.seLinuxOptions.user",
allowedValues: []interface{}{
"",
},
},
{
path: "spec.ephemeralContainers[*].seLinuxOptions.user",
allowedValues: []interface{}{
"",
},
},
// role
{
path: "spec.securityContext.seLinuxOptions.role",
allowedValues: []interface{}{
"",
},
},
{
path: "spec.containers[*].securityContext.seLinuxOptions.role",
allowedValues: []interface{}{
"",
},
},
{
path: "spec.initContainers[*].securityContext.seLinuxOptions.role",
allowedValues: []interface{}{
"",
},
},
{
path: "spec.ephemeralContainers[*].seLinuxOptions.role",
allowedValues: []interface{}{
"",
},
},
},
"seccompProfile_baseline": {
{
path: "spec.securityContext.seccompProfile.type",
allowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
{
path: "spec.containers[*].securityContext.seccompProfile.type",
allowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
{
path: "spec.initContainers[*].securityContext.seccompProfile.type",
allowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.seccompProfile.type",
allowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
},
"seccompProfile_restricted": {
{
path: "spec.securityContext.seccompProfile.type",
allowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
{
path: "spec.containers[*].securityContext.seccompProfile.type",
allowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
{
path: "spec.initContainers[*].securityContext.seccompProfile.type",
allowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.seccompProfile.type",
allowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
},
// Pod-level controls
"sysctls": {
{
path: "spec.securityContext.sysctls[*].name",
allowedValues: []interface{}{
"kernel.shm_rmid_forced",
"net.ipv4.ip_local_port_range",
"net.ipv4.tcp_syncookies",
"net.ipv4.ping_group_range",
"net.ipv4.ip_unprivileged_port_start",
},
},
},
"hostPathVolumes": {
{
path: "spec.volumes[*].hostPath",
allowedValues: []interface{}{
nil,
},
},
},
"hostNamespaces": {
{
path: "spec.hostNetwork",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.hostPID",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.hostIPC",
allowedValues: []interface{}{
false,
nil,
},
},
},
// metadata-level controls
"appArmorProfile": {
{
path: "metadata.annotations",
allowedValues: []interface{}{
nil,
"",
"runtime/default",
"localhost/*",
},
},
},
// === Restricted
"restrictedVolumes": {
{
path: "spec.volumes[*]",
allowedValues: []interface{}{
"spec.volumes[*].configMap",
"spec.volumes[*].downwardAPI",
"spec.volumes[*].emptyDir",
"spec.volumes[*].projected",
"spec.volumes[*].secret",
"spec.volumes[*].csi",
"spec.volumes[*].persistentVolumeClaim",
"spec.volumes[*].ephemeral",
},
},
},
"runAsNonRoot": {
{
path: "spec.containers[*].securityContext.runAsNonRoot",
allowedValues: []interface{}{
true,
nil,
},
},
{
path: "spec.initContainers[*].securityContext.runAsNonRoot",
allowedValues: []interface{}{
false,
nil,
},
},
{
path: "spec.ephemeralContainers[*].securityContext.runAsNonRoot",
allowedValues: []interface{}{
false,
nil,
},
},
},
"runAsUser": {
{
path: "spec.securityContext.runAsUser",
allowedValues: []interface{}{
"",
nil,
},
},
{
path: "spec.containers[*].securityContext.runAsUser",
allowedValues: []interface{}{
"",
nil,
},
},
{
path: "spec.initContainers[*].securityContext.runAsUser",
allowedValues: []interface{}{
"",
nil,
},
},
{
path: "spec.ephemeralContainers[*].securityContext.runAsUser",
allowedValues: []interface{}{
"",
nil,
},
},
},
"allowPrivilegeEscalation": {
{
path: "spec.containers[*].securityContext.allowPrivilegeEscalation",
allowedValues: []interface{}{
false,
},
},
{
path: "spec.initContainers[*].securityContext.allowPrivilegeEscalation",
allowedValues: []interface{}{
false,
},
},
{
path: "spec.ephemeralContainers[*].securityContext.allowPrivilegeEscalation",
allowedValues: []interface{}{
false,
},
},
},
"capabilities_restricted": {
{
path: "spec.containers[*].securityContext.capabilities.drop",
allowedValues: []interface{}{
"ALL",
},
},
{
path: "spec.initContainers[*].securityContext.capabilities.drop",
allowedValues: []interface{}{
"ALL",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.capabilities.drop",
allowedValues: []interface{}{
"ALL",
},
},
{
path: "spec.containers[*].securityContext.capabilities.add",
allowedValues: []interface{}{
nil,
"NET_BIND_SERVICE",
},
},
{
path: "spec.initContainers[*].securityContext.capabilities.add",
allowedValues: []interface{}{
nil,
"NET_BIND_SERVICE",
},
},
{
path: "spec.ephemeralContainers[*].securityContext.capabilities.add",
allowedValues: []interface{}{
nil,
"NET_BIND_SERVICE",
},
},
},
}

View file

@ -1,69 +0,0 @@
package pss
import (
"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"
)
// 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
}
matchingImages := exclude.Images
matching = &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: pod.GetName(),
Namespace: pod.GetNamespace(),
},
}
for _, container := range pod.Spec.Containers {
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
matching.Spec.Containers = append(matching.Spec.Containers, container)
}
}
for _, container := range pod.Spec.InitContainers {
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
matching.Spec.InitContainers = append(matching.Spec.InitContainers, container)
}
}
for _, container := range pod.Spec.EphemeralContainers {
if utils.ContainsWildcardPatterns(matchingImages, container.Image) {
matching.Spec.EphemeralContainers = append(matching.Spec.EphemeralContainers, container)
}
}
return nil, matching
}
// Get restrictedFields from Check.ID
func getRestrictedFields(check policy.Check) []restrictedField {
for _, control := range PSS_controls_to_check_id {
for _, checkID := range control {
if check.ID == checkID {
return PSS_controls[checkID]
}
}
}
return nil
}
func FormatChecksPrint(checks []pssCheckResult) string {
var str string
for _, check := range checks {
str += fmt.Sprintf("(%+v)\n", check.checkResult)
}
return str
}

626
pkg/pss/utils/mapping.go Normal file
View file

@ -0,0 +1,626 @@
package utils
var PSS_baseline_control_names = []string{
"HostProcess",
"Host Namespaces",
"Privileged Containers",
"Capabilities",
"HostPath Volumes",
"Host Ports",
"AppArmor",
"SELinux",
"/proc Mount Type",
"Seccomp",
"Sysctls",
}
var PSS_restricted_control_names = []string{
"Volume Types",
"Privilege Escalation",
"Running as Non-root",
"Running as Non-root user",
"Seccomp",
"Capabilities",
}
var PSS_pod_level_control = []string{
"Host Namespaces",
"HostPath Volumes",
"Sysctls",
"AppArmor",
"Volume Types",
}
var PSS_container_level_control = []string{
"Capabilities",
"Privileged Containers",
"Host Ports",
"/proc Mount Type",
"Privilege Escalation",
}
// Translate PSS control to CheckResult.ID so that we can use PSS control in Kyverno policy
// For PSS controls see: https://kubernetes.io/docs/concepts/security/pod-security-standards/
// 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",
},
// === Baseline
// Container-level controls
"Privileged Containers": {
"privileged",
},
"Host Ports": {
"hostPorts",
},
"/proc Mount Type": {
"procMount",
},
// Container and pod-level controls
"HostProcess": {
"windowsHostProcess",
},
"SELinux": {
"seLinuxOptions",
},
// Pod-level controls
"Host Namespaces": {
"hostNamespaces",
},
"HostPath Volumes": {
"hostPathVolumes",
},
"Sysctls": {
"sysctls",
},
// Metadata-level control
"AppArmor": {
"appArmorProfile",
},
// === Restricted
// Container-level control
"Privilege Escalation": {
"allowPrivilegeEscalation",
},
// Container and pod-level controls
"Running as Non-root": {
"runAsNonRoot",
},
"Running as Non-root user": {
"runAsUser",
},
// Pod-level controls
"Volume Types": {
"restrictedVolumes",
},
}
var PSS_controls = map[string][]RestrictedField{
// Control name as key, same as ID field in CheckResult
// === Baseline
// Container-level controls
"privileged": {
{
// type:
// - container-level
// - pod-container-level
// - pod level
Path: "spec.containers[*].securityContext.privileged",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.initContainers[*].securityContext.privileged",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.privileged",
AllowedValues: []interface{}{
false,
nil,
},
},
},
"hostPorts": {
{
Path: "spec.containers[*].ports[*].hostPort",
AllowedValues: []interface{}{
false,
0,
},
},
{
Path: "spec.initContainers[*].ports[*].hostPort",
AllowedValues: []interface{}{
false,
0,
},
},
{
Path: "spec.ephemeralContainers[*].ports[*].hostPort",
AllowedValues: []interface{}{
false,
0,
},
},
},
"procMount": {
{
Path: "spec.containers[*].securityContext.procMount",
AllowedValues: []interface{}{
nil,
"Default",
},
},
{
Path: "spec.initContainers[*].securityContext.procMount",
AllowedValues: []interface{}{
nil,
"Default",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.procMount",
AllowedValues: []interface{}{
nil,
"Default",
},
},
},
"capabilities_baseline": {
{
Path: "spec.containers[*].securityContext.capabilities.add",
AllowedValues: []interface{}{
nil,
"AUDIT_WRITE",
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"MKNOD",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
},
},
{
Path: "spec.initContainers[*].securityContext.capabilities.add",
AllowedValues: []interface{}{
nil,
"AUDIT_WRITE",
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"MKNOD",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.capabilities.add",
AllowedValues: []interface{}{
nil,
"AUDIT_WRITE",
"CHOWN",
"DAC_OVERRIDE",
"FOWNER",
"FSETID",
"KILL",
"MKNOD",
"NET_BIND_SERVICE",
"SETFCAP",
"SETGID",
"SETPCAP",
"SETUID",
"SYS_CHROOT",
},
},
},
// Container and pod-level controls
"windowsHostProcess": {
{
Path: "spec.securityContext.windowsOptions.hostProcess",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.containers[*].securityContext.windowsOptions.hostProcess",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.initContainers[*].securityContext.windowsOptions.hostProcess",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.windowsOptions.hostProcess",
AllowedValues: []interface{}{
false,
nil,
},
},
},
"seLinuxOptions": {
// type
{
Path: "spec.securityContext.seLinuxOptions.type",
AllowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
{
Path: "spec.containers[*].securityContext.seLinuxOptions.type",
AllowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
{
Path: "spec.initContainers[*].securityContext.seLinuxOptions.type",
AllowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.seLinuxOptions.type",
AllowedValues: []interface{}{
"",
"container_t",
"container_init_t",
"container_kvm_t",
},
},
// user
{
Path: "spec.securityContext.seLinuxOptions.user",
AllowedValues: []interface{}{
"",
},
},
{
Path: "spec.containers[*].securityContext.seLinuxOptions.user",
AllowedValues: []interface{}{
"",
},
},
{
Path: "spec.initContainers[*].securityContext.seLinuxOptions.user",
AllowedValues: []interface{}{
"",
},
},
{
Path: "spec.ephemeralContainers[*].seLinuxOptions.user",
AllowedValues: []interface{}{
"",
},
},
// role
{
Path: "spec.securityContext.seLinuxOptions.role",
AllowedValues: []interface{}{
"",
},
},
{
Path: "spec.containers[*].securityContext.seLinuxOptions.role",
AllowedValues: []interface{}{
"",
},
},
{
Path: "spec.initContainers[*].securityContext.seLinuxOptions.role",
AllowedValues: []interface{}{
"",
},
},
{
Path: "spec.ephemeralContainers[*].seLinuxOptions.role",
AllowedValues: []interface{}{
"",
},
},
},
"seccompProfile_baseline": {
{
Path: "spec.securityContext.seccompProfile.type",
AllowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
{
Path: "spec.containers[*].securityContext.seccompProfile.type",
AllowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
{
Path: "spec.initContainers[*].securityContext.seccompProfile.type",
AllowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.seccompProfile.type",
AllowedValues: []interface{}{
nil,
"RuntimeDefault",
"Localhost",
},
},
},
"seccompProfile_restricted": {
{
Path: "spec.securityContext.seccompProfile.type",
AllowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
{
Path: "spec.containers[*].securityContext.seccompProfile.type",
AllowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
{
Path: "spec.initContainers[*].securityContext.seccompProfile.type",
AllowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.seccompProfile.type",
AllowedValues: []interface{}{
"RuntimeDefault",
"Localhost",
},
},
},
// Pod-level controls
"sysctls": {
{
Path: "spec.securityContext.sysctls[*].name",
AllowedValues: []interface{}{
"kernel.shm_rmid_forced",
"net.ipv4.ip_local_port_range",
"net.ipv4.tcp_syncookies",
"net.ipv4.ping_group_range",
"net.ipv4.ip_unprivileged_port_start",
},
},
},
"hostPathVolumes": {
{
Path: "spec.volumes[*].hostPath",
AllowedValues: []interface{}{
nil,
},
},
},
"hostNamespaces": {
{
Path: "spec.hostNetwork",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.hostPID",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.hostIPC",
AllowedValues: []interface{}{
false,
nil,
},
},
},
// metadata-level controls
"appArmorProfile": {
{
Path: "metadata.annotations",
AllowedValues: []interface{}{
nil,
"",
"runtime/default",
"localhost/*",
},
},
},
// === Restricted
"restrictedVolumes": {
{
Path: "spec.volumes[*]",
AllowedValues: []interface{}{
"spec.volumes[*].configMap",
"spec.volumes[*].downwardAPI",
"spec.volumes[*].emptyDir",
"spec.volumes[*].projected",
"spec.volumes[*].secret",
"spec.volumes[*].csi",
"spec.volumes[*].persistentVolumeClaim",
"spec.volumes[*].ephemeral",
},
},
},
"runAsNonRoot": {
{
Path: "spec.containers[*].securityContext.runAsNonRoot",
AllowedValues: []interface{}{
true,
nil,
},
},
{
Path: "spec.initContainers[*].securityContext.runAsNonRoot",
AllowedValues: []interface{}{
false,
nil,
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.runAsNonRoot",
AllowedValues: []interface{}{
false,
nil,
},
},
},
"runAsUser": {
{
Path: "spec.securityContext.runAsUser",
AllowedValues: []interface{}{
"",
nil,
},
},
{
Path: "spec.containers[*].securityContext.runAsUser",
AllowedValues: []interface{}{
"",
nil,
},
},
{
Path: "spec.initContainers[*].securityContext.runAsUser",
AllowedValues: []interface{}{
"",
nil,
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.runAsUser",
AllowedValues: []interface{}{
"",
nil,
},
},
},
"allowPrivilegeEscalation": {
{
Path: "spec.containers[*].securityContext.allowPrivilegeEscalation",
AllowedValues: []interface{}{
false,
},
},
{
Path: "spec.initContainers[*].securityContext.allowPrivilegeEscalation",
AllowedValues: []interface{}{
false,
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.allowPrivilegeEscalation",
AllowedValues: []interface{}{
false,
},
},
},
"capabilities_restricted": {
{
Path: "spec.containers[*].securityContext.capabilities.drop",
AllowedValues: []interface{}{
"ALL",
},
},
{
Path: "spec.initContainers[*].securityContext.capabilities.drop",
AllowedValues: []interface{}{
"ALL",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.capabilities.drop",
AllowedValues: []interface{}{
"ALL",
},
},
{
Path: "spec.containers[*].securityContext.capabilities.add",
AllowedValues: []interface{}{
nil,
"NET_BIND_SERVICE",
},
},
{
Path: "spec.initContainers[*].securityContext.capabilities.add",
AllowedValues: []interface{}{
nil,
"NET_BIND_SERVICE",
},
},
{
Path: "spec.ephemeralContainers[*].securityContext.capabilities.add",
AllowedValues: []interface{}{
nil,
"NET_BIND_SERVICE",
},
},
},
}

16
pkg/pss/utils/types.go Normal file
View file

@ -0,0 +1,16 @@
package utils
import (
"k8s.io/pod-security-admission/policy"
)
type RestrictedField struct {
Path string
AllowedValues []interface{}
}
type PSSCheckResult struct {
ID string
CheckResult policy.CheckResult
RestrictedFields []RestrictedField
}