From 0e61fb4015c1afc97d089aec0ae2106cda9ea517 Mon Sep 17 00:00:00 2001 From: Morgan Hoffman <hoffmanm@vt.edu> Date: Mon, 25 Mar 2024 20:14:33 +0000 Subject: [PATCH] Revert "Merge branch 'bbooker-platform-2365' into 'master'" This reverts merge request !66 --- Chart.yaml | 2 +- README.md | 2 + rego/pss_apparmor/policy.rego | 111 +++ rego/pss_apparmor/policy_test.rego | 374 ++++++++++ rego/pss_host_namespaces/policy.rego | 139 ++++ rego/pss_host_namespaces/policy_test.rego | 421 +++++++++++ rego/pss_hostpath_volumes/policy.rego | 109 +++ rego/pss_hostpath_volumes/policy_test.rego | 239 +++++++ rego/pss_hostports/policy.rego | 108 +++ rego/pss_hostports/policy_test.rego | 345 +++++++++ rego/pss_pod_capabilities/policy.rego | 111 +++ rego/pss_pod_capabilities/policy_test.rego | 585 +++++++++++++++ rego/pss_privileged_pods/policy.rego | 106 +++ rego/pss_privileged_pods/policy_test.rego | 224 ++++++ rego/pss_procmounts/policy.rego | 108 +++ rego/pss_procmounts/policy_test.rego | 454 ++++++++++++ rego/pss_seccomp/policy.rego | 121 ++++ rego/pss_seccomp/policy_test.rego | 671 ++++++++++++++++++ rego/pss_selinux/policy.rego | 142 ++++ rego/pss_selinux/policy_test.rego | 663 +++++++++++++++++ rego/pss_sysctl_options/policy.rego | 109 +++ rego/pss_sysctl_options/policy_test.rego | 268 +++++++ .../constraint_template_pss_apparmor.yaml | 13 + ...onstraint_template_pss_host_namespace.yaml | 13 + ...nstraint_template_pss_hostpath_volume.yaml | 13 + .../constraint_template_pss_hostport.yaml | 13 + ...straint_template_pss_pod_capabilities.yaml | 13 + .../constraint_template_pss_privileged.yaml | 13 + .../constraint_template_pss_procmount.yaml | 13 + .../constraint_template_pss_seccomp.yaml | 13 + .../constraint_template_pss_selinux.yaml | 13 + ...onstraint_template_pss_sysctl_options.yaml | 13 + 32 files changed, 5541 insertions(+), 1 deletion(-) create mode 100644 rego/pss_apparmor/policy.rego create mode 100644 rego/pss_apparmor/policy_test.rego create mode 100644 rego/pss_host_namespaces/policy.rego create mode 100644 rego/pss_host_namespaces/policy_test.rego create mode 100644 rego/pss_hostpath_volumes/policy.rego create mode 100644 rego/pss_hostpath_volumes/policy_test.rego create mode 100644 rego/pss_hostports/policy.rego create mode 100644 rego/pss_hostports/policy_test.rego create mode 100644 rego/pss_pod_capabilities/policy.rego create mode 100644 rego/pss_pod_capabilities/policy_test.rego create mode 100644 rego/pss_privileged_pods/policy.rego create mode 100644 rego/pss_privileged_pods/policy_test.rego create mode 100644 rego/pss_procmounts/policy.rego create mode 100644 rego/pss_procmounts/policy_test.rego create mode 100644 rego/pss_seccomp/policy.rego create mode 100644 rego/pss_seccomp/policy_test.rego create mode 100644 rego/pss_selinux/policy.rego create mode 100644 rego/pss_selinux/policy_test.rego create mode 100644 rego/pss_sysctl_options/policy.rego create mode 100644 rego/pss_sysctl_options/policy_test.rego create mode 100644 templates/constraint_template_pss_apparmor.yaml create mode 100644 templates/constraint_template_pss_host_namespace.yaml create mode 100644 templates/constraint_template_pss_hostpath_volume.yaml create mode 100644 templates/constraint_template_pss_hostport.yaml create mode 100644 templates/constraint_template_pss_pod_capabilities.yaml create mode 100644 templates/constraint_template_pss_privileged.yaml create mode 100644 templates/constraint_template_pss_procmount.yaml create mode 100644 templates/constraint_template_pss_seccomp.yaml create mode 100644 templates/constraint_template_pss_selinux.yaml create mode 100644 templates/constraint_template_pss_sysctl_options.yaml diff --git a/Chart.yaml b/Chart.yaml index b33aff3..0a01ccf 100644 --- a/Chart.yaml +++ b/Chart.yaml @@ -1,4 +1,4 @@ apiVersion: v2 name: constraint-templates -version: 2.0.0 +version: 1.5.3 appVersion: 1.0.0 diff --git a/README.md b/README.md index 41fa32f..ffb37cb 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,8 @@ The following policies are defined within this chart: - `BlockNodePort` - prevents NodePort Services from being defined - `ContainerResourceQuotas` - requires CPU/memory definitions for resource requests and limits - `FluxTenant` - ensures the `serviceAccountName` and `targetNamespace` fields are specified and that the `targetNamespace` matches the namespace on Kustomization and HelmRelease objects, preventing namespace escapes +- `Pss*` - each policy implements one of the policies listed in the [Pod Security Standards](https://kubernetes.io/docs/concepts/security/pod-security-standards/) + ## Development diff --git a/rego/pss_apparmor/policy.rego b/rego/pss_apparmor/policy.rego new file mode 100644 index 0000000..9d40672 --- /dev/null +++ b/rego/pss_apparmor/policy.rego @@ -0,0 +1,111 @@ +package pss_apparmor + +apparmor_keys[containerName] = key { + containerName := containers[_].name + key := sprintf("%s/%s", ["container.apparmor.security.beta.kubernetes.io", containerName]) +} + +custom_apparmor_containers[containerName] { + key := apparmor_keys[containerName] + annotation := annotations[_] + val = annotation[key] + val != "runtime/default" + not startswith(val, "localhost/") +} + +violation[msg] { + failedContainer := custom_apparmor_containers[_] + + msg := format(sprintf("Container '%s' of %s '%s' should specify an AppArmor profile", [failedContainer, kind, name])) +} + +################### LIBRARY ################### + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +annotations[annotation] { + pods[pod] + annotation = pod.metadata.annotations +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} diff --git a/rego/pss_apparmor/policy_test.rego b/rego/pss_apparmor/policy_test.rego new file mode 100644 index 0000000..e199012 --- /dev/null +++ b/rego/pss_apparmor/policy_test.rego @@ -0,0 +1,374 @@ +package pss_apparmor + +################Helpers############################## + +review_pod(annotations) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } +} + +review_deployment(annotations) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "metadata": { + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } + } + } +} + +review_daemonset(annotations) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "metadata": { + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } + } + } +} + +review_replicaset(annotations) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "metadata": { + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } + } + } +} + +review_statefulset(annotations) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "metadata": { + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } + } + } +} + +review_job(annotations) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "metadata": { + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } + } + } +} + +review_cronjob(annotations) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "metadata": { + "annotations": annotations, + }, + "spec": { + "containers": [ {"name" : "hello"}, ], + }, + } + } + } + } + } + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} + +################Container Tests###################### + +test_not_allowed_apparmor_profile_container_on_pod { + input := input_obj(review_pod({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_pod({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_pod({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_pod { + input := input_obj(review_pod({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_pod { + input := input_obj(review_pod(null)) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_apparmor_profile_container_on_deployment { + input := input_obj(review_deployment({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_deployment({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_deployment({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_deployment { + input := input_obj(review_deployment({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_deployment { + input := input_obj(review_deployment(null)) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_apparmor_profile_container_on_daemonset { + input := input_obj(review_daemonset({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_daemonset({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_daemonset({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_daemonset { + input := input_obj(review_daemonset({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_daemonset { + input := input_obj(review_daemonset(null)) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_apparmor_profile_container_on_replicaset { + input := input_obj(review_replicaset({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_replicaset({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_replicaset({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_replicaset { + input := input_obj(review_replicaset({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_replicaset { + input := input_obj(review_replicaset(null)) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_apparmor_profile_container_on_statefulset { + input := input_obj(review_statefulset({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_statefulset({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_statefulset({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_statefulset { + input := input_obj(review_statefulset({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_statefulset { + input := input_obj(review_statefulset(null)) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_apparmor_profile_container_on_job { + input := input_obj(review_job({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_job({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_job({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_job { + input := input_obj(review_job({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_job { + input := input_obj(review_job(null)) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_apparmor_profile_container_on_cronjob { + input := input_obj(review_cronjob({"container.apparmor.security.beta.kubernetes.io/hello":"custom"})) + results := violation with input as input + count(results) == 1 +} + +test_allowed_when_apparmor_profile_specified_on_nonexisting_container_on_pod { + input := input_obj(review_cronjob({"container.apparmor.security.beta.kubernetes.io/something-else":"custom"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_localhost_apparmor_profile_container_on_pod { + input := input_obj(review_cronjob({"container.apparmor.security.beta.kubernetes.io/hello":"localhost/test"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_container_on_cronjob { + input := input_obj(review_cronjob({"container.apparmor.security.beta.kubernetes.io/hello":"runtime/default"})) + results := violation with input as input + count(results) == 0 +} + +test_allowed_apparmor_profile_nill_container_on_cronjob { + input := input_obj(review_cronjob(null)) + results := violation with input as input + count(results) == 0 +} \ No newline at end of file diff --git a/rego/pss_host_namespaces/policy.rego b/rego/pss_host_namespaces/policy.rego new file mode 100644 index 0000000..2d6854f --- /dev/null +++ b/rego/pss_host_namespaces/policy.rego @@ -0,0 +1,139 @@ +package pss_hostnamespaces + + +violation[msg] { + failHostNetwork + + msg := format(sprintf("%s '%s' should not set 'spec.template.spec.hostNetwork' to true", [kind, name])) +} + +violation[msg] { + failHostIPC + + msg := format(sprintf("%s '%s' should not set 'spec.template.spec.hostIPC' to true", [kind, name])) +} + +violation[msg] { + failHostPID + + msg := format(sprintf("%s '%s' should not set 'spec.template.spec.hostPID' to true", [kind, name])) +} + +# failHostNetwork is true if spec.hostNetwork is set to true (on all controllers) +failHostNetwork { + host_networks[_] == true +} + +# failHostIPC is true if spec.hostIPC is set to true (on all resources) +failHostIPC { + host_ipcs[_] == true +} + +# failHostPID is true if spec.hostPID is set to true (on all controllers) +failHostPID { + host_pids[_] == true +} + + + +################### LIBRARY ################### + + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} + +host_networks[host_network] { + pods[pod] + host_network = pod.spec.hostNetwork +} + +host_ipcs[host_ipc] { + pods[pod] + host_ipc = pod.spec.hostIPC +} + +host_pids[host_pid] { + pods[pod] + host_pid = pod.spec.hostPID +} diff --git a/rego/pss_host_namespaces/policy_test.rego b/rego/pss_host_namespaces/policy_test.rego new file mode 100644 index 0000000..3b89e8c --- /dev/null +++ b/rego/pss_host_namespaces/policy_test.rego @@ -0,0 +1,421 @@ +package pss_hostnamespaces + +test_host_network_on_pod { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_pod { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_pod { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_pod { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_pod { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_pod { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_network_on_deployment { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_deployment { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_deployment { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_deployment { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_deployment { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_deployment { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_network_on_daemonset { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_daemonset { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_daemonset { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_daemonset { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_daemonset { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_daemonset { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_network_on_replicaset { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_replicaset { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_replicaset { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_replicaset { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_replicaset { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_replicaset { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_network_on_statefulset { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_statefulset { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_statefulset { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_statefulset { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_statefulset { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_statefulset { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_network_on_job { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_job { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_job { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_job { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_job { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_job { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_network_on_cronjob { + pod_spec := {"spec":{"hostNetwork":true}} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_network_on_cronjob { + pod_spec := {"spec":{"hostNetwork":false}} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_ipc_on_cronjob { + pod_spec := {"spec":{"hostIPC":true}} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_ipc_on_cronjob { + pod_spec := {"spec":{"hostIPC":false}} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_host_pid_on_cronjob { + pod_spec := {"spec":{"hostPID":true}} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_host_pid_on_cronjob { + pod_spec := {"spec":{"hostPID":false}} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +pod_definition(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec.spec + } + } +} + +deployment_definition(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec.spec + } + } + } + } +} + +daemonset_definition(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec.spec + } + } + } + } +} + +replicaset_definition(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec.spec + } + } + } + } +} + +statefulset_definition(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec.spec + } + } + } + } +} + +job_definition(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec.spec + } + } + } + } +} + +cronjob_definition(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec.spec + } + } + } + } + } + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_hostpath_volumes/policy.rego b/rego/pss_hostpath_volumes/policy.rego new file mode 100644 index 0000000..75e9ec2 --- /dev/null +++ b/rego/pss_hostpath_volumes/policy.rego @@ -0,0 +1,109 @@ +package pss_hostpathvolumes + + +violation[msg] { + failHostPathVolume + + msg := format(sprintf("%s '%s' should not set 'spec.template.volumes.hostPath'", [kind, name])) +} + +failHostPathVolume { + allVolumes := volumes + has_key(allVolumes[_], "hostPath") +} + + +################### LIBRARY ################### + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers", "ephemeralContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +volumes[volume] { + pods[pod] + volume = pod.spec.volumes[_] +} + +has_field(obj, field) { + obj[field] +} + +has_key(x, k) { + _ = x[k] +} diff --git a/rego/pss_hostpath_volumes/policy_test.rego b/rego/pss_hostpath_volumes/policy_test.rego new file mode 100644 index 0000000..b3e47b4 --- /dev/null +++ b/rego/pss_hostpath_volumes/policy_test.rego @@ -0,0 +1,239 @@ +package pss_hostpathvolumes + +test_hostpath_on_pod { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_pod { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":"{}"}]} + input := input_obj(pod_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_hostpath_on_deployment { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_deployment { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}}]} + input := input_obj(deployment_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_hostpath_on_daemonset { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_daemonset { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}}]} + input := input_obj(daemonset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_hostpath_on_replicaset { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_replicaset { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}}]} + input := input_obj(replicaset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_hostpath_on_statefulset { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_statefulset { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}}]} + input := input_obj(statefulset_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_hostpath_on_job { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_job { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}}]} + input := input_obj(job_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +test_hostpath_on_cronjob { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}},{"name":"test-volume","hostPath":{"path":"/data","type":"Directory"}}]} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 1 +} + +test_no_hostpath_on_cronjob { + pod_spec := {"volumes":[{"name":"cache-volume","emptyDir":{}}]} + input := input_obj(cronjob_definition(pod_spec)) + results := violation with input as input + count(results) == 0 +} + +pod_definition(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": { + "volumes": pod_spec.volumes + } + } + } +} + +deployment_definition(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": { + "volumes": pod_spec.volumes + } + } + } + } + } +} + +daemonset_definition(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": { + "volumes": pod_spec.volumes + } + } + } + } + } +} + +replicaset_definition(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": { + "volumes": pod_spec.volumes + } + } + } + } + } +} + +statefulset_definition(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": { + "volumes": pod_spec.volumes + } + } + } + } + } +} + +job_definition(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": { + "volumes": pod_spec.volumes + } + } + } + } + } +} + +cronjob_definition(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": { + "volumes": pod_spec.volumes + } + } + } + } + } + } + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_hostports/policy.rego b/rego/pss_hostports/policy.rego new file mode 100644 index 0000000..c5399d3 --- /dev/null +++ b/rego/pss_hostports/policy.rego @@ -0,0 +1,108 @@ +package pss_hostports + + +violation[msg] { + failHostPorts := getContainersWithHostPorts + count(failHostPorts) > 0 + + msg := format(sprintf("Container '%s' of %s '%s' should not set host ports", [failHostPorts[_], kind, name])) + +} + +getContainersWithHostPorts[container] { + allContainers := containers[_] + hostport_present := allContainers.ports[_].hostPort + container := allContainers.name +} + + + + + + +################### LIBRARY ################### + + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} diff --git a/rego/pss_hostports/policy_test.rego b/rego/pss_hostports/policy_test.rego new file mode 100644 index 0000000..c9f47a5 --- /dev/null +++ b/rego/pss_hostports/policy_test.rego @@ -0,0 +1,345 @@ +package pss_hostports + +test_container_with_hostport_on_pod { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_pod(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_pod { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_pod(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_hostport_on_deployment { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_deployment(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_deployment { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_deployment(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_hostport_on_daemonset { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_daemonset(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_daemonset { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_daemonset(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_hostport_on_replicaset { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_replicaset(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_replicaset { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_replicaset(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_hostport_on_statefulset { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_statefulset(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_statefulset { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_statefulset(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_hostport_on_job { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_job(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_job { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_job(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_hostport_on_cronjob { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_cronjob(pod_spec(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_hostport_on_cronjob { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_cronjob(pod_spec(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_pod { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_pod(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_pod { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_pod(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_deployment { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_deployment(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_deployment { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_deployment(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_daemonset { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_daemonset(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_daemonset { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_daemonset(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_replicaset { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_replicaset(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_replicaset { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_replicaset(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_statefulset { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_statefulset(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_statefulset { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_statefulset(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_job { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_job(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_job { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_job(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_hostport_on_cronjob { + container_ports := {"ports":[{"containerPort": 80, "hostPort": 80}]} + input := input_obj(review_cronjob(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_hostport_on_cronjob { + container_ports := {"ports":[{"containerPort": 80}]} + input := input_obj(review_cronjob(pod_spec_init_containers(container_ports))) + results := violation with input as input + count(results) == 0 +} + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(container_ports) = out { + out = { + "containers": [ + { + "name": "container1", + "ports": container_ports.ports + } + ] + } +} + +pod_spec_init_containers(container_ports) = out { + out = { + "initContainers": [ + { + "name": "container1", + "ports": container_ports.ports + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_pod_capabilities/policy.rego b/rego/pss_pod_capabilities/policy.rego new file mode 100644 index 0000000..33c21c0 --- /dev/null +++ b/rego/pss_pod_capabilities/policy.rego @@ -0,0 +1,111 @@ +package pss_podcapabilities + + +violation[msg] { + failedContainers := getContainersWithDisallowedCaps + count(failedContainers) > 0 + + msg := format(sprintf("Container '%s' of %s '%s' should not set 'securityContext.capabilities.add'%s", [failedContainers[_], kind, name, caps_msg])) +} + +allowed_caps := {"AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"} + +getContainersWithDisallowedCaps[container] { + allContainers := containers[_] + set_caps := {cap | cap := allContainers.securityContext.capabilities.add[_]} + caps_not_allowed := set_caps - allowed_caps + count(caps_not_allowed) > 0 + container := allContainers.name +} + +caps_msg = "" { + count(allowed_caps) == 0 +} else = msg { + msg := sprintf(" or set it to the following allowed values: %s", [concat(", ", allowed_caps)]) +} + +################### LIBRARY ################### + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers", "ephemeralContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} diff --git a/rego/pss_pod_capabilities/policy_test.rego b/rego/pss_pod_capabilities/policy_test.rego new file mode 100644 index 0000000..ca76c10 --- /dev/null +++ b/rego/pss_pod_capabilities/policy_test.rego @@ -0,0 +1,585 @@ +package pss_podcapabilities + +################Helpers############################## + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(capabilities) = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": { + "capabilities": { + "add": capabilities + } + } + } + ] + } +} + +pod_init_container_spec(capabilities) = out { + out = { + "initContainers": [ + { + "name": "container1", + "securityContext": { + "capabilities": { + "add": capabilities + } + } + } + ] + } +} + +pod_ephemeral_container_spec(capabilities) = out { + out = { + "ephemeralContainers": [ + { + "name": "container1", + "securityContext": { + "capabilities": { + "add": capabilities + } + } + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} + +################Container Tests###################### + +test_not_allowed_cap_container_on_pod { + input := input_obj(review_pod(pod_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_pod { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_pod(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_pod(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_deployment { + cap_list := ["SYS_TIME"] + input := input_obj(review_deployment(pod_spec(cap_list))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_deployment { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_deployment(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_deployment(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_daemonset { + cap_list := ["SYS_TIME"] + input := input_obj(review_daemonset(pod_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_daemonset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_daemonset(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_daemonset(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_replicaset { + input := input_obj(review_replicaset(pod_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_replicaset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_replicaset(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_replicaset(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_statefulset { + input := input_obj(review_statefulset(pod_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_statefulset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_statefulset(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_statefulset(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_job { + input := input_obj(review_job(pod_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_jobt { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_job(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_job(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_cronjob { + input := input_obj(review_cronjob(pod_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_cronjob { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_cronjob(pod_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_cronjob(pod_spec(null))) + results := violation with input as input + count(results) == 0 +} + +################Init Container Tests###################### + +test_not_allowed_cap_container_on_pod { + input := input_obj(review_pod(pod_init_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_pod { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_pod(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_pod(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_deployment { + cap_list := ["SYS_TIME"] + input := input_obj(review_deployment(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_deployment { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_deployment(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_deployment(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_daemonset { + cap_list := ["SYS_TIME"] + input := input_obj(review_daemonset(pod_init_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_daemonset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_daemonset(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_daemonset(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_replicaset { + input := input_obj(review_replicaset(pod_init_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_replicaset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_replicaset(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_replicaset(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_statefulset { + input := input_obj(review_statefulset(pod_init_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_statefulset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_statefulset(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_statefulset(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_job { + input := input_obj(review_job(pod_init_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_jobt { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_job(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_job(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_cronjob { + input := input_obj(review_cronjob(pod_init_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_cronjob { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_cronjob(pod_init_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_cronjob(pod_init_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +################Ephemeral Container Tests###################### + +test_not_allowed_cap_container_on_pod { + input := input_obj(review_pod(pod_ephemeral_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_pod { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_pod(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_pod(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_deployment { + cap_list := ["SYS_TIME"] + input := input_obj(review_deployment(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_deployment { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_deployment(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_deployment(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_daemonset { + cap_list := ["SYS_TIME"] + input := input_obj(review_daemonset(pod_ephemeral_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_daemonset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_daemonset(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_daemonset(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_replicaset { + input := input_obj(review_replicaset(pod_ephemeral_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_replicaset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_replicaset(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_replicaset(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_statefulset { + input := input_obj(review_statefulset(pod_ephemeral_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_statefulset { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_statefulset(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_statefulset(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_job { + input := input_obj(review_job(pod_ephemeral_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_jobt { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_job(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_job(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_cap_on_cronjob { + input := input_obj(review_cronjob(pod_ephemeral_container_spec(["SYS_TIME"]))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_cap_container_on_cronjob { + cap_list := ["AUDIT_WRITE", "CHOWN", "DAC_OVERRIDE", "FOWNER", "FSETID", "KILL", "MKNOD", "NET_BIND_SERVICE", "SETFCAP", "SETGID", "SETPCAP", "SETUID", "SYS_CHROOT"] + input := input_obj(review_cronjob(pod_ephemeral_container_spec(cap_list))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_cap_nill_container_on_pod { + input := input_obj(review_cronjob(pod_ephemeral_container_spec(null))) + results := violation with input as input + count(results) == 0 +} \ No newline at end of file diff --git a/rego/pss_privileged_pods/policy.rego b/rego/pss_privileged_pods/policy.rego new file mode 100644 index 0000000..8af891a --- /dev/null +++ b/rego/pss_privileged_pods/policy.rego @@ -0,0 +1,106 @@ +package pss_privilegedpods + + +violation[msg] { + failedContainers := getPrivilegedContainers + count(failedContainers) > 0 + + msg := format(sprintf("Container '%s' of %s '%s' should set 'securityContext.privileged' to false", [failedContainers[_], kind, name])) +} + +getPrivilegedContainers[container] { + allContainers := containers[_] + allContainers.securityContext.privileged == true + container := allContainers.name +} + + + + + +################### LIBRARY ################### + + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} diff --git a/rego/pss_privileged_pods/policy_test.rego b/rego/pss_privileged_pods/policy_test.rego new file mode 100644 index 0000000..29894cd --- /dev/null +++ b/rego/pss_privileged_pods/policy_test.rego @@ -0,0 +1,224 @@ +package pss_privilegedpods + +test_privileged_container_on_pod { + input := input_obj(review_pod(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_pod { + input := input_obj(review_pod(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +test_privileged_container_on_deployment { + input := input_obj(review_deployment(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_deployment { + input := input_obj(review_deployment(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +test_privileged_container_on_daemonset { + input := input_obj(review_daemonset(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_daemonset { + input := input_obj(review_daemonset(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +test_privileged_container_on_replicaset { + input := input_obj(review_replicaset(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_replicaset { + input := input_obj(review_replicaset(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +test_privileged_container_on_statefulset { + input := input_obj(review_statefulset(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_statefulset { + input := input_obj(review_statefulset(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +test_privileged_container_on_job { + input := input_obj(review_job(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_jobt { + input := input_obj(review_job(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +test_privileged_container_on_cronjob { + input := input_obj(review_cronjob(pod_spec(true))) + results := violation with input as input + count(results) == 1 +} + +test_unprivileged_container_on_cronjob { + input := input_obj(review_cronjob(pod_spec(false))) + results := violation with input as input + count(results) == 0 +} + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(allow_privileged) = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": { + "privileged": allow_privileged + } + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_procmounts/policy.rego b/rego/pss_procmounts/policy.rego new file mode 100644 index 0000000..d1c9ab0 --- /dev/null +++ b/rego/pss_procmounts/policy.rego @@ -0,0 +1,108 @@ +package pss_procmounts + + +violation[msg] { + failProcMountOpts + + msg := format(sprintf("%s '%s' should not set 'spec.containers[*].securityContext.procMount' or 'spec.initContainers[*].securityContext.procMount'", [kind, name])) +} + +failProcMountOpts { + allContainers := containers[_] + has_key(allContainers.securityContext, "procMount") +} + + + + + +################### LIBRARY ################### + + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers", "ephemeralContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} + +has_key(x, k) { + _ = x[k] +} diff --git a/rego/pss_procmounts/policy_test.rego b/rego/pss_procmounts/policy_test.rego new file mode 100644 index 0000000..8b99b6d --- /dev/null +++ b/rego/pss_procmounts/policy_test.rego @@ -0,0 +1,454 @@ +package pss_procmounts + +test_container_with_procmount_on_pod { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_pod(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_pod { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_pod(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_procmount_on_deployment { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_deployment(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_deployment { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_deployment(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_procmount_on_daemonset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_daemonset(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_daemonset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_daemonset(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_procmount_on_replicaset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_replicaset(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_replicaset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_replicaset(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_procmount_on_statefulset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_statefulset(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_statefulset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_statefulset(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_procmount_on_job { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_job(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_jobt { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_job(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_procmount_on_cronjob { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_cronjob(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_procmount_on_cronjob { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_cronjob(pod_spec(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_pod { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_pod(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_pod { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_pod(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_deployment { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_deployment(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_deployment { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_deployment(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_daemonset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_daemonset(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_daemonset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_daemonset(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_replicaset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_replicaset(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_replicaset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_replicaset(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_statefulset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_statefulset(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_statefulset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_statefulset(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_job { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_job(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_jobt { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_job(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_procmount_on_cronjob { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_cronjob(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_procmount_on_cronjob { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_cronjob(pod_spec_init_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_pod { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_pod(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_pod { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_pod(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_deployment { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_deployment(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_deployment { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_deployment(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_daemonset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_daemonset(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_daemonset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_daemonset(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_replicaset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_replicaset(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_replicaset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_replicaset(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_statefulset { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_statefulset(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_statefulset { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_statefulset(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_job { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_job(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_jobt { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_job(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_procmount_on_cronjob { + container_securitycontext := {"securityContext":{"procMount": "Unmasked"}} + input := input_obj(review_cronjob(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_procmount_on_cronjob { + container_securitycontext := {"securityContext":{}} + input := input_obj(review_cronjob(pod_spec_ephemeral_containers(container_securitycontext))) + results := violation with input as input + count(results) == 0 +} + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(container_securitycontext) = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": container_securitycontext.securityContext + } + ] + } +} + +pod_spec_init_containers(container_securitycontext) = out { + out = { + "initContainers": [ + { + "name": "container1", + "securityContext": container_securitycontext.securityContext + } + ] + } +} + +pod_spec_ephemeral_containers(container_securitycontext) = out { + out = { + "ephemeralContainers": [ + { + "name": "container1", + "securityContext": container_securitycontext.securityContext + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_seccomp/policy.rego b/rego/pss_seccomp/policy.rego new file mode 100644 index 0000000..f66a0a6 --- /dev/null +++ b/rego/pss_seccomp/policy.rego @@ -0,0 +1,121 @@ +package pss_seccomp + +violation[msg] { + failSeccompProfileType + + msg := format(sprintf("%s '%s' should set 'spec.securityContext.seccompProfile.type' to 'RuntimeDefault'", [kind, name])) +} + +violation[msg] { + count(getContainersWithDisallowedSeccompProfileType) > 0 + + msg := format(sprintf("Container '%s' of %s '%s' should set 'spec.containers[*].securityContext.seccompProfile.type' to 'RuntimeDefault'", [getContainersWithDisallowedSeccompProfileType[_], kind, name])) +} + +failSeccompProfileType { + pod := pods[_] + type := pod.spec.securityContext.seccompProfile.type + not type == "RuntimeDefault" +} + +getContainersWithDisallowedSeccompProfileType[name] { + container := containers[_] + type := container.securityContext.seccompProfile.type + not type == "RuntimeDefault" + name := container.name +} + + + + + +################### LIBRARY ################### + + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers", "ephemeralContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} + +has_key(x, k) { + _ = x[k] +} diff --git a/rego/pss_seccomp/policy_test.rego b/rego/pss_seccomp/policy_test.rego new file mode 100644 index 0000000..80cb5d0 --- /dev/null +++ b/rego/pss_seccomp/policy_test.rego @@ -0,0 +1,671 @@ +package pss_seccomp + +test_unconfined_seccomp_on_pod { + pod_seccomp := {"type": "Unconfined"} + input := input_obj(review_pod(pod_spec_seccomp(pod_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_no_unconfined_seccomp_on_pod { + pod_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_pod(pod_spec_seccomp(pod_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_pod { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_pod(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_pod { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_pod(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_deployment { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_deployment(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_deployment { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_deployment(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_deployment { + input := input_obj(review_deployment(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_daemonset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_daemonset(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_daemonset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_daemonset(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_daemonset { + input := input_obj(review_daemonset(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_replicaset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_replicaset(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_replicaset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_replicaset(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_replicaset { + input := input_obj(review_replicaset(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_statefulset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_statefulset(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_statefulset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_statefulset(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_statefulset { + input := input_obj(review_statefulset(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_job { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_job(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_job { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_job(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_job { + input := input_obj(review_job(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_unconfined_seccomp_on_cronjob { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_cronjob(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_no_unconfined_seccomp_on_cronjob { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_cronjob(pod_spec(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_container_with_no_securitycontext_on_cronjob { + input := input_obj(review_cronjob(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_pod { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_pod(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_pod { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_pod(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_deployment { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_deployment(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_deployment { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_deployment(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_deployment { + input := input_obj(review_deployment(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_daemonset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_daemonset(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_daemonset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_daemonset(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_daemonset { + input := input_obj(review_daemonset(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_replicaset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_replicaset(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_replicaset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_replicaset(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_replicaset { + input := input_obj(review_replicaset(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_statefulset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_statefulset(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_statefulset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_statefulset(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_statefulset { + input := input_obj(review_statefulset(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_job { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_job(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_job { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_job(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_job { + input := input_obj(review_job(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_unconfined_seccomp_on_cronjob { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_cronjob(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_no_unconfined_seccomp_on_cronjob { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_cronjob(pod_spec_init_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_no_securitycontext_on_cronjob { + input := input_obj(review_cronjob(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_pod { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_pod(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_pod { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_pod(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_deployment { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_deployment(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_deployment { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_deployment(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_deployment { + input := input_obj(review_deployment(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_daemonset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_daemonset(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_daemonset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_daemonset(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_daemonset { + input := input_obj(review_daemonset(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_replicaset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_replicaset(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_replicaset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_replicaset(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_replicaset { + input := input_obj(review_replicaset(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_statefulset { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_statefulset(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_statefulset { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_statefulset(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_statefulset { + input := input_obj(review_statefulset(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_job { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_job(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_job { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_job(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_job { + input := input_obj(review_job(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_unconfined_seccomp_on_cronjob { + container_seccomp := {"type": "Unconfined"} + input := input_obj(review_cronjob(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_no_unconfined_seccomp_on_cronjob { + container_seccomp := {"type": "RuntimeDefault"} + input := input_obj(review_cronjob(pod_spec_ephemeral_containers(container_seccomp))) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_no_securitycontext_on_cronjob { + input := input_obj(review_cronjob(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(container_seccomp) = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": { + "seccompProfile": { + "type": container_seccomp.type + } + } + } + ] + } +} + +pod_spec_seccomp(pod_seccomp) = out { + out = { + "securityContext": { + "seccompProfile": { + "type": pod_seccomp.type + } + }, + "containers": [ + { + "name": "container1" + } + ] + } +} + +pod_spec_no_securitycontext() = out { + out = { + "securityContext": {}, + "containers": [ + { + "name": "container1" + } + ] + } +} + +pod_spec_containers_no_securitycontext() = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": {} + } + ] + } +} + +pod_spec_init_containers(container_seccomp) = out { + out = { + "initContainers": [ + { + "name": "container1", + "securityContext": { + "seccompProfile": { + "type": container_seccomp.type + } + } + } + ] + } +} + +pod_spec_init_containers_no_securitycontext() = out { + out = { + "initContainers": [ + { + "name": "container1", + "securityContext": {} + } + ] + } +} + +pod_spec_ephemeral_containers(container_seccomp) = out { + out = { + "ephemeralContainers": [ + { + "name": "container1", + "securityContext": { + "seccompProfile": { + "type": container_seccomp.type + } + } + } + ] + } +} + +pod_spec_ephemeral_containers_no_securitycontext() = out { + out = { + "ephemeralContainers": [ + { + "name": "container1", + "securityContext": {} + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_selinux/policy.rego b/rego/pss_selinux/policy.rego new file mode 100644 index 0000000..4e7bc76 --- /dev/null +++ b/rego/pss_selinux/policy.rego @@ -0,0 +1,142 @@ +package pss_selinux + +violation[msg] { + type := failSELinuxType[_] + + msg := format(sprintf("%s '%s' uses invalid seLinux type '%s'", [kind, name, type])) +} + +violation[msg] { + keys := failForbiddenSELinuxProperties + + count(keys) > 0 + + msg := format(sprintf("%s '%s' uses restricted properties in seLinuxOptions: (%s)", [kind, name, concat(", ", keys)])) +} + +failSELinuxType[type] { + context := getAllSecurityContexts[_] + context.seLinuxOptions != null + context.seLinuxOptions.type != null + + type := context.seLinuxOptions.type +} + +failForbiddenSELinuxProperties[key] { + context := getAllSecurityContexts[_] + context.seLinuxOptions != null + forbiddenProps := getForbiddenSELinuxProperties(context) + key := forbiddenProps[_] +} + +getAllSecurityContexts[context] { + context := containers[_].securityContext +} + +getAllSecurityContexts[context] { + context := pods[_].spec.securityContext +} + +getForbiddenSELinuxProperties(context) = keys { + forbiddenProperties = ["role", "user"] + keys := {msg | + key := forbiddenProperties[_] + has_key(context.seLinuxOptions, key) + msg := sprintf("'%s'", [key]) + } +} + + + + + +################### LIBRARY ################### + + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers", "ephemeralContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} + +has_key(x, k) { + _ = x[k] +} diff --git a/rego/pss_selinux/policy_test.rego b/rego/pss_selinux/policy_test.rego new file mode 100644 index 0000000..a73b8ae --- /dev/null +++ b/rego/pss_selinux/policy_test.rego @@ -0,0 +1,663 @@ +package pss_selinux + +test_selinux_options_on_pod { + pod_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_pod(pod_spec_selinux(pod_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_multiple_selinux_options_on_pod { + pod_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_pod(pod_spec_selinux(pod_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_pod { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_pod(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_pod { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_pod(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_deployment { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_deployment(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_deployment { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_deployment(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_deployment { + input := input_obj(review_deployment(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_daemonset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_daemonset(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_daemonset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_daemonset(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_daemonset { + input := input_obj(review_daemonset(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_replicaset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_replicaset(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_replicaset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_replicaset(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_replicaset { + input := input_obj(review_replicaset(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_statefulset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_statefulset(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_statefulset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_statefulset(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_statefulset { + input := input_obj(review_statefulset(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_job { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_job(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_job { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_job(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_job { + input := input_obj(review_job(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_container_with_selinux_options_on_cronjob { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_cronjob(pod_spec(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_container_with_multiple_selinux_options_on_cronjob { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_cronjob(pod_spec(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_container_with_no_securitycontext_on_cronjob { + input := input_obj(review_cronjob(pod_spec_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_pod { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_pod(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_pod { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_pod(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_deployment { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_deployment(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_deployment { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_deployment(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_deployment { + input := input_obj(review_deployment(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_daemonset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_daemonset(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_daemonset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_daemonset(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_daemonset { + input := input_obj(review_daemonset(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_replicaset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_replicaset(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_replicaset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_replicaset(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_replicaset { + input := input_obj(review_replicaset(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_statefulset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_statefulset(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_statefulset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_statefulset(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_statefulset { + input := input_obj(review_statefulset(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_job { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_job(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_job { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_job(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_job { + input := input_obj(review_job(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_init_container_with_selinux_options_on_cronjob { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_cronjob(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_init_container_with_multiple_selinux_options_on_cronjob { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_cronjob(pod_spec_init_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_init_container_with_no_securitycontext_on_cronjob { + input := input_obj(review_cronjob(pod_spec_init_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_pod { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_pod(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_pod { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_pod(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_pod { + input := input_obj(review_pod(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_deployment { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_deployment(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_deployment { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_deployment(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_deployment { + input := input_obj(review_deployment(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_daemonset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_daemonset(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_daemonset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_daemonset(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_daemonset { + input := input_obj(review_daemonset(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_replicaset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_replicaset(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_replicaset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_replicaset(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_replicaset { + input := input_obj(review_replicaset(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_statefulset { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_statefulset(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_statefulset { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_statefulset(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_statefulset { + input := input_obj(review_statefulset(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_job { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_job(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_job { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_job(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_job { + input := input_obj(review_job(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +test_ephemeral_container_with_selinux_options_on_cronjob { + container_selinux := {"seLinuxOptions":{"type": "custom"}} + input := input_obj(review_cronjob(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) == 1 +} + +test_ephemeral_container_with_multiple_selinux_options_on_cronjob { + container_selinux := {"seLinuxOptions":{"type": "custom", "role": "admin"}} + input := input_obj(review_cronjob(pod_spec_ephemeral_containers(container_selinux))) + results := violation with input as input + count(results) > 1 +} + +test_ephemeral_container_with_no_securitycontext_on_cronjob { + input := input_obj(review_cronjob(pod_spec_ephemeral_containers_no_securitycontext)) + results := violation with input as input + count(results) == 0 +} + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(pod_selinux) = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": { + "seLinuxOptions": pod_selinux.seLinuxOptions + } + } + ] + } +} + +pod_spec_selinux(pod_selinux) = out { + out = { + "securityContext": { + "seLinuxOptions": pod_selinux.seLinuxOptions + }, + "containers": [ + { + "name": "container1" + } + ] + } +} + +pod_spec_no_securitycontext() = out { + out = { + "securityContext": {}, + "containers": [ + { + "name": "container1" + } + ] + } +} + +pod_spec_containers_no_securitycontext() = out { + out = { + "containers": [ + { + "name": "container1", + "securityContext": {} + } + ] + } +} + +pod_spec_init_containers(pod_selinux) = out { + out = { + "initContainers": [ + { + "name": "container1", + "securityContext": { + "seLinuxOptions": pod_selinux.seLinuxOptions + } + } + ] + } +} + +pod_spec_init_containers_no_securitycontext() = out { + out = { + "initContainers": [ + { + "name": "container1", + "securityContext": {} + } + ] + } +} + +pod_spec_ephemeral_containers(pod_selinux) = out { + out = { + "ephemeralContainers": [ + { + "name": "container1", + "securityContext": { + "seLinuxOptions": pod_selinux.seLinuxOptions + } + } + ] + } +} + +pod_spec_ephemeral_containers_no_securitycontext() = out { + out = { + "ephemeralContainers": [ + { + "name": "container1", + "securityContext": {} + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} diff --git a/rego/pss_sysctl_options/policy.rego b/rego/pss_sysctl_options/policy.rego new file mode 100644 index 0000000..b199123 --- /dev/null +++ b/rego/pss_sysctl_options/policy.rego @@ -0,0 +1,109 @@ +package pss_sysctloptions + + +violation[msg] { + failSysctls + + msg := format(sprintf("%s '%s' should set 'securityContext.sysctl' to the allowed values", [kind, name])) +} + +allowed_sysctls := { + "kernel.shm_rmid_forced", + "net.ipv4.ip_local_port_range", + "net.ipv4.ip_unprivileged_port_start", + "net.ipv4.tcp_syncookies", + "net.ipv4.ping_group_range", +} + +failSysctls { + pod := pods[_] + set_sysctls := {sysctl | sysctl := pod.spec.securityContext.sysctls[_].name} + sysctls_not_allowed := set_sysctls - allowed_sysctls + count(sysctls_not_allowed) > 0 +} + +################### LIBRARY ################### + +default is_gatekeeper = true + +object = input.review.object { + is_gatekeeper +} + +format(msg) = gatekeeper_format { + is_gatekeeper + gatekeeper_format = {"msg": msg} +} + +name = object.metadata.name + +kind = object.kind + +is_pod { + kind = "Pod" +} + +is_cronjob { + kind = "CronJob" +} + +default is_controller = false + +is_controller { + kind = "Deployment" +} + +is_controller { + kind = "StatefulSet" +} + +is_controller { + kind = "DaemonSet" +} + +is_controller { + kind = "ReplicaSet" +} + +is_controller { + kind = "ReplicationController" +} + +is_controller { + kind = "Job" +} + +pod_containers(pod) = all_containers { + keys = {"containers", "initContainers", "ephemeralContainers"} + all_containers = [c | keys[k]; c = pod.spec[k][_]] +} + +containers[container] { + pods[pod] + all_containers = pod_containers(pod) + container = all_containers[_] +} + +containers[container] { + all_containers = pod_containers(object) + container = all_containers[_] +} + +pods[pod] { + is_pod + pod = object +} + +pods[pod] { + is_controller + pod = object.spec.template +} + +pods[pod] { + is_cronjob + pod = object.spec.jobTemplate.spec.template +} + +has_field(obj, field) { + obj[field] +} diff --git a/rego/pss_sysctl_options/policy_test.rego b/rego/pss_sysctl_options/policy_test.rego new file mode 100644 index 0000000..327d413 --- /dev/null +++ b/rego/pss_sysctl_options/policy_test.rego @@ -0,0 +1,268 @@ +package pss_sysctloptions + +################Helpers############################## + +review_pod(pod_spec) = out { + out = { + "object": { + "kind": "Pod", + "apiVersion": "v1", + "metadata": { + "name": "my-pod", + }, + "spec": pod_spec + } + } +} + +review_deployment(pod_spec) = out { + out = { + "object": { + "kind": "Deployment", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-deployment", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_daemonset(pod_spec) = out { + out = { + "object": { + "kind": "DaemonSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-daemonset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_replicaset(pod_spec) = out { + out = { + "object": { + "kind": "ReplicaSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-replicaset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_statefulset(pod_spec) = out { + out = { + "object": { + "kind": "StatefulSet", + "apiVersion": "apps/v1", + "metadata": { + "name": "my-statefulset", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_job(pod_spec) = out { + out = { + "object": { + "kind": "Job", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-job", + }, + "spec": { + "template": { + "spec": pod_spec + } + } + } + } +} + +review_cronjob(pod_spec) = out { + out = { + "object": { + "kind": "CronJob", + "apiVersion": "batch/v1", + "metadata": { + "name": "my-cronjob", + }, + "spec": { + "jobTemplate": { + "spec" : { + "template": { + "spec": pod_spec + } + } + } + } + } + } +} + +pod_spec(securitycontext) = out { + out = { + "securityContext" : securitycontext, + "containers": [ + { + "name": "container1", + } + ] + } +} + +input_obj(review) = out { + out = { + "parameters": {}, + "review": review + } +} + +################Container Tests###################### + +test_not_allowed_sysctls_options_container_on_pod { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_pod { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_pod { + input := input_obj(review_pod(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_sysctls_options_container_on_deployment { + input := input_obj(review_deployment(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_deployment { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_deployment { + input := input_obj(review_deployment(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_sysctls_options_container_on_daemonset { + input := input_obj(review_daemonset(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_daemonset { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_daemonset { + input := input_obj(review_daemonset(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_sysctls_options_container_on_replicaset { + input := input_obj(review_replicaset(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_replicaset { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_replicaset { + input := input_obj(review_replicaset(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_sysctls_options_container_on_statefulset { + input := input_obj(review_statefulset(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_statefulset { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_statefulset { + input := input_obj(review_statefulset(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_sysctls_options_container_on_job { + input := input_obj(review_job(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_job { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_job { + input := input_obj(review_job(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} + +test_not_allowed_sysctls_options_container_on_cronjob { + input := input_obj(review_cronjob(pod_spec({"sysctls": [{"name": "net.core.somaxconn","value": "1024",},{"name": "kernel.msgmax","value": "65536",},]}))) + results := violation with input as input + count(results) == 1 +} + +test_allowed_sysctls_options_container_on_cronjob { + input := input_obj(review_pod(pod_spec({"sysctls": [{"name": "kernel.shm_rmid_forced","value": "0",},{"name": "net.ipv4.ip_local_port_range","value": "",},{"name": "net.ipv4.ip_unprivileged_port_start","value": "0",},{"name": "net.ipv4.tcp_syncookies","value": "1",},{"name": "net.ipv4.ping_group_range","value": "",}]}))) + results := violation with input as input + count(results) == 0 +} + +test_allowed_sysctls_options_nill_container_on_cronjob { + input := input_obj(review_cronjob(pod_spec({"sysctls": null}))) + results := violation with input as input + count(results) == 0 +} \ No newline at end of file diff --git a/templates/constraint_template_pss_apparmor.yaml b/templates/constraint_template_pss_apparmor.yaml new file mode 100644 index 0000000..1ab93dd --- /dev/null +++ b/templates/constraint_template_pss_apparmor.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: pssapparmor +spec: + crd: + spec: + names: + kind: PssAppArmor + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_apparmor/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_host_namespace.yaml b/templates/constraint_template_pss_host_namespace.yaml new file mode 100644 index 0000000..835bd31 --- /dev/null +++ b/templates/constraint_template_pss_host_namespace.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: psshostnamespace +spec: + crd: + spec: + names: + kind: PssHostNamespace + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_host_namespaces/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_hostpath_volume.yaml b/templates/constraint_template_pss_hostpath_volume.yaml new file mode 100644 index 0000000..eadb130 --- /dev/null +++ b/templates/constraint_template_pss_hostpath_volume.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: psshostpathvolume +spec: + crd: + spec: + names: + kind: PssHostpathVolume + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_hostpath_volumes/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_hostport.yaml b/templates/constraint_template_pss_hostport.yaml new file mode 100644 index 0000000..1f07308 --- /dev/null +++ b/templates/constraint_template_pss_hostport.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: psshostport +spec: + crd: + spec: + names: + kind: PssHostPort + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_hostports/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_pod_capabilities.yaml b/templates/constraint_template_pss_pod_capabilities.yaml new file mode 100644 index 0000000..dd73b93 --- /dev/null +++ b/templates/constraint_template_pss_pod_capabilities.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: psspodcapabilities +spec: + crd: + spec: + names: + kind: PssPodCapabilities + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_pod_capabilities/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_privileged.yaml b/templates/constraint_template_pss_privileged.yaml new file mode 100644 index 0000000..7dd5d9d --- /dev/null +++ b/templates/constraint_template_pss_privileged.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: pssprivilegedpod +spec: + crd: + spec: + names: + kind: PssPrivilegedPod + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_privileged_pods/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_procmount.yaml b/templates/constraint_template_pss_procmount.yaml new file mode 100644 index 0000000..bdd64bb --- /dev/null +++ b/templates/constraint_template_pss_procmount.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: pssprocmount +spec: + crd: + spec: + names: + kind: PssProcMount + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_procmounts/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_seccomp.yaml b/templates/constraint_template_pss_seccomp.yaml new file mode 100644 index 0000000..e470bba --- /dev/null +++ b/templates/constraint_template_pss_seccomp.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: pssseccomp +spec: + crd: + spec: + names: + kind: PssSeccomp + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_seccomp/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_selinux.yaml b/templates/constraint_template_pss_selinux.yaml new file mode 100644 index 0000000..c1cc025 --- /dev/null +++ b/templates/constraint_template_pss_selinux.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: pssselinux +spec: + crd: + spec: + names: + kind: PssSELinux + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_selinux/policy.rego" | indent 8 }} diff --git a/templates/constraint_template_pss_sysctl_options.yaml b/templates/constraint_template_pss_sysctl_options.yaml new file mode 100644 index 0000000..bacca2b --- /dev/null +++ b/templates/constraint_template_pss_sysctl_options.yaml @@ -0,0 +1,13 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: psssysctlsoptions +spec: + crd: + spec: + names: + kind: PssSysctlsOptions + targets: + - target: admission.k8s.gatekeeper.sh + rego: | +{{.Files.Get "rego/pss_sysctl_options/policy.rego" | indent 8 }} -- GitLab