diff --git a/Chart.yaml b/Chart.yaml index b33aff33d91791bb561804f7950987b63f547380..0a01ccf8479c50ebbfe5ffeb7b0ca82036f44750 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 41fa32fad6edda32e4240271b5844f257705249c..ffb37cbb3ebb1344d51676d594da7aa1892edfd2 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 0000000000000000000000000000000000000000..9d40672ef45bac1a44cad933cd7a426c523c80ae --- /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 0000000000000000000000000000000000000000..e199012a8795c712e6928429288921d28cb76185 --- /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 0000000000000000000000000000000000000000..2d6854f877f5ff58974cb258ce9df6add6c6fe2a --- /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 0000000000000000000000000000000000000000..3b89e8c988ff6c5989f21c5bfb9fbe45d435ace6 --- /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 0000000000000000000000000000000000000000..75e9ec26330ad4b930c36f3e30917cad851b5322 --- /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 0000000000000000000000000000000000000000..b3e47b4b39e4560105c924ebf14e85ce29057ea2 --- /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 0000000000000000000000000000000000000000..c5399d37b2487422b4c1203c43089b4399ae68c0 --- /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 0000000000000000000000000000000000000000..c9f47a53ddaf7fa99a1f458528af936befd64b29 --- /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 0000000000000000000000000000000000000000..33c21c0464cfe6ee3187732fe0e886a1f417dd2d --- /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 0000000000000000000000000000000000000000..ca76c10cf1b8fc36abe37d90351087d4c0dafe88 --- /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 0000000000000000000000000000000000000000..8af891a5424c9aaa9bff3659a0527b2f0ef4c151 --- /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 0000000000000000000000000000000000000000..29894cdb561535fd27fffd4c18addc5054a68ddf --- /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 0000000000000000000000000000000000000000..d1c9ab0455d19abd8604618a265c98a26e6b48c3 --- /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 0000000000000000000000000000000000000000..8b99b6d8ae633f2ec5cc8b65bad7c524c77d8baa --- /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 0000000000000000000000000000000000000000..f66a0a6f8bd5ef3074ef9bdfaf4d00af8dd3de6f --- /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 0000000000000000000000000000000000000000..80cb5d0e78eb7be534ebc7b5f0738b4789703053 --- /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 0000000000000000000000000000000000000000..4e7bc76f3e8a2758087f8323a78daa8446793fcf --- /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 0000000000000000000000000000000000000000..a73b8ae54548f8d4efe135b5666f10b9df5dab9a --- /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 0000000000000000000000000000000000000000..b19912335fc505f1d8b651c4f1818a110ef7b182 --- /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 0000000000000000000000000000000000000000..327d4136aa477c0c916ee2fc9c127d5ce9269d8e --- /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 0000000000000000000000000000000000000000..1ab93dd710a54af93917e67195cd02f662c74bfb --- /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 0000000000000000000000000000000000000000..835bd3133c778d5bba86efc668b128268f61557e --- /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 0000000000000000000000000000000000000000..eadb130ba2f064f3cb78df70f597f1899f4e431d --- /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 0000000000000000000000000000000000000000..1f0730844ffa0ea22ae9569047b08761b056d2e5 --- /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 0000000000000000000000000000000000000000..dd73b93db67bbfc01039937e3bfbe3e5a7448fe7 --- /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 0000000000000000000000000000000000000000..7dd5d9d10807ebd5b258e36951202f6fc224925c --- /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 0000000000000000000000000000000000000000..bdd64bb9347c3b1d5728503f8508678e3095bf53 --- /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 0000000000000000000000000000000000000000..e470bba229193bd6e0124d96e79b6691bbcf9bc3 --- /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 0000000000000000000000000000000000000000..c1cc025c34c25bf090789fd0602092465174d8e6 --- /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 0000000000000000000000000000000000000000..bacca2b14acded7dadd9e02cb6b75d23dcd886bd --- /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 }}