mirror of
https://github.com/kyverno/kyverno.git
synced 2024-12-15 17:51:20 +00:00
1b9a2fca21
* init commit for pss Signed-off-by: ShutingZhao <shuting@nirmata.com> * add test for Volume Type control * add test for App Armor control except ExemptProfile. Fix PSS profile check in EvaluatePSS() * remove unused code, still a JMESPATH problem with app armor ExemptProfile() * test for Host Process / Host Namespaces controls * test for Privileged containers controls * test for HostPathVolume control * test for HostPorts control * test for HostPorts control * test for SELinux control * test for Proc mount type control * Set to baseline * test for Seccomp control * test for Sysctl control * test for Privilege escalation control * test for Run as non root control * test for Restricted Seccomp control * Add problems to address * add solutions to problems * Add validate rule for PSA * api.Version --> string. latest by default * Exclude all values for a restrictedField * add tests for kyverno engine * code to be used to match kyverno rule's namespace * Refacto pkg/pss * fix multiple problems: not matching containers, add contains methods, select the right container when we have the same exclude.RestrictedField for multiple containers: * EvaluatePod * Use EvaluatePod in kyverno engine * Set pod instead of container in context to use full Jmespath. e.g.: securityContext.capabilities.add --> spec.containers[*].securityContext.capabilities.add * Check if PSSCheckResult matched at least one exclude value * add tests for engine * fix engine validation test * config * update go.mod and go.sum * crds * Check validate value: add PodSecurity * exclude all restrictedFields when we only specify the controlName * ExemptProfile(): check if exclud.RestrictedField matches at least one restrictedField.path * handle containers, initContainers, ephemeralContainers when we only specify the controlName (all restrictedFields are excluded) * refacto pks/pss/evaluate.go and add pkg/engine/validation_test.go * add all controls with containers in restrictedFields as comments * add tests for capabilities and privileged containers and fix some errors * add tests for host ports control * add tests for proc mount control * add tests for privilege escalation control * add tests for capabilities control * remove comments * new algo * refacto algo, working. Add test for hostProcess control * remove unused code * fix getPodWithNotMatchingContainers(), add tests for host namespaces control * refacto ExemptProfile() * get values for a specific container. add test for SELinuxOptions control * fix allowedValues for SELinuxOptions * add tests for seccompProfile_baseline control * refacto checkContainers(), add test for seccomp control * add test for running as non root control * add some tests for runAsUser control, have to update current PSA version * add sysctls control * add allowed values for restrictedVolumes control * add some tests for appArmor, volume types controls * add tests for volume types control * add tests for hostPath volume control * finish merge conflicts and add tests for runAsUser * update charts and crds * exclude.images optional * change volume types control exclude values * add appAmor control * fix: did not match any exclude value for pod-level restrictedFields * create autogen for validate.PodSecurity * clean code, remove logs * fix sonatype lift errors * fix sonatype lift errors: duplication * fix crash in pkg/policy/validate/ tests and unmarshall errors for pkg/engine tests * beginning of autogen implement for validate.exclude * Autogen for validation.PodSecurity * working autogen with simple tests * change validate.PodSecurity failure response format * make codegen * fix lint errors, remove debug prints * fix tags * fix tags * fix crash when deleting pods matching validate.podSecurity rule. Only check validatePodSecurity() when it's not a delete request * Changes requested * Changes requested 2 * Changes requested 3 * Changes requested 4 * Changes requested and make codegen * fix host namespaces control * fix lint * fix codegen error * update docs/crd/v1/index.html Signed-off-by: ShutingZhao <shuting@nirmata.com> * fix path Signed-off-by: ShutingZhao <shuting@nirmata.com> * update crd schema Signed-off-by: ShutingZhao <shuting@nirmata.com> * update charts/kyverno/templates/crds.yaml Signed-off-by: ShutingZhao <shuting@nirmata.com> Signed-off-by: ShutingZhao <shuting@nirmata.com> Co-authored-by: ShutingZhao <shuting@nirmata.com>
600 lines
11 KiB
Go
600 lines
11 KiB
Go
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
|
|
"Capabilities": {
|
|
"capabilities_baseline",
|
|
"capabilities_restricted",
|
|
},
|
|
"Seccomp": {
|
|
"seccompProfile_baseline",
|
|
"seccompProfile_restricted",
|
|
},
|
|
|
|
// === Baseline
|
|
// Container-level controls
|
|
"Privileged Containers": {
|
|
"privileged",
|
|
},
|
|
"Host Ports": {
|
|
"hostPorts",
|
|
},
|
|
"/proc Mount Type": {
|
|
"procMount",
|
|
},
|
|
"procMount": {
|
|
"hostPorts",
|
|
},
|
|
|
|
// 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 and pod-level controls
|
|
"Privilege Escalation": {
|
|
"allowPrivilegeEscalation",
|
|
},
|
|
"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",
|
|
},
|
|
},
|
|
},
|
|
}
|