From 6c3bfb9a1e356f8129e8c87c802bb3dff6a07af1 Mon Sep 17 00:00:00 2001 From: "Luke Mallon (Nalum)" Date: Wed, 8 Mar 2023 17:23:11 +0000 Subject: [PATCH 1/7] Setup the policy checking for secrets encryption / variable substitution Signed-off-by: Luke Mallon (Nalum) --- .../policy.rego | 57 ++++++++++++ .../policy.yaml | 88 +++++++++++++++++++ .../tests/secret.yaml | 8 ++ 3 files changed, 153 insertions(+) create mode 100644 policies/SecretEncryptionVariableSubstitution/policy.rego create mode 100644 policies/SecretEncryptionVariableSubstitution/policy.yaml create mode 100644 policies/SecretEncryptionVariableSubstitution/tests/secret.yaml diff --git a/policies/SecretEncryptionVariableSubstitution/policy.rego b/policies/SecretEncryptionVariableSubstitution/policy.rego new file mode 100644 index 00000000..c8f2f27d --- /dev/null +++ b/policies/SecretEncryptionVariableSubstitution/policy.rego @@ -0,0 +1,57 @@ +package weave.policies.secrets +import future.keywords.in + +exclude_namespaces := input.parameters.exclude_namespaces +exclude_label_key := input.parameters.exclude_label_key +exclude_label_value := input.parameters.exclude_label_value + +has_key(x, k) { + _ = x[k] +} + +isExcludedNamespace = true { + obj.metadata.namespace + obj.metadata.namespace in exclude_namespaces +} else = false + +obj = input.review.object + +enc_keys = [sprintf("data.%s", [key]) | + obj.data[key] + not startswith(obj.data[key], "ENC[") +] + +tpl_keys = [sprintf("data.%s", [key]) | + obj.data[key] + not startswith(obj.data[key], "${") +] + +violation[result] { + isExcludedNamespace == false + not exclude_label_value == obj.metadata.labels[exclude_label_key] + has_key(obj, "sops") + count(enc_keys) > 0 + + some key in enc_keys + + result = { + "issue_detected": true, + "msg": sprintf("Secret is either not encrypted or not using Flux Substitute Variables: %s", [key]), + "violating_key": key + } +} + +violation[result] { + isExcludedNamespace == false + not exclude_label_value == obj.metadata.labels[exclude_label_key] + not has_key(obj, "sops") + count(tpl_keys) > 0 + + some key in tpl_keys + + result = { + "issue_detected": true, + "msg": sprintf("Secret is either not encrypted or not using Flux Substitute Variables: %s", [key]), + "violating_key": key + } +} diff --git a/policies/SecretEncryptionVariableSubstitution/policy.yaml b/policies/SecretEncryptionVariableSubstitution/policy.yaml new file mode 100644 index 00000000..d9c35b8c --- /dev/null +++ b/policies/SecretEncryptionVariableSubstitution/policy.yaml @@ -0,0 +1,88 @@ +apiVersion: pac.weave.works/v2beta2 +kind: Policy +metadata: + name: weave.policies.secrets +spec: + id: weave.policies.secrets + name: Deny Secrets not Encrypted or not using Flux Variable Substitution + enabled: true + description: | + Checks the secrets in the repo to make sure there are none with unencrypted data or that Substitute Variables are used. + how_to_solve: | + Please recreate the secret data and encrypt the secret file using the appropriate commmands. + category: weave.categories.secrets + severity: critical + targets: + kinds: + - Secret + parameters: + - name: exclude_namespaces + type: array + required: false + value: + - name: exclude_label_key + type: string + required: false + value: weave.policies.secrets + - name: exclude_label_value + type: string + required: false + value: ignore + code: | + package weave.policies.secrets + import future.keywords.in + + exclude_namespaces := input.parameters.exclude_namespaces + exclude_label_key := input.parameters.exclude_label_key + exclude_label_value := input.parameters.exclude_label_value + + has_key(x, k) { + _ = x[k] + } + + isExcludedNamespace = true { + obj.metadata.namespace + obj.metadata.namespace in exclude_namespaces + } else = false + + obj = input.review.object + + enc_keys = [sprintf("data.%s", [key]) | + obj.data[key] + not startswith(obj.data[key], "ENC[") + ] + + tpl_keys = [sprintf("data.%s", [key]) | + obj.data[key] + not startswith(obj.data[key], "${") + ] + + violation[result] { + isExcludedNamespace == false + not exclude_label_value == obj.metadata.labels[exclude_label_key] + has_key(obj, "sops") + count(enc_keys) > 0 + + some key in enc_keys + + result = { + "issue_detected": true, + "msg": sprintf("Secret is either not encrypted or not using Flux Substitute Variables: %s", [key]), + "violating_key": key + } + } + + violation[result] { + isExcludedNamespace == false + not exclude_label_value == obj.metadata.labels[exclude_label_key] + not has_key(obj, "sops") + count(tpl_keys) > 0 + + some key in tpl_keys + + result = { + "issue_detected": true, + "msg": sprintf("Secret is either not encrypted or not using Flux Substitute Variables: %s", [key]), + "violating_key": key + } + } diff --git a/policies/SecretEncryptionVariableSubstitution/tests/secret.yaml b/policies/SecretEncryptionVariableSubstitution/tests/secret.yaml new file mode 100644 index 00000000..471af552 --- /dev/null +++ b/policies/SecretEncryptionVariableSubstitution/tests/secret.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +data: + testing-1: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= + testing-2: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= +kind: Secret +metadata: + name: testing +type: Opaque From af9be828fdeb9b73a85dd33542596cd28846cf35 Mon Sep 17 00:00:00 2001 From: "Luke Mallon (Nalum)" Date: Wed, 8 Mar 2023 17:57:20 +0000 Subject: [PATCH 2/7] Update tests Signed-off-by: Luke Mallon (Nalum) --- .../tests/enc-secret.yaml | 11 +++++++++++ .../tests/{secret.yaml => sub-secret.yaml} | 1 + 2 files changed, 12 insertions(+) create mode 100644 policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml rename policies/SecretEncryptionVariableSubstitution/tests/{secret.yaml => sub-secret.yaml} (85%) diff --git a/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml b/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml new file mode 100644 index 00000000..b0d5d9c0 --- /dev/null +++ b/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +data: + testing-1: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= + testing-2: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= + testing-3: ENC[aweqm] +kind: Secret +metadata: + name: testing +type: Opaque +sops: + sops-related-keys: true diff --git a/policies/SecretEncryptionVariableSubstitution/tests/secret.yaml b/policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml similarity index 85% rename from policies/SecretEncryptionVariableSubstitution/tests/secret.yaml rename to policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml index 471af552..821432ec 100644 --- a/policies/SecretEncryptionVariableSubstitution/tests/secret.yaml +++ b/policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml @@ -2,6 +2,7 @@ apiVersion: v1 data: testing-1: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= testing-2: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= + testing-3: ${VarForSub} kind: Secret metadata: name: testing From 58330982961c578010246b49460b7b7d0e405a37 Mon Sep 17 00:00:00 2001 From: "Luke Mallon (Nalum)" Date: Wed, 8 Mar 2023 17:59:48 +0000 Subject: [PATCH 3/7] Fix secrets so the policy passes Signed-off-by: Luke Mallon (Nalum) --- .../SecretEncryptionVariableSubstitution/tests/enc-secret.yaml | 2 -- .../SecretEncryptionVariableSubstitution/tests/sub-secret.yaml | 2 -- 2 files changed, 4 deletions(-) diff --git a/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml b/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml index b0d5d9c0..cde0f457 100644 --- a/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml +++ b/policies/SecretEncryptionVariableSubstitution/tests/enc-secret.yaml @@ -1,7 +1,5 @@ apiVersion: v1 data: - testing-1: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= - testing-2: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= testing-3: ENC[aweqm] kind: Secret metadata: diff --git a/policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml b/policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml index 821432ec..1cc15f42 100644 --- a/policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml +++ b/policies/SecretEncryptionVariableSubstitution/tests/sub-secret.yaml @@ -1,7 +1,5 @@ apiVersion: v1 data: - testing-1: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= - testing-2: RW5jcnlwdCB5b3Ugc2VjcmV0cwo= testing-3: ${VarForSub} kind: Secret metadata: From 68d9b4fb5ab869ba9612e3c23dcd94b63dd58991 Mon Sep 17 00:00:00 2001 From: github-actions Date: Wed, 8 Mar 2023 18:01:15 +0000 Subject: [PATCH 4/7] add auto-generated policies doc --- policies/policies.md | 3253 +++++++++++++++++++++--------------------- 1 file changed, 1640 insertions(+), 1613 deletions(-) diff --git a/policies/policies.md b/policies/policies.md index 80254142..4a096d0e 100644 --- a/policies/policies.md +++ b/policies/policies.md @@ -1,68 +1,52 @@ -## Prohibit Naked Pods From Being Scheduled +## Mongo-Express Enforce Environment Variable - ME_CONFIG_MONGODB_ADMINUSERNAME ### ID -weave.policies.prohibit-naked-pods-from-being-scheduled +weave.policies.mongo-express-enforce-admin-username-env-var ### Description -This Policy checks for a `kind` and can prohibit it from being schedule to your cluster. A common example is running "naked" pods. +This Policy ensures ME_CONFIG_MONGODB_ADMINUSERNAME environment variable are in place when using the official container images from Docker Hub. +ME_CONFIG_MONGODB_ADMINUSERNAME: The ME_CONFIG_MONGODB_ADMINUSERNAME environment variable sets the MongoDB admin username. ### How to solve? -Ensure you are not using a kind that is specified within the Policy. -``` -kind: -``` - -https://kubernetes.io/docs/concepts/configuration/overview/#naked-pods-vs-replicasets-deployments-and-jobs +If you encounter a violation, ensure the ME_CONFIG_MONGODB_ADMINUSERNAME environment variables is set. +For futher information about the Mongo-Express Docker container, check here: https://hub.docker.com/_/mongo-express ### Category -weave.categories.organizational-standards +weave.categories.access-control ### Severity -medium +high ### Targets -{'kinds': ['Pod']} +{'kinds': ['Deployment', 'Job', 'ReplicationController', 'ReplicaSet', 'DaemonSet', 'StatefulSet', 'CronJob']} ### Tags -['cis-benchmark'] +['pci-dss', 'mitre-attack', 'hipaa'] + +### Parameters +[{'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': None}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] --- -## Containers Sharing Host IPC +## MariaDB Enforce Environment Variable - MYSQL_DATABASE ### ID -weave.policies.containers-sharing-host-ipc +weave.policies.mariadb-enforce-mysql-database-env-var ### Description -This Policy allows check if sharing host IPC namespace with the container should be allowed or not. Resources that can be shared with the container include: - -### hostNetwork -Controls whether the pod may use the node network namespace. Doing so gives the pod access to the loopback device, services listening on localhost, and could be used to snoop on network activity of other pods on the same node. - -### hostPID -Controls whether the pod containers can share the host process ID namespace. Note that when paired with ptrace this can be used to escalate privileges outside of the container (ptrace is forbidden by default). - -### shareProcessNamespace -When process namespace sharing is enabled, processes in a container are visible to all other containers in that pod. - -### hostIPC -Controls whether the pod containers can share the host IPC namespace. +This Policy ensures MYSQL_DATABASE environment variable are in place when using the official container images from Docker Hub. +MYSQL_DATABASE: The MYSQL_DATABASE environment variable sets a default MARIADB database instance up with the name of that DB being the value of environment variable. ### How to solve? -Match the shared resource with either true or false, as set in your constraint. -``` -... - spec: - : -``` -https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces +If you encounter a violation, ensure the MYSQL_DATABASE environment variables is set. +For futher information about the MariaDB Docker container, check here: https://hub.docker.com/_/mariadb ### Category -weave.categories.pod-security +weave.categories.access-control ### Severity high @@ -71,30 +55,35 @@ high {'kinds': ['Deployment', 'Job', 'ReplicationController', 'ReplicaSet', 'DaemonSet', 'StatefulSet', 'CronJob']} ### Tags -['nist800-190', 'gdpr', 'default'] +['pci-dss', 'mitre-attack', 'hipaa', 'gdpr'] ### Parameters -[{'name': 'resource_enabled', 'type': 'boolean', 'required': True, 'value': False}, {'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': None}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] +[{'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': None}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] --- -## MongoDB Enforce Environment Variable - MONGO_INITDB_ROOT_PASSWORD_FILE +## Containers Missing Security Context ### ID -weave.policies.mongodb-enforce-root-password-file-env-var +weave.policies.containers-missing-security-context ### Description -This Policy ensures MONGO_INITDB_ROOT_PASSWORD_FILE environment variable are in place when using the official container images from Docker Hub. -MONGO_INITDB_ROOT_PASSWORD_FILE: The MONGO_INITDB_ROOT_PASSWORD_FILE environment variable is an alternative to passing sensitive information via environment variables, _FILE may be appended to the previously listed environment variables, causing the initialization script to load the values for those variables from files present in the container. +This Policy checks if the container is missing securityContext while there is no securityContext defined on the Pod level as well. The security settings that are specified on the Pod level apply to all containers in the Pod. ### How to solve? -If you encounter a violation, ensure the MONGO_INITDB_ROOT_PASSWORD_FILE environment variables is set. -For futher information about the MongoDB Docker container, check here: https://hub.docker.com/_/mariadb +Make sure you secure your containers by specifying a `securityContext` whether on each container or on the Pod level. The security settings that you specify on the Pod level apply to all containers in the Pod. +``` +... + spec: + securityContext: + +``` +https://kubernetes.io/docs/tasks/configure-pod-container/security-context/ ### Category -weave.categories.access-control +weave.categories.pod-security ### Severity high @@ -103,145 +92,97 @@ high {'kinds': ['Deployment', 'Job', 'ReplicationController', 'ReplicaSet', 'DaemonSet', 'StatefulSet', 'CronJob']} ### Tags -['pci-dss', 'mitre-attack', 'hipaa'] +['pci-dss', 'cis-benchmark', 'mitre-attack', 'nist800-190', 'gdpr', 'default'] ### Parameters -[{'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': None}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] +[{'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': ['kube-system']}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] --- -## Mongo-Express Enforce Environment Variable - ME_CONFIG_SITE_BASEURL +## Containers Minimum Replica Count ### ID -weave.policies.mongo-express-enforce-base-url-env-var +weave.policies.containers-minimum-replica-count ### Description -This Policy ensures ME_CONFIG_SITE_BASEURL environment variable are in place when using the official container images from Docker Hub. -ME_CONFIG_SITE_BASEURL: The ME_CONFIG_SITE_BASEURL environment variable sets the baseUrl to ease mounting at a subdirectory. Remember to include a leading and trailing slash. +Use this Policy to to check the replica count of your workloads. The value set in the Policy is greater than or equal to the amount desired, so if the replica count is lower than what is specified, the Policy will be in violation. ### How to solve? -If you encounter a violation, ensure the ME_CONFIG_SITE_BASEURL environment variables is set. -For futher information about the Mongo-Express Docker container, check here: https://hub.docker.com/_/mongo-express +The replica count should be a value equal or greater than what is set in the Policy. +``` +spec: + replicas: +``` +https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#scaling-a-deployment ### Category -weave.categories.network-security +weave.categories.reliability ### Severity -high +medium ### Targets -{'kinds': ['Deployment', 'Job', 'ReplicationController', 'ReplicaSet', 'DaemonSet', 'StatefulSet', 'CronJob']} +{'kinds': ['Deployment', 'StatefulSet', 'ReplicaSet', 'ReplicationController', 'HorizontalPodAutoscaler']} ### Tags -['pci-dss'] +['soc2-type1'] ### Parameters -[{'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': None}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] +[{'name': 'replica_count', 'type': 'integer', 'required': True, 'value': 2}, {'name': 'exclude_namespaces', 'type': 'array', 'required': False, 'value': None}, {'name': 'exclude_label_key', 'type': 'string', 'required': False, 'value': None}, {'name': 'exclude_label_value', 'type': 'string', 'required': False, 'value': None}] --- -## Missing Kubernetes App Part Of Label +## MariaDB Enforce Environment Variable - MYSQL_ROOT_PASSWORD ### ID -weave.policies.missing-kubernetes-app-part-of-label +weave.policies.mariadb-enforce-mysql-root-password-env-var ### Description -Custom labels can help enforce organizational standards for each artifact deployed. This Policy ensure a custom label key is set in the entity's `metadata`. The Policy detects the presence of the following: - -### owner -A label key of `owner` will help identify who the owner of this entity is. - -### app.kubernetes.io/name -The name of the application - -### app.kubernetes.io/instance -A unique name identifying the instance of an application - -### app.kubernetes.io/version -The current version of the application (e.g., a semantic version, revision hash, etc.) - -### app.kubernetes.io/part-of -The name of a higher level application this one is part of - -### app.kubernetes.io/managed-by -The tool being used to manage the operation of an application - -### app.kubernetes.io/created-by -The controller/user who created this resource +This Policy ensures MYSQL_ROOT_PASSWORD environment variable are in place when using the official container images from Docker Hub. +MYSQL_ROOT_PASSWORD: The MYSQL_ROOT_PASSWORD environment variable specifies a password for the MARIADB root account. ### How to solve? -Add these custom labels to `metadata`. -* owner -* app.kubernetes.io/name -* app.kubernetes.io/instance -* app.kubernetes.io/version -* app.kubernetes.io/name -* app.kubernetes.io/part-of -* app.kubernetes.io/managed-by -* app.kubernetes.io/created-by - -``` -metadata: - labels: -