diff --git a/plugins/source/k8s/policies/README.md b/plugins/source/k8s/policies/README.md index 88d9becc4c4f08..d3e24f16c9f849 100644 --- a/plugins/source/k8s/policies/README.md +++ b/plugins/source/k8s/policies/README.md @@ -1,3 +1,7 @@ +# Deprecation Notice + +These are the policy files for CloudQuery **v0.x.x**. Please use the [policies_v1/](../policies_v1/) directory for CloudQuery v1.x.x policies. + # CloudQuery Policies CloudQuery SQL Policies for Kubernetes diff --git a/plugins/source/k8s/policies_v1/README.md b/plugins/source/k8s/policies_v1/README.md new file mode 100644 index 00000000000000..88d9becc4c4f08 --- /dev/null +++ b/plugins/source/k8s/policies_v1/README.md @@ -0,0 +1,33 @@ +# CloudQuery Policies + +CloudQuery SQL Policies for Kubernetes + +## Policies and Compliance Frameworks Available + +- [Kubernetes NSA CISA v1](./nsa_cisa_v1/policy.sql) + +## Running + +You can execute policies with `psql`. For example: + +```bash +# Set DSN to your PostgreSQL populated by CloudQuery +export DSN=postgres://postgres:pass@localhost:5432/postgres +# Execute the NSA CISA Policy +psql ${DSN} -f ./nsa_cisa_v1/policy.sql +``` + +This will create all the results in `k8s_policy_results` table which you can query directly, connect to any BI system (Grafana, Preset, AWS QuickSight, PowerBI, …). + +You can also output it into CSV or HTML with the following built-in `psql` commands: + +```bash +# Set DSN to your PostgreSQL populated by CloudQuery +export DSN=postgres://postgres:pass@localhost:5432/postgres +# default tabular output +psql ${DSN} -c "select * from k8s_policy_results" +# CSV output +psql ${DSN} -c "select * from k8s_policy_results" --csv +# HTML output +psql ${DSN} -c "select * from k8s_policy_results" --html +``` diff --git a/plugins/source/k8s/policies_v1/create_k8s_policy_results.sql b/plugins/source/k8s/policies_v1/create_k8s_policy_results.sql new file mode 100644 index 00000000000000..e95b26a6c59779 --- /dev/null +++ b/plugins/source/k8s/policies_v1/create_k8s_policy_results.sql @@ -0,0 +1,12 @@ +create table if not exists k8s_policy_results +( + execution_time timestamp with time zone, + framework varchar(255), + check_id varchar(255), + title text, + context text, + namespace text, + resource_id varchar(1024), + resource_name text, + status varchar(16) +) \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/nsa_cisa_v1/README.md b/plugins/source/k8s/policies_v1/nsa_cisa_v1/README.md new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/plugins/source/k8s/policies_v1/nsa_cisa_v1/network_hardening.sql b/plugins/source/k8s/policies_v1/nsa_cisa_v1/network_hardening.sql new file mode 100644 index 00000000000000..9d096c71c05ae0 --- /dev/null +++ b/plugins/source/k8s/policies_v1/nsa_cisa_v1/network_hardening.sql @@ -0,0 +1,132 @@ +\echo "Executing K8S Network Hardening NSA CISA v1" + +\echo "Enforce CPU resource limits" + +\echo "Deamonsets enforce cpu limit" +\set check_id "daemonset_cpu_limit" +\ir ../queries/network_hardening/daemonset_cpu_limit.sql + +\echo "Deployments enforce cpu limit" +\set check_id "deployment_cpu_limit" +\ir ../queries/network_hardening/deployment_cpu_limit.sql + +\echo "Jobs enforce cpu limit" +\set check_id "job_cpu_limit" +\ir ../queries/network_hardening/job_cpu_limit.sql + + +\echo "Namespaces CPU limit range default" +\set check_id "namespace_limit_range_default_cpu_limit" +\ir ../queries/network_hardening/namespace_limit_range_default_cpu_limit.sql + + +\echo "Namespaces CPU limit resource quota" +\set check_id "namespace_resource_quota_cpu_limit" +\ir ../queries/network_hardening/namespace_resource_quota_cpu_limit.sql + + +\echo "ReplciaSets enforce cpu limit" +\set check_id "replicaset_cpu_limit" +\ir ../queries/network_hardening/replicaset_cpu_limit.sql + + +\echo "Enforce CPU request" + +\echo "Deamonsets enforce cpu request" +\set check_id "daemonset_cpu_request" +\ir ../queries/network_hardening/daemonset_cpu_request.sql + +\echo "Deployments enforce cpu request" +\set check_id "deployment_cpu_request" +\ir ../queries/network_hardening/deployment_cpu_request.sql + +\echo "Jobs enforce cpu request" +\set check_id "job_cpu_limit" +\ir ../queries/network_hardening/job_cpu_limit.sql + + +\echo "Namespaces CPU request range default" +\set check_id "namespace_limit_range_default_cpu_request" +\ir ../queries/network_hardening/namespace_limit_range_default_cpu_request.sql + + +\echo "Namespaces CPU request resource quota" +\set check_id "namespace_resource_quota_cpu_request" +\ir ../queries/network_hardening/namespace_resource_quota_cpu_request.sql + + +\echo "ReplciaSets enforce cpu request" +\set check_id "replicaset_cpu_request" +\ir ../queries/network_hardening/replicaset_cpu_request.sql + +\echo "Ensure memory limits set" + +\echo "Deamonsets enforce memory limit" +\set check_id "daemonset_memory_limit" +\ir ../queries/network_hardening/daemonset_memory_limit.sql + +\echo "Deployments enforce memory limit" +\set check_id "deployment_memory_limit" +\ir ../queries/network_hardening/deployment_memory_limit.sql + +\echo "Jobs enforce memory limit" +\set check_id "job_memory_limit" +\ir ../queries/network_hardening/job_memory_limit.sql + + +\echo "Namespaces CPU memory range default" +\set check_id "namespace_limit_range_default_memory_limit" +\ir ../queries/network_hardening/namespace_limit_range_default_memory_limit.sql + + +\echo "Namespaces CPU memory resource quota" +\set check_id "namespace_resource_quota_memory_limit" +\ir ../queries/network_hardening/namespace_resource_quota_memory_limit.sql + + +\echo "ReplciaSets enforce memory limit" +\set check_id "replicaset_memory_limit" +\ir ../queries/network_hardening/replicaset_memory_limit.sql + + +\echo "Enforce Memory request" + +\echo "Deamonsets enforce memory request" +\set check_id "daemonset_memory_request" +\ir ../queries/network_hardening/daemonset_memory_request.sql + +\echo "Deployments enforce memory request" +\set check_id "deployment_memory_request" +\ir ../queries/network_hardening/deployment_memory_request.sql + +\echo "Jobs enforce memory request" +\set check_id "job_memory_request" +\ir ../queries/network_hardening/job_memory_request.sql + + +\echo "Namespaces Memory request range default" +\set check_id "namespace_limit_range_default_memory_request" +\ir ../queries/network_hardening/namespace_limit_range_default_memory_request.sql + + +\echo "Namespaces Memory request resource quota" +\set check_id "namespace_resource_quota_memory_request" +\ir ../queries/network_hardening/namespace_resource_quota_memory_request.sql + + +\echo "ReplciaSets enforce cpu request" +\set check_id "replicaset_memory_request" +\ir ../queries/network_hardening/replicaset_memory_request.sql + + +\echo "Enforce default deny network policy" + +\echo "Network policy default deny egress" +\set check_id "network_policy_default_deny_egress" +\ir ../queries/network_hardening/network_policy_default_deny_egress.sql + + +\echo "Network policy default deny ingress" +\set check_id "network_policy_default_deny_ingress" +\ir ../queries/network_hardening/network_policy_default_deny_ingress.sql + diff --git a/plugins/source/k8s/policies_v1/nsa_cisa_v1/pod_security.sql b/plugins/source/k8s/policies_v1/nsa_cisa_v1/pod_security.sql new file mode 100644 index 00000000000000..75c70a6b9bcf89 --- /dev/null +++ b/plugins/source/k8s/policies_v1/nsa_cisa_v1/pod_security.sql @@ -0,0 +1,152 @@ +\echo "Executing K8S Pod Security NSA CISA v1" + +\set check_id "container_disallow_host_path" +\echo "Disallow host path access" +\ir ../queries/pod_security/pod_volume_host_path.sql + +\echo "Verify containers have privileged access disabled" + +\echo "Deamonset privileges disabled" +\set check_id "daemonset_container_privilege_disabled" +\ir ../queries/pod_security/daemonset_container_privilege_disabled.sql + +\echo "Deployment containers privileged access disabled" +\set check_id "deployment_container_privilege_disabled" +\ir ../queries/pod_security/deployment_container_privilege_disabled.sql + +\echo "Jobs container privileged access disabled" +\set check_id "job_container_privilege_disabled" +\ir ../queries/pod_security/job_container_privilege_disabled.sql + +\echo "Pod container privileged access disabled" +\set check_id "pod_container_privilege_disabled" +\ir ../queries/pod_security/pod_container_privilege_disabled.sql + +\echo "ReplicaSet container privileged access disabled" +\set check_id "replicaset_container_privilege_disabled" +\ir ../queries/pod_security/replicaset_container_privilege_disabled.sql + +\echo "Container privileged escalation disabled" + +\echo "DaemonSet container privileged escalation disabled" +\set check_id "daemonset_container_privilege_escalation_disabled" +\ir ../queries/pod_security/daemonset_container_privilege_escalation_disabled.sql + +\echo "Deployment container privileged escalation disabled" +\set check_id "deployment_container_privilege_escalation_disabled" +\ir ../queries/pod_security/deployment_container_privilege_escalation_disabled.sql + +\echo "Job container privileged escalation disabled" +\set check_id "job_container_privilege_escalation_disabled" +\ir ../queries/pod_security/job_container_privilege_escalation_disabled.sql + +\echo "Pod container privileged escalation disabled" +\set check_id "pod_container_privilege_escalation_disabled" +\ir ../queries/pod_security/pod_container_privilege_escalation_disabled.sql + +\echo "ReplicaSet container privileged escalation disabled" +\set check_id "replicaset_container_privilege_escalation_disabled" +\ir ../queries/pod_security/replicaset_container_privilege_escalation_disabled.sql + + +\echo "Host network access disabled" + +\echo "DaemonSet container hostNetwork disabled" +\set check_id "daemonset_host_network_access_disabled" +\ir ../queries/pod_security/daemonset_host_network_access_disabled.sql + +\echo "Deployment container hostNetwork disabled" +\set check_id "deployment_host_network_access_disabled" +\ir ../queries/pod_security/deployment_host_network_access_disabled.sql + +\echo "Job container hostNetwork disabled" +\set check_id "job_host_network_access_disabled" +\ir ../queries/pod_security/job_host_network_access_disabled.sql + +\echo "Pod container hostNetwork disabled" +\set check_id "pod_container_privilege_escalation_disabled" +\ir ../queries/pod_security/pod_host_network_access_disabled.sql + +\echo "ReplicaSet container hostNetwork disabled" +\set check_id "replicaset_container_privilege_escalation_disabled" +\ir ../queries/pod_security/replicaset_host_network_access_disabled.sql + + +\echo "HostPID and HostIPC sharing disabled" + +\echo "DeamonSet containers HostPID and HostIPC sharing disabled" +\set check_id "daemonset_hostpid_hostipc_sharing_disabled" +\ir ../queries/pod_security/daemonset_hostpid_hostipc_sharing_disabled.sql + +\echo "Deployment containers HostPID and HostIPC sharing disabled" +\set check_id "deployment_hostpid_hostipc_sharing_disabled" +\ir ../queries/pod_security/deployment_hostpid_hostipc_sharing_disabled.sql + +\echo "Job containers HostPID and HostIPC sharing disabled" +\set check_id "job_hostpid_hostipc_sharing_disabled" +\ir ../queries/pod_security/job_hostpid_hostipc_sharing_disabled.sql + +\echo "Pod containers HostPID and HostIPC sharing disabled" +\set check_id "pod_hostpid_hostipc_sharing_disabled" +\ir ../queries/pod_security/pod_hostpid_hostipc_sharing_disabled.sql + +\echo "ReplicaSet containers HostPID and HostIPC sharing disabled" +\set check_id "replicaset_hostpid_hostipc_sharing_disabled" +\ir ../queries/pod_security/replicaset_hostpid_hostipc_sharing_disabled.sql + +\echo "Containers root file system is read-only" + +\echo "DeamonSet containers root file system is read-only" +\set check_id "daemonset_immutable_container_filesystem" +\ir ../queries/pod_security/daemonset_immutable_container_filesystem.sql + +\echo "Deployment containers root file system is read-only" +\set check_id "deployment_immutable_container_filesystem" +\ir ../queries/pod_security/deployment_immutable_container_filesystem.sql + +\echo "Job containers root file system is read-only" +\set check_id "job_immutable_container_filesystem" +\ir ../queries/pod_security/job_immutable_container_filesystem.sql + +\echo "Pod containers root file system is read-only" +\set check_id "pod_immutable_container_filesystem" +\ir ../queries/pod_security/pod_immutable_container_filesystem.sql + +\echo "ReplicaSet containers root file system is read-only" +\set check_id "replicaset_immutable_container_filesystem" +\ir ../queries/pod_security/replicaset_immutable_container_filesystem.sql + + +\echo "Enforce containers to run as non-root" + +\echo "DeamonSet containers to run as non-root" +\set check_id "daemonset_non_root_container" +\ir ../queries/pod_security/daemonset_non_root_container.sql + +\echo "Deployment containers to run as non-root" +\set check_id "deployment_non_root_container" +\ir ../queries/pod_security/deployment_non_root_container.sql + +\echo "Job containers to run as non-root" +\set check_id "job_non_root_container" +\ir ../queries/pod_security/job_non_root_container.sql + +\echo "Pod containers to run as non-root" +\set check_id "pod_non_root_container" +\ir ../queries/pod_security/pod_non_root_container.sql + +\echo "ReplicaSet containers to run as non-root" +\set check_id "replicaset_non_root_container" +\ir ../queries/pod_security/replicaset_non_root_container.sql + + +\echo "Automatic mapping of the service account tokens disabled" + +\echo "Pod service account tokens disabled" +\set check_id "pod_service_account_token_disabled" +\ir ../queries/pod_security/pod_service_account_token_disabled.sql + +\echo "Service account tokens disabled" +\set check_id "service_account_token_disabled" +\ir ../queries/pod_security/service_account_token_disabled.sql + diff --git a/plugins/source/k8s/policies_v1/nsa_cisa_v1/policy.sql b/plugins/source/k8s/policies_v1/nsa_cisa_v1/policy.sql new file mode 100644 index 00000000000000..b023acd021c31f --- /dev/null +++ b/plugins/source/k8s/policies_v1/nsa_cisa_v1/policy.sql @@ -0,0 +1,15 @@ +\set ON_ERROR_STOP on +SET TIME ZONE 'UTC'; +-- neat trick to set execution_time if not already set +-- https://stackoverflow.com/questions/32582600/only-set-variable-in-psql-script-if-not-specified-on-the-command-line +\set execution_time :execution_time +SELECT CASE + WHEN :'execution_time' = ':execution_time' THEN to_char(now(), 'YYYY-MM-dd HH24:MI:SS.US') + ELSE :'execution_time' +END AS "execution_time" \gset + +\set framework 'cis_v1.2.0' + +\ir ../create_k8s_policy_results.sql +\ir ./network_hardening.sql +\ir ./pod_security.sql diff --git a/plugins/source/k8s/policies_v1/policy.sql b/plugins/source/k8s/policies_v1/policy.sql new file mode 100644 index 00000000000000..86c1d88edf9ee4 --- /dev/null +++ b/plugins/source/k8s/policies_v1/policy.sql @@ -0,0 +1,11 @@ +\set ON_ERROR_STOP on +SET TIME ZONE 'UTC'; +-- neat trick to set execution_time if not already set +-- https://stackoverflow.com/questions/32582600/only-set-variable-in-psql-script-if-not-specified-on-the-command-line +\set execution_time :execution_time +SELECT CASE + WHEN :'execution_time' = ':execution_time' THEN to_char(now(), 'YYYY-MM-dd HH24:MI:SS.US') + ELSE :'execution_time' +END AS "execution_time" \gset + +\ir nsa_cisa_v1/policy.sql \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_cpu_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_cpu_limit.sql new file mode 100644 index 00000000000000..64d4bc87e0b979 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_cpu_limit.sql @@ -0,0 +1,25 @@ +-- Join every row in the daemonset table with its json array of containers. +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Daemonset enforces cpu limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a CPU limit for the check to pass + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'resources'->'limits'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets + diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_cpu_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_cpu_request.sql new file mode 100644 index 00000000000000..9597f259652c5c --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_cpu_request.sql @@ -0,0 +1,24 @@ +-- Join every row in the daemonset table with its json array of containers. +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Daemonset enforces cpu requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a CPU request for the check to pass + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'resources'->'requests'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_memory_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_memory_limit.sql new file mode 100644 index 00000000000000..30472a8eead96e --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_memory_limit.sql @@ -0,0 +1,24 @@ +-- Join every row in the daemonset table with its json array of containers. +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Daemonset enforces memory limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a Memory limit for the check to pass + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'resources'->'limits'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_memory_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_memory_request.sql new file mode 100644 index 00000000000000..c5ecd1b2239cd1 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/daemonset_memory_request.sql @@ -0,0 +1,24 @@ +-- Join every row in the daemonset table with its json array of containers. +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Daemonset enforces memory requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a Memory request for the check to pass + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'resources'->'requests'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_cpu_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_cpu_limit.sql new file mode 100644 index 00000000000000..6f055b7a0a2cc6 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_cpu_limit.sql @@ -0,0 +1,24 @@ +-- Join every row in the deployment table with its json array of containers. +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment enforces cpu limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a CPU limit for the check to pass + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'resources'->'limits'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_cpu_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_cpu_request.sql new file mode 100644 index 00000000000000..e8b10bc20d9f99 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_cpu_request.sql @@ -0,0 +1,24 @@ +-- Join every row in the deployment table with its json array of containers. +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment enforces cpu requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a CPU request for the check to pass + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'resources'->'requests'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_memory_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_memory_limit.sql new file mode 100644 index 00000000000000..bc5f5a3165c99b --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_memory_limit.sql @@ -0,0 +1,25 @@ +-- Join every row in the deployment table with its json array of containers. +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment enforces memory limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a Memory limit for the check to pass + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'resources'->'limits'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status + +FROM k8s_apps_deployments \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_memory_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_memory_request.sql new file mode 100644 index 00000000000000..ee89aa5ad728a6 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/deployment_memory_request.sql @@ -0,0 +1,24 @@ +-- Join every row in the deployment table with its json array of containers. +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment enforces memory requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a Memory request for the check to pass + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'resources'->'requests'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/job_cpu_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/job_cpu_limit.sql new file mode 100644 index 00000000000000..798e12594a774c --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/job_cpu_limit.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job enforces cpu limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'resources'->'limits'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/job_cpu_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/job_cpu_request.sql new file mode 100644 index 00000000000000..d3c7e6c8b789c7 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/job_cpu_request.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job enforces cpu requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'resources'->'requests'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/job_memory_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/job_memory_limit.sql new file mode 100644 index 00000000000000..fd185b024e30cd --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/job_memory_limit.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job enforces memory limit' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'resources'->'limits'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/job_memory_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/job_memory_request.sql new file mode 100644 index 00000000000000..05fa18faccf3a6 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/job_memory_request.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job enforces memory requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'resources'->'requests'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_cpu_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_cpu_limit.sql new file mode 100644 index 00000000000000..0d7a387a2743ed --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_cpu_limit.sql @@ -0,0 +1,24 @@ +WITH default_cpu_limits AS ( + SELECT context, namespace, value->'default'->>'cpu' AS default_cpu_limit + FROM k8s_core_limit_ranges CROSS JOIN jsonb_array_elements(k8s_core_limit_ranges.spec_limits)) + +INSERT +INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespaces CPU default resource limit' AS title, + context AS context, + name AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(default_cpu_limit) FROM default_cpu_limits + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_cpu_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_cpu_request.sql new file mode 100644 index 00000000000000..a07676e4808391 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_cpu_request.sql @@ -0,0 +1,24 @@ +WITH default_request_cpu_limits AS ( + SELECT context, namespace, value->'default_request'->>'cpu' AS default_request_cpu_limit + FROM k8s_core_limit_ranges CROSS JOIN jsonb_array_elements(k8s_core_limit_ranges.spec_limits)) + +INSERT +INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespaces CPU request resource quota' AS title, + context AS context, + name AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(default_request_cpu_limit) FROM default_request_cpu_limits + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_memory_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_memory_limit.sql new file mode 100644 index 00000000000000..8e1491d58c3f97 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_memory_limit.sql @@ -0,0 +1,24 @@ +WITH default_memory_limits AS ( + SELECT context, namespace, value->'default'->>'memory' AS default_memory_limit + FROM k8s_core_limit_ranges CROSS JOIN jsonb_array_elements(k8s_core_limit_ranges.spec_limits)) + +INSERT +INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespaces Memory default resource limit' AS title, + context AS context, + name AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(default_memory_limit) FROM default_memory_limits + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_memory_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_memory_request.sql new file mode 100644 index 00000000000000..0c96de6787f059 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_limit_range_default_memory_request.sql @@ -0,0 +1,26 @@ + + +WITH default_request_memory_limits AS ( + SELECT namespace, value->'default_request'->>'memory' AS default_request_memory_limit + FROM k8s_core_limit_ranges CROSS JOIN jsonb_array_elements(k8s_core_limit_ranges.spec_limits)) + +INSERT +INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespaces Memory request resource quota' AS title, + context AS context, + name AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(default_request_memory_limit) FROM default_request_memory_limits + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_cpu_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_cpu_limit.sql new file mode 100644 index 00000000000000..1124f35afdcc8d --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_cpu_limit.sql @@ -0,0 +1,20 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select DISTINCT (k8s_core_namespaces.uid) AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespace enforces resource quota cpu limits' AS title, + k8s_core_namespaces.context AS context, + k8s_core_namespaces.name AS namespace, + k8s_core_namespaces.name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM k8s_core_resource_quotas + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context + AND spec_hard->>'limits.cpu' IS NOT NULL) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_cpu_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_cpu_request.sql new file mode 100644 index 00000000000000..1ba018bda0aa89 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_cpu_request.sql @@ -0,0 +1,20 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select DISTINCT (k8s_core_namespaces.uid) AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespace enforces resource quota cpu request' AS title, + k8s_core_namespaces.context AS context, + k8s_core_namespaces.name AS namespace, + k8s_core_namespaces.name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM k8s_core_resource_quotas + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context + AND spec_hard->>'requests.cpu' IS NOT NULL) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_memory_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_memory_limit.sql new file mode 100644 index 00000000000000..ed23db9c6890d4 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_memory_limit.sql @@ -0,0 +1,20 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select DISTINCT (k8s_core_namespaces.uid) AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespace enforces resource quota memory limits' AS title, + k8s_core_namespaces.context AS context, + k8s_core_namespaces.name AS namespace, + k8s_core_namespaces.name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM k8s_core_resource_quotas + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context + AND spec_hard->>'limits.memory' IS NOT NULL) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_memory_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_memory_request.sql new file mode 100644 index 00000000000000..d9ae9d65fa830e --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/namespace_resource_quota_memory_request.sql @@ -0,0 +1,20 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select DISTINCT (k8s_core_namespaces.uid) AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Namespace enforces resource quota memory request' AS title, + k8s_core_namespaces.context AS context, + k8s_core_namespaces.name AS namespace, + k8s_core_namespaces.name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM k8s_core_resource_quotas + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context + AND spec_hard->>'requests.memory' IS NOT NULL) = 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_namespaces; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/network_policy_default_deny_egress.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/network_policy_default_deny_egress.sql new file mode 100644 index 00000000000000..9ecf9d6d9a0f68 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/network_policy_default_deny_egress.sql @@ -0,0 +1,23 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, +:'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Network policy default deny egress' AS title, + context AS context, + name AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM k8s_networking_network_policies + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context + AND spec_policy_types @> ARRAY['Egress'] + AND spec_pod_selector::TEXT = '{}' + AND ((spec_egress IS NULL) OR (JSONB_ARRAY_LENGTH(spec_egress) = 0))) = 0 + THEN 'fail' + ELSE 'pass' + END AS STATUS + +FROM k8s_core_namespaces \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/network_policy_default_deny_ingress.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/network_policy_default_deny_ingress.sql new file mode 100644 index 00000000000000..08c631d65a1abe --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/network_policy_default_deny_ingress.sql @@ -0,0 +1,23 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, +:'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Network policy default deny ingress' AS title, + context AS context, + name AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM k8s_networking_network_policies + WHERE namespace = k8s_core_namespaces.name + AND context = k8s_core_namespaces.context + AND spec_policy_types @> ARRAY['Ingress'] + AND spec_pod_selector::TEXT = '{}' + AND ((spec_ingress IS NULL) OR (JSONB_ARRAY_LENGTH(spec_ingress) = 0))) = 0 + THEN 'fail' + ELSE 'pass' + END AS STATUS + +FROM k8s_core_namespaces \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_cpu_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_cpu_limit.sql new file mode 100644 index 00000000000000..f85a5aa3de353d --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_cpu_limit.sql @@ -0,0 +1,24 @@ +-- Join every row in the replica_set table with its json array of containers. +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Replicaset enforces cpu limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a CPU limit for the check to pass + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'resources'->'limits'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_cpu_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_cpu_request.sql new file mode 100644 index 00000000000000..04be7198101c8a --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_cpu_request.sql @@ -0,0 +1,24 @@ +-- Join every row in the replica_set table with its json array of containers. +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Replicaset enforces cpu requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a CPU request for the check to pass + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'resources'->'requests'->>'cpu' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_memory_limit.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_memory_limit.sql new file mode 100644 index 00000000000000..50f0fa7bd1b92a --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_memory_limit.sql @@ -0,0 +1,24 @@ +-- Join every row in the replica_set table with its json array of containers. +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Replicaset enforces memory limits' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a memory limit for the check to pass + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'resources'->'limits'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_memory_request.sql b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_memory_request.sql new file mode 100644 index 00000000000000..7d90669ff1ae7d --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/network_hardening/replicaset_memory_request.sql @@ -0,0 +1,24 @@ +-- Join every row in the deployment table with its json array of containers. +With replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +Insert Into k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Replicaset enforces memory requests' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + -- Every container needs to have a memory request for the check to pass + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'resources'->'requests'->>'memory' IS NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_container_privilege_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_container_privilege_disabled.sql new file mode 100644 index 00000000000000..4ce9c75ac19c7f --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_container_privilege_disabled.sql @@ -0,0 +1,21 @@ +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'DaemonSet containers privileges disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'securityContext'->>'privileged' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_container_privilege_escalation_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_container_privilege_escalation_disabled.sql new file mode 100644 index 00000000000000..7da3b6484e3d33 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_container_privilege_escalation_disabled.sql @@ -0,0 +1,21 @@ +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'DaemonSet containers privilege escalation disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'securityContext'->>'allowPrivilegeEscalation' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_host_network_access_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_host_network_access_disabled.sql new file mode 100644 index 00000000000000..72226dac7a1d57 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_host_network_access_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deamonset container hostNetwork disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostNetwork' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_hostpid_hostipc_sharing_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_hostpid_hostipc_sharing_disabled.sql new file mode 100644 index 00000000000000..bbecd7801d630d --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_hostpid_hostipc_sharing_disabled.sql @@ -0,0 +1,18 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deamonset containers HostPID and HostIPC sharing disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostPID' = 'true' + OR spec_template -> 'spec' ->> 'hostIPC' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_immutable_container_filesystem.sql b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_immutable_container_filesystem.sql new file mode 100644 index 00000000000000..504646e22146fb --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_immutable_container_filesystem.sql @@ -0,0 +1,22 @@ +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'DeamonSet containers root file system is read-only' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'securityContext'->>'readOnlyRootFilesystem' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_non_root_container.sql b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_non_root_container.sql new file mode 100644 index 00000000000000..e420948919eca6 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/daemonset_non_root_container.sql @@ -0,0 +1,21 @@ +WITH daemonset_containers AS (SELECT uid, value AS container + FROM k8s_apps_daemon_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'DaemonSet containers to run as non-root' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM daemonset_containers WHERE daemonset_containers.uid = k8s_apps_daemon_sets.uid AND + daemonset_containers.container->'securityContext'->>'runAsNonRoot' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_daemon_sets; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/deployment_container_privilege_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_container_privilege_disabled.sql new file mode 100644 index 00000000000000..1719cf50f70be8 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_container_privilege_disabled.sql @@ -0,0 +1,21 @@ +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployments privileges disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'securityContext'->>'privileged' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/deployment_container_privilege_escalation_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_container_privilege_escalation_disabled.sql new file mode 100644 index 00000000000000..4edc5b12900ff3 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_container_privilege_escalation_disabled.sql @@ -0,0 +1,25 @@ +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployments privilege escalation disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'securityContext'->>'allowPrivilegeEscalation' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments; + + + + diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/deployment_host_network_access_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_host_network_access_disabled.sql new file mode 100644 index 00000000000000..52a28321535feb --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_host_network_access_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployments container hostNetwork disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostNetwork' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/deployment_hostpid_hostipc_sharing_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_hostpid_hostipc_sharing_disabled.sql new file mode 100644 index 00000000000000..a4e7ecc372b732 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_hostpid_hostipc_sharing_disabled.sql @@ -0,0 +1,18 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment containers HostPID and HostIPC sharing disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostPID' = 'true' + OR spec_template -> 'spec' ->> 'hostIPC' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/deployment_immutable_container_filesystem.sql b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_immutable_container_filesystem.sql new file mode 100644 index 00000000000000..ae7c91a5e339fa --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_immutable_container_filesystem.sql @@ -0,0 +1,22 @@ +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment containers root file system is read-only' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'securityContext'->>'readOnlyRootFilesystem' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments; + diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/deployment_non_root_container.sql b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_non_root_container.sql new file mode 100644 index 00000000000000..956c7399777cf2 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/deployment_non_root_container.sql @@ -0,0 +1,21 @@ +WITH deployment_containers AS (SELECT uid, value AS container + FROM k8s_apps_deployments + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Deployment containers to run as non-root' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM deployment_containers WHERE deployment_containers.uid = k8s_apps_deployments.uid AND + deployment_containers.container->'securityContext'->>'runAsNonRoot' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_deployments; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/job_container_privilege_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/job_container_privilege_disabled.sql new file mode 100644 index 00000000000000..e82b316b1e23f7 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/job_container_privilege_disabled.sql @@ -0,0 +1,23 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job containers privileges disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'securityContext'->>'privileged' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs + diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/job_container_privilege_escalation_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/job_container_privilege_escalation_disabled.sql new file mode 100644 index 00000000000000..41d1cb3ed33c95 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/job_container_privilege_escalation_disabled.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job containers privilege escalation disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'securityContext'->>'allowPrivilegeEscalation' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/job_host_network_access_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/job_host_network_access_disabled.sql new file mode 100644 index 00000000000000..082a765383c020 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/job_host_network_access_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Jobs container hostNetwork disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostNetwork' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/job_hostpid_hostipc_sharing_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/job_hostpid_hostipc_sharing_disabled.sql new file mode 100644 index 00000000000000..b71d18013d6431 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/job_hostpid_hostipc_sharing_disabled.sql @@ -0,0 +1,18 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job containers HostPID and HostIPC sharing disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostPID' = 'true' + OR spec_template -> 'spec' ->> 'hostIPC' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/job_immutable_container_filesystem.sql b/plugins/source/k8s/policies_v1/queries/pod_security/job_immutable_container_filesystem.sql new file mode 100644 index 00000000000000..b896d52640197a --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/job_immutable_container_filesystem.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job containers root file system is read-only' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'securityContext'->>'readOnlyRootFilesystem' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/job_non_root_container.sql b/plugins/source/k8s/policies_v1/queries/pod_security/job_non_root_container.sql new file mode 100644 index 00000000000000..6e0025608c6b02 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/job_non_root_container.sql @@ -0,0 +1,22 @@ +WITH job_containers AS (SELECT uid, value AS container + FROM k8s_batch_jobs + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Job containers run as non-root' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM job_containers WHERE job_containers.uid = k8s_batch_jobs.uid AND + job_containers.container->'securityContext'->>'runAsNonRoot' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_batch_jobs \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_container_privilege_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_container_privilege_disabled.sql new file mode 100644 index 00000000000000..4272261e165bbc --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_container_privilege_disabled.sql @@ -0,0 +1,22 @@ +WITH pod_containers AS (SELECT uid, value AS container + FROM k8s_core_pods + CROSS JOIN jsonb_array_elements(spec_containers) AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod container privileged access disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM pod_containers WHERE pod_containers.uid = k8s_core_pods.uid AND + pod_containers.container->'securityContext'->>'privileged' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; + diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_container_privilege_escalation_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_container_privilege_escalation_disabled.sql new file mode 100644 index 00000000000000..bb164d3bcfe194 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_container_privilege_escalation_disabled.sql @@ -0,0 +1,21 @@ +WITH pod_containers AS (SELECT uid, value AS container + FROM k8s_core_pods + CROSS JOIN jsonb_array_elements(spec_containers) AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod container privilege escalation disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM pod_containers WHERE pod_containers.uid = k8s_core_pods.uid AND + pod_containers.container->'securityContext'->>'allowPrivilegeEscalation' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_host_network_access_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_host_network_access_disabled.sql new file mode 100644 index 00000000000000..1260207c8ef5e6 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_host_network_access_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pods container hostNetwork disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_host_network + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_hostpid_hostipc_sharing_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_hostpid_hostipc_sharing_disabled.sql new file mode 100644 index 00000000000000..5ce9480d386dd7 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_hostpid_hostipc_sharing_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod containers HostPID and HostIPC sharing disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_host_pid OR spec_host_ipc + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_immutable_container_filesystem.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_immutable_container_filesystem.sql new file mode 100644 index 00000000000000..b8c6761b6b0f8f --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_immutable_container_filesystem.sql @@ -0,0 +1,21 @@ +WITH pod_containers AS (SELECT uid, value AS container + FROM k8s_core_pods + CROSS JOIN jsonb_array_elements(spec_containers) AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod container filesystem is read-ony' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM pod_containers WHERE pod_containers.uid = k8s_core_pods.uid AND + pod_containers.container->'securityContext'->>'readOnlyRootFilesystem' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_non_root_container.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_non_root_container.sql new file mode 100644 index 00000000000000..41d4c9e327c7fa --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_non_root_container.sql @@ -0,0 +1,21 @@ +WITH pod_containers AS (SELECT uid, value AS container + FROM k8s_core_pods + CROSS JOIN jsonb_array_elements(spec_containers) AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod container runs as non-root' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM pod_containers WHERE pod_containers.uid = k8s_core_pods.uid AND + pod_containers.container->'securityContext'->>'runAsNonRoot' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_service_account_token_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_service_account_token_disabled.sql new file mode 100644 index 00000000000000..2d4ea27f7d4206 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_service_account_token_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select DISTINCT uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod service account tokens disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_automount_service_account_token + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/pod_volume_host_path.sql b/plugins/source/k8s/policies_v1/queries/pod_security/pod_volume_host_path.sql new file mode 100644 index 00000000000000..2095fe71b96b42 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/pod_volume_host_path.sql @@ -0,0 +1,21 @@ +WITH pod_volumes AS (SELECT uid, value AS volumes + FROM k8s_core_pods + CROSS JOIN jsonb_array_elements(spec_volumes) AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod volume don''t have a hostPath' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM pod_volumes WHERE pod_volumes.uid = k8s_core_pods.uid AND + pod_volumes.volumes->>'hostPath' IS NOT NULL) > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_pods; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_container_privilege_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_container_privilege_disabled.sql new file mode 100644 index 00000000000000..3d21fad92ed9be --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_container_privilege_disabled.sql @@ -0,0 +1,22 @@ +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Replicaset privileges disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'securityContext'->>'privileged' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets; + diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_container_privilege_escalation_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_container_privilege_escalation_disabled.sql new file mode 100644 index 00000000000000..1cc00d6e8d44f1 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_container_privilege_escalation_disabled.sql @@ -0,0 +1,21 @@ +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'ReplicaSet container privileged escalation disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE WHEN + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'securityContext'->>'privileged' = 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_host_network_access_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_host_network_access_disabled.sql new file mode 100644 index 00000000000000..118c0ab183cbc9 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_host_network_access_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'ReplicaSet container hostNetwork disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostNetwork' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets; diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_hostpid_hostipc_sharing_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_hostpid_hostipc_sharing_disabled.sql new file mode 100644 index 00000000000000..2e8ccf8205901f --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_hostpid_hostipc_sharing_disabled.sql @@ -0,0 +1,18 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'ReplicaSet containers HostPID and HostIPC sharing disabled' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_template -> 'spec' ->> 'hostPID' = 'true' + OR spec_template -> 'spec' ->> 'hostIPC' = 'true' + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_immutable_container_filesystem.sql b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_immutable_container_filesystem.sql new file mode 100644 index 00000000000000..51a1e032f3197e --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_immutable_container_filesystem.sql @@ -0,0 +1,22 @@ +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'ReplicaSet containers root file system is read-only' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'securityContext' ->> 'readOnlyRootFilesystem' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_non_root_container.sql b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_non_root_container.sql new file mode 100644 index 00000000000000..f9b3dee2a56c61 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/replicaset_non_root_container.sql @@ -0,0 +1,22 @@ +WITH replica_set_containers AS (SELECT uid, value AS container + FROM k8s_apps_replica_sets + CROSS JOIN jsonb_array_elements(spec_template->'spec'->'containers') AS value) + +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'ReplicaSet containers must run as non-root' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + (SELECT COUNT(*) FROM replica_set_containers WHERE replica_set_containers.uid = k8s_apps_replica_sets.uid AND + replica_set_containers.container->'securityContext' ->> 'runAsNonRoot' IS DISTINCT FROM 'true') > 0 + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_apps_replica_sets; \ No newline at end of file diff --git a/plugins/source/k8s/policies_v1/queries/pod_security/service_account_token_disabled.sql b/plugins/source/k8s/policies_v1/queries/pod_security/service_account_token_disabled.sql new file mode 100644 index 00000000000000..6b3735f61c0fe2 --- /dev/null +++ b/plugins/source/k8s/policies_v1/queries/pod_security/service_account_token_disabled.sql @@ -0,0 +1,17 @@ +INSERT INTO k8s_policy_results (resource_id, execution_time, framework, check_id, title, context, namespace, + resource_name, status) +select DISTINCT uid AS resource_id, + :'execution_time'::timestamp AS execution_time, + :'framework' AS framework, + :'check_id' AS check_id, + 'Pod service account tokens disabled"' AS title, + context AS context, + namespace AS namespace, + name AS resource_name, + CASE + WHEN + spec_automount_service_account_token + THEN 'fail' + ELSE 'pass' + END AS status +FROM k8s_core_service_accounts