mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +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:
parent
a1182859ad
commit
1d83e86c12
14 changed files with 1664 additions and 681 deletions
|
@ -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.
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
|
@ -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
626
pkg/pss/utils/mapping.go
Normal 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
16
pkg/pss/utils/types.go
Normal 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
|
||||
}
|
Loading…
Reference in a new issue