From bb44c88e2f3c05df8c22fcd870d2a4a48d2e86f9 Mon Sep 17 00:00:00 2001 From: rmccright-ms3 Date: Fri, 27 Aug 2021 15:14:19 -0400 Subject: [PATCH] OPA Gatekeeper with Base Pos Security Policies --- playbooks/provision_playbook.yaml | 5 + roles/opa_gatekeeper/files/helmrepo.yaml | 8 ++ roles/opa_gatekeeper/files/kustomization.yaml | 7 ++ roles/opa_gatekeeper/files/ns.yaml | 4 + .../policies/capabilities/constraint.yaml | 17 +++ .../files/policies/capabilities/template.yaml | 67 +++++++++++ .../forbidden-sysctls/constraint.yaml | 15 +++ .../policies/forbidden-sysctls/template.yaml | 39 +++++++ .../policies/host-filesystem/constraint.yaml | 16 +++ .../policies/host-filesystem/template.yaml | 106 ++++++++++++++++++ .../policies/host-namespaces/constraint.yaml | 13 +++ .../policies/host-namespaces/template.yaml | 25 +++++ .../host-network-ports/constraint.yaml | 19 ++++ .../policies/host-network-ports/template.yaml | 48 ++++++++ .../files/policies/kustomization.yaml | 15 +++ .../privileged-containers/constraint.yaml | 14 +++ .../privileged-containers/template.yaml | 26 +++++ roles/opa_gatekeeper/files/release.yaml | 23 ++++ roles/opa_gatekeeper/tasks/main.yaml | 39 +++++++ .../templates/flux-kustomization.j2 | 14 +++ .../flux-system/watches/opa-gatekeeper.yaml | 14 +++ .../platform/opa-gatekeeper/helmrepo.yaml | 8 ++ .../opa-gatekeeper/kustomization.yaml | 7 ++ .../platform/opa-gatekeeper/ns.yaml | 4 + .../policies/capabilities/constraint.yaml | 17 +++ .../policies/capabilities/template.yaml | 67 +++++++++++ .../forbidden-sysctls/constraint.yaml | 15 +++ .../policies/forbidden-sysctls/template.yaml | 39 +++++++ .../policies/host-filesystem/constraint.yaml | 16 +++ .../policies/host-filesystem/template.yaml | 106 ++++++++++++++++++ .../policies/host-namespaces/constraint.yaml | 13 +++ .../policies/host-namespaces/template.yaml | 25 +++++ .../host-network-ports/constraint.yaml | 19 ++++ .../policies/host-network-ports/template.yaml | 48 ++++++++ .../policies/kustomization.yaml | 15 +++ .../privileged-containers/constraint.yaml | 14 +++ .../privileged-containers/template.yaml | 26 +++++ .../platform/opa-gatekeeper/release.yaml | 23 ++++ .../flux-system/watches/opa-gatekeeper.yaml | 14 +++ .../platform/opa-gatekeeper/helmrepo.yaml | 8 ++ .../opa-gatekeeper/kustomization.yaml | 7 ++ .../platform/opa-gatekeeper/ns.yaml | 4 + .../policies/capabilities/constraint.yaml | 17 +++ .../policies/capabilities/template.yaml | 67 +++++++++++ .../forbidden-sysctls/constraint.yaml | 15 +++ .../policies/forbidden-sysctls/template.yaml | 39 +++++++ .../policies/host-filesystem/constraint.yaml | 16 +++ .../policies/host-filesystem/template.yaml | 106 ++++++++++++++++++ .../policies/host-namespaces/constraint.yaml | 13 +++ .../policies/host-namespaces/template.yaml | 25 +++++ .../host-network-ports/constraint.yaml | 19 ++++ .../policies/host-network-ports/template.yaml | 48 ++++++++ .../policies/kustomization.yaml | 15 +++ .../privileged-containers/constraint.yaml | 14 +++ .../privileged-containers/template.yaml | 26 +++++ .../platform/opa-gatekeeper/release.yaml | 23 ++++ 56 files changed, 1472 insertions(+) create mode 100644 roles/opa_gatekeeper/files/helmrepo.yaml create mode 100644 roles/opa_gatekeeper/files/kustomization.yaml create mode 100644 roles/opa_gatekeeper/files/ns.yaml create mode 100644 roles/opa_gatekeeper/files/policies/capabilities/constraint.yaml create mode 100644 roles/opa_gatekeeper/files/policies/capabilities/template.yaml create mode 100644 roles/opa_gatekeeper/files/policies/forbidden-sysctls/constraint.yaml create mode 100644 roles/opa_gatekeeper/files/policies/forbidden-sysctls/template.yaml create mode 100644 roles/opa_gatekeeper/files/policies/host-filesystem/constraint.yaml create mode 100644 roles/opa_gatekeeper/files/policies/host-filesystem/template.yaml create mode 100644 roles/opa_gatekeeper/files/policies/host-namespaces/constraint.yaml create mode 100644 roles/opa_gatekeeper/files/policies/host-namespaces/template.yaml create mode 100644 roles/opa_gatekeeper/files/policies/host-network-ports/constraint.yaml create mode 100644 roles/opa_gatekeeper/files/policies/host-network-ports/template.yaml create mode 100644 roles/opa_gatekeeper/files/policies/kustomization.yaml create mode 100644 roles/opa_gatekeeper/files/policies/privileged-containers/constraint.yaml create mode 100644 roles/opa_gatekeeper/files/policies/privileged-containers/template.yaml create mode 100644 roles/opa_gatekeeper/files/release.yaml create mode 100644 roles/opa_gatekeeper/tasks/main.yaml create mode 100644 roles/opa_gatekeeper/templates/flux-kustomization.j2 create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/flux-system/watches/opa-gatekeeper.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/helmrepo.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/kustomization.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/ns.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/kustomization.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/release.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/flux-system/watches/opa-gatekeeper.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/helmrepo.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/kustomization.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/ns.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/kustomization.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml create mode 100644 tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/release.yaml diff --git a/playbooks/provision_playbook.yaml b/playbooks/provision_playbook.yaml index c5d16d5d..3a321ae4 100644 --- a/playbooks/provision_playbook.yaml +++ b/playbooks/provision_playbook.yaml @@ -20,6 +20,11 @@ name: ms3_inc.tavros.fluxtoolkit tags: [ fluxtoolkit ] + - name: Opa Gatekeeper + include_role: + name: ms3_inc.tavros.opa_gatekeeper + tags: [ opa_gatekeeper ] + - name: sealed-secrets include_role: name: ms3_inc.tavros.sealed_secrets diff --git a/roles/opa_gatekeeper/files/helmrepo.yaml b/roles/opa_gatekeeper/files/helmrepo.yaml new file mode 100644 index 00000000..24e242e5 --- /dev/null +++ b/roles/opa_gatekeeper/files/helmrepo.yaml @@ -0,0 +1,8 @@ +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmRepository +metadata: + name: opa-gatekeeper + namespace: flux-system +spec: + interval: 10m + url: https://open-policy-agent.github.io/gatekeeper/charts \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/kustomization.yaml b/roles/opa_gatekeeper/files/kustomization.yaml new file mode 100644 index 00000000..5c54f6b2 --- /dev/null +++ b/roles/opa_gatekeeper/files/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ns.yaml + - helmrepo.yaml + - release.yaml + - policies/ \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/ns.yaml b/roles/opa_gatekeeper/files/ns.yaml new file mode 100644 index 00000000..89ef3f26 --- /dev/null +++ b/roles/opa_gatekeeper/files/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gatekeeper-system diff --git a/roles/opa_gatekeeper/files/policies/capabilities/constraint.yaml b/roles/opa_gatekeeper/files/policies/capabilities/constraint.yaml new file mode 100644 index 00000000..3389d995 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/capabilities/constraint.yaml @@ -0,0 +1,17 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPCapabilities +metadata: + name: capabilities-demo +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + parameters: + allowedCapabilities: + - NET_ADMIN + requiredDropCapabilities: [] diff --git a/roles/opa_gatekeeper/files/policies/capabilities/template.yaml b/roles/opa_gatekeeper/files/policies/capabilities/template.yaml new file mode 100644 index 00000000..9fa16be7 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/capabilities/template.yaml @@ -0,0 +1,67 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspcapabilities + annotations: + description: Controls Linux capabilities. +spec: + crd: + spec: + names: + kind: K8sPSPCapabilities + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedCapabilities: + type: array + items: + type: string + requiredDropCapabilities: + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package capabilities + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + has_disallowed_capabilities(container) + msg := sprintf("container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + missing_drop_capabilities(container) + msg := sprintf("container <%v> is not dropping all required capabilities. Container must drop all of %v", [container.name, input.parameters.requiredDropCapabilities]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + has_disallowed_capabilities(container) + msg := sprintf("init container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + missing_drop_capabilities(container) + msg := sprintf("init container <%v> is not dropping all required capabilities. Container must drop all of %v", [container.name, input.parameters.requiredDropCapabilities]) + } + has_disallowed_capabilities(container) { + allowed := {c | c := input.parameters.allowedCapabilities[_]} + not allowed["*"] + capabilities := {c | c := container.securityContext.capabilities.add[_]} + count(capabilities - allowed) > 0 + } + missing_drop_capabilities(container) { + must_drop := {c | c := input.parameters.requiredDropCapabilities[_]} + dropped := {c | c := container.securityContext.capabilities.drop[_]} + count(must_drop - dropped) > 0 + } + get_default(obj, param, _default) = out { + out = obj[param] + } + get_default(obj, param, _default) = out { + not obj[param] + not obj[param] == false + out = _default + } \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/forbidden-sysctls/constraint.yaml b/roles/opa_gatekeeper/files/policies/forbidden-sysctls/constraint.yaml new file mode 100644 index 00000000..d87bada7 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/forbidden-sysctls/constraint.yaml @@ -0,0 +1,15 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPForbiddenSysctls +metadata: + name: psp-forbidden-sysctls +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + parameters: + forbiddenSysctls: + - "*" # * may be used to forbid all sysctls + # - kernel.* \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/forbidden-sysctls/template.yaml b/roles/opa_gatekeeper/files/policies/forbidden-sysctls/template.yaml new file mode 100644 index 00000000..e72aa230 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/forbidden-sysctls/template.yaml @@ -0,0 +1,39 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspforbiddensysctls + annotations: + description: Controls the `sysctl` profile used by containers. +spec: + crd: + spec: + names: + kind: K8sPSPForbiddenSysctls + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + forbiddenSysctls: + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspforbiddensysctls + violation[{"msg": msg, "details": {}}] { + sysctl := input.review.object.spec.securityContext.sysctls[_].name + forbidden_sysctl(sysctl) + msg := sprintf("The sysctl %v is not allowed, pod: %v. Forbidden sysctls: %v", [sysctl, input.review.object.metadata.name, input.parameters.forbiddenSysctls]) + } + # * may be used to forbid all sysctls + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == "*" + } + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == sysctl + } + forbidden_sysctl(sysctl) { + startswith(sysctl, trim(input.parameters.forbiddenSysctls[_], "*")) + } \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/host-filesystem/constraint.yaml b/roles/opa_gatekeeper/files/policies/host-filesystem/constraint.yaml new file mode 100644 index 00000000..776f9e36 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/host-filesystem/constraint.yaml @@ -0,0 +1,16 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostFilesystem +metadata: + name: psp-host-filesystem +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - elastic-system + - kube-system + parameters: + allowedHostPaths: [] \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/host-filesystem/template.yaml b/roles/opa_gatekeeper/files/policies/host-filesystem/template.yaml new file mode 100644 index 00000000..6d1f676d --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/host-filesystem/template.yaml @@ -0,0 +1,106 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostfilesystem + annotations: + description: Controls usage of the host filesystem. +spec: + crd: + spec: + names: + kind: K8sPSPHostFilesystem + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedHostPaths: + type: array + items: + type: object + properties: + readOnly: + type: boolean + pathPrefix: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostfilesystem + violation[{"msg": msg, "details": {}}] { + volume := input_hostpath_volumes[_] + allowedPaths := get_allowed_paths(input) + input_hostpath_violation(allowedPaths, volume) + msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) + } + input_hostpath_violation(allowedPaths, volume) { + # An empty list means all host paths are blocked + allowedPaths == [] + } + input_hostpath_violation(allowedPaths, volume) { + not input_hostpath_allowed(allowedPaths, volume) + } + get_allowed_paths(arg) = out { + not arg.parameters + out = [] + } + get_allowed_paths(arg) = out { + not arg.parameters.allowedHostPaths + out = [] + } + get_allowed_paths(arg) = out { + out = arg.parameters.allowedHostPaths + } + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + not allowedHostPath.readOnly == true + } + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + allowedHostPath.readOnly + not writeable_input_volume_mounts(volume.name) + } + writeable_input_volume_mounts(volume_name) { + container := input_containers[_] + mount := container.volumeMounts[_] + mount.name == volume_name + not mount.readOnly + } + # This allows "/foo", "/foo/", "/foo/bar" etc., but + # disallows "/fool", "/etc/foo" etc. + path_matches(prefix, path) { + a := path_array(prefix) + b := path_array(path) + prefix_matches(a, b) + } + path_array(p) = out { + p != "/" + out := split(trim(p, "/"), "/") + } + # This handles the special case for "/", since + # split(trim("/", "/"), "/") == [""] + path_array("/") = [] + prefix_matches(a, b) { + count(a) <= count(b) + not any_not_equal_upto(a, b, count(a)) + } + any_not_equal_upto(a, b, n) { + a[i] != b[i] + i < n + } + input_hostpath_volumes[v] { + v := input.review.object.spec.volumes[_] + has_field(v, "hostPath") + } + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/host-namespaces/constraint.yaml b/roles/opa_gatekeeper/files/policies/host-namespaces/constraint.yaml new file mode 100644 index 00000000..8b5378f4 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/host-namespaces/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNamespace +metadata: + name: psp-host-namespace +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/host-namespaces/template.yaml b/roles/opa_gatekeeper/files/policies/host-namespaces/template.yaml new file mode 100644 index 00000000..7cbd259a --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/host-namespaces/template.yaml @@ -0,0 +1,25 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnamespace + annotations: + description: Controls usage of host namespaces. +spec: + crd: + spec: + names: + kind: K8sPSPHostNamespace + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnamespace + violation[{"msg": msg, "details": {}}] { + input_share_hostnamespace(input.review.object) + msg := sprintf("Sharing the host namespace is not allowed: %v", [input.review.object.metadata.name]) + } + input_share_hostnamespace(o) { + o.spec.hostPID + } + input_share_hostnamespace(o) { + o.spec.hostIPC + } \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/host-network-ports/constraint.yaml b/roles/opa_gatekeeper/files/policies/host-network-ports/constraint.yaml new file mode 100644 index 00000000..0a4566c3 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/host-network-ports/constraint.yaml @@ -0,0 +1,19 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNetworkingPorts +metadata: + name: psp-host-network-ports +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + - elastic-system + - jaeger + parameters: + hostNetwork: false + min: 0 + max: 0 \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/host-network-ports/template.yaml b/roles/opa_gatekeeper/files/policies/host-network-ports/template.yaml new file mode 100644 index 00000000..8407e3e9 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/host-network-ports/template.yaml @@ -0,0 +1,48 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnetworkingports + annotations: + description: Controls usage of host networking and ports. +spec: + crd: + spec: + names: + kind: K8sPSPHostNetworkingPorts + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + hostNetwork: + type: boolean + min: + type: integer + max: + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnetworkingports + violation[{"msg": msg, "details": {}}] { + input_share_hostnetwork(input.review.object) + msg := sprintf("The specified hostNetwork and hostPort are not allowed, pod: %v. Allowed values: %v", [input.review.object.metadata.name, input.parameters]) + } + input_share_hostnetwork(o) { + not input.parameters.hostNetwork + o.spec.hostNetwork + } + input_share_hostnetwork(o) { + hostPort := input_containers[_].ports[_].hostPort + hostPort < input.parameters.min + } + input_share_hostnetwork(o) { + hostPort := input_containers[_].ports[_].hostPort + hostPort > input.parameters.max + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } \ No newline at end of file diff --git a/roles/opa_gatekeeper/files/policies/kustomization.yaml b/roles/opa_gatekeeper/files/policies/kustomization.yaml new file mode 100644 index 00000000..0c01d6d8 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - privileged-containers/template.yaml + - privileged-containers/constraint.yaml + - host-filesystem/template.yaml + - host-filesystem/constraint.yaml + - capabilities/template.yaml + - capabilities/constraint.yaml + - host-network-ports/template.yaml + - host-network-ports/constraint.yaml + - host-namespaces/template.yaml + - host-namespaces/constraint.yaml + - forbidden-sysctls/template.yaml + - forbidden-sysctls/constraint.yaml diff --git a/roles/opa_gatekeeper/files/policies/privileged-containers/constraint.yaml b/roles/opa_gatekeeper/files/policies/privileged-containers/constraint.yaml new file mode 100644 index 00000000..3a2e35f7 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/privileged-containers/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPPrivilegedContainer +metadata: + name: psp-privileged-container +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + - elastic-system diff --git a/roles/opa_gatekeeper/files/policies/privileged-containers/template.yaml b/roles/opa_gatekeeper/files/policies/privileged-containers/template.yaml new file mode 100644 index 00000000..30952456 --- /dev/null +++ b/roles/opa_gatekeeper/files/policies/privileged-containers/template.yaml @@ -0,0 +1,26 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspprivilegedcontainer + annotations: + description: Controls running of privileged containers. +spec: + crd: + spec: + names: + kind: K8sPSPPrivilegedContainer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspprivileged + violation[{"msg": msg, "details": {}}] { + c := input_containers[_] + c.securityContext.privileged + msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext]) + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } diff --git a/roles/opa_gatekeeper/files/release.yaml b/roles/opa_gatekeeper/files/release.yaml new file mode 100644 index 00000000..25efa250 --- /dev/null +++ b/roles/opa_gatekeeper/files/release.yaml @@ -0,0 +1,23 @@ +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: tavros + namespace: gatekeeper-system +spec: + targetNamespace: gatekeeper-system + interval: 10m + chart: + spec: + # https://github.com/open-policy-agent/gatekeeper/blob/master/charts/gatekeeper/values.yaml + chart: gatekeeper + version: 3.5.2 + sourceRef: + kind: HelmRepository + name: opa-gatekeeper + namespace: flux-system + install: + remediation: + retries: 5 + upgrade: + remediation: + retries: 5 diff --git a/roles/opa_gatekeeper/tasks/main.yaml b/roles/opa_gatekeeper/tasks/main.yaml new file mode 100644 index 00000000..7da51f8d --- /dev/null +++ b/roles/opa_gatekeeper/tasks/main.yaml @@ -0,0 +1,39 @@ +--- +- name: Create Directory + file: + path: /tmp/{{ cluster_fqdn }}/platform/opa-gatekeeper + state: directory + tags: [ opa_gatekeeper ] + +- name: Copy Files + copy: + src: "{{ item.name }}" + dest: /tmp/{{ cluster_fqdn }}/platform/opa-gatekeeper/{{ item.dest | default(item.name) }} + when: item.condition | default(true) + loop: + - name: kustomization.yaml + - name: ns.yaml + - name: helmrepo.yaml + - name: release.yaml + - name: policies + dest: "" + tags: [ opa_gatekeeper ] + +- name: Apply Resources + tags: [ requires_cluster, opa_gatekeeper ] + when: ('dry-run' not in ansible_run_tags) + loop: "{{ lookup('ms3_inc.tavros.kustomize', '/tmp/' + cluster_fqdn + '/platform/opa-gatekeeper/', reorder='none') }}" + loop_control: + label: "{{ item.kind }}/{{ item.metadata.name | default('unnamed')}}" + ms3_inc.tavros.kube: + kubeconfig: '~/.kube/config' + definition: "{{ item }}" + wait: true + wait_condition: "{{ wait_conditions[item.kind] | default(omit) }}" + wait_timeout: 900 + +- name: Template flux-kustomization + template: + src: flux-kustomization.j2 + dest: /tmp/{{ cluster_fqdn }}/platform/flux-system/watches/opa-gatekeeper.yaml + tags: [ opa_gatekeeper ] diff --git a/roles/opa_gatekeeper/templates/flux-kustomization.j2 b/roles/opa_gatekeeper/templates/flux-kustomization.j2 new file mode 100644 index 00000000..d20f9945 --- /dev/null +++ b/roles/opa_gatekeeper/templates/flux-kustomization.j2 @@ -0,0 +1,14 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 +kind: Kustomization +metadata: + name: opa-gatekeeper + namespace: flux-system +spec: + interval: 5m0s + path: ./platform/opa-gatekeeper + sourceRef: + kind: GitRepository + name: tavros + validation: client + prune: true + timeout: 5m0s diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/flux-system/watches/opa-gatekeeper.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/flux-system/watches/opa-gatekeeper.yaml new file mode 100644 index 00000000..d20f9945 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/flux-system/watches/opa-gatekeeper.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 +kind: Kustomization +metadata: + name: opa-gatekeeper + namespace: flux-system +spec: + interval: 5m0s + path: ./platform/opa-gatekeeper + sourceRef: + kind: GitRepository + name: tavros + validation: client + prune: true + timeout: 5m0s diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/helmrepo.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/helmrepo.yaml new file mode 100644 index 00000000..24e242e5 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/helmrepo.yaml @@ -0,0 +1,8 @@ +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmRepository +metadata: + name: opa-gatekeeper + namespace: flux-system +spec: + interval: 10m + url: https://open-policy-agent.github.io/gatekeeper/charts \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/kustomization.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/kustomization.yaml new file mode 100644 index 00000000..5c54f6b2 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ns.yaml + - helmrepo.yaml + - release.yaml + - policies/ \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/ns.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/ns.yaml new file mode 100644 index 00000000..89ef3f26 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gatekeeper-system diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml new file mode 100644 index 00000000..3389d995 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml @@ -0,0 +1,17 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPCapabilities +metadata: + name: capabilities-demo +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + parameters: + allowedCapabilities: + - NET_ADMIN + requiredDropCapabilities: [] diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml new file mode 100644 index 00000000..9fa16be7 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml @@ -0,0 +1,67 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspcapabilities + annotations: + description: Controls Linux capabilities. +spec: + crd: + spec: + names: + kind: K8sPSPCapabilities + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedCapabilities: + type: array + items: + type: string + requiredDropCapabilities: + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package capabilities + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + has_disallowed_capabilities(container) + msg := sprintf("container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + missing_drop_capabilities(container) + msg := sprintf("container <%v> is not dropping all required capabilities. Container must drop all of %v", [container.name, input.parameters.requiredDropCapabilities]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + has_disallowed_capabilities(container) + msg := sprintf("init container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + missing_drop_capabilities(container) + msg := sprintf("init container <%v> is not dropping all required capabilities. Container must drop all of %v", [container.name, input.parameters.requiredDropCapabilities]) + } + has_disallowed_capabilities(container) { + allowed := {c | c := input.parameters.allowedCapabilities[_]} + not allowed["*"] + capabilities := {c | c := container.securityContext.capabilities.add[_]} + count(capabilities - allowed) > 0 + } + missing_drop_capabilities(container) { + must_drop := {c | c := input.parameters.requiredDropCapabilities[_]} + dropped := {c | c := container.securityContext.capabilities.drop[_]} + count(must_drop - dropped) > 0 + } + get_default(obj, param, _default) = out { + out = obj[param] + } + get_default(obj, param, _default) = out { + not obj[param] + not obj[param] == false + out = _default + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml new file mode 100644 index 00000000..d87bada7 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml @@ -0,0 +1,15 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPForbiddenSysctls +metadata: + name: psp-forbidden-sysctls +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + parameters: + forbiddenSysctls: + - "*" # * may be used to forbid all sysctls + # - kernel.* \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml new file mode 100644 index 00000000..e72aa230 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml @@ -0,0 +1,39 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspforbiddensysctls + annotations: + description: Controls the `sysctl` profile used by containers. +spec: + crd: + spec: + names: + kind: K8sPSPForbiddenSysctls + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + forbiddenSysctls: + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspforbiddensysctls + violation[{"msg": msg, "details": {}}] { + sysctl := input.review.object.spec.securityContext.sysctls[_].name + forbidden_sysctl(sysctl) + msg := sprintf("The sysctl %v is not allowed, pod: %v. Forbidden sysctls: %v", [sysctl, input.review.object.metadata.name, input.parameters.forbiddenSysctls]) + } + # * may be used to forbid all sysctls + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == "*" + } + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == sysctl + } + forbidden_sysctl(sysctl) { + startswith(sysctl, trim(input.parameters.forbiddenSysctls[_], "*")) + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml new file mode 100644 index 00000000..776f9e36 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml @@ -0,0 +1,16 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostFilesystem +metadata: + name: psp-host-filesystem +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - elastic-system + - kube-system + parameters: + allowedHostPaths: [] \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml new file mode 100644 index 00000000..6d1f676d --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml @@ -0,0 +1,106 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostfilesystem + annotations: + description: Controls usage of the host filesystem. +spec: + crd: + spec: + names: + kind: K8sPSPHostFilesystem + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedHostPaths: + type: array + items: + type: object + properties: + readOnly: + type: boolean + pathPrefix: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostfilesystem + violation[{"msg": msg, "details": {}}] { + volume := input_hostpath_volumes[_] + allowedPaths := get_allowed_paths(input) + input_hostpath_violation(allowedPaths, volume) + msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) + } + input_hostpath_violation(allowedPaths, volume) { + # An empty list means all host paths are blocked + allowedPaths == [] + } + input_hostpath_violation(allowedPaths, volume) { + not input_hostpath_allowed(allowedPaths, volume) + } + get_allowed_paths(arg) = out { + not arg.parameters + out = [] + } + get_allowed_paths(arg) = out { + not arg.parameters.allowedHostPaths + out = [] + } + get_allowed_paths(arg) = out { + out = arg.parameters.allowedHostPaths + } + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + not allowedHostPath.readOnly == true + } + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + allowedHostPath.readOnly + not writeable_input_volume_mounts(volume.name) + } + writeable_input_volume_mounts(volume_name) { + container := input_containers[_] + mount := container.volumeMounts[_] + mount.name == volume_name + not mount.readOnly + } + # This allows "/foo", "/foo/", "/foo/bar" etc., but + # disallows "/fool", "/etc/foo" etc. + path_matches(prefix, path) { + a := path_array(prefix) + b := path_array(path) + prefix_matches(a, b) + } + path_array(p) = out { + p != "/" + out := split(trim(p, "/"), "/") + } + # This handles the special case for "/", since + # split(trim("/", "/"), "/") == [""] + path_array("/") = [] + prefix_matches(a, b) { + count(a) <= count(b) + not any_not_equal_upto(a, b, count(a)) + } + any_not_equal_upto(a, b, n) { + a[i] != b[i] + i < n + } + input_hostpath_volumes[v] { + v := input.review.object.spec.volumes[_] + has_field(v, "hostPath") + } + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml new file mode 100644 index 00000000..8b5378f4 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNamespace +metadata: + name: psp-host-namespace +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml new file mode 100644 index 00000000..7cbd259a --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml @@ -0,0 +1,25 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnamespace + annotations: + description: Controls usage of host namespaces. +spec: + crd: + spec: + names: + kind: K8sPSPHostNamespace + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnamespace + violation[{"msg": msg, "details": {}}] { + input_share_hostnamespace(input.review.object) + msg := sprintf("Sharing the host namespace is not allowed: %v", [input.review.object.metadata.name]) + } + input_share_hostnamespace(o) { + o.spec.hostPID + } + input_share_hostnamespace(o) { + o.spec.hostIPC + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml new file mode 100644 index 00000000..0a4566c3 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml @@ -0,0 +1,19 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNetworkingPorts +metadata: + name: psp-host-network-ports +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + - elastic-system + - jaeger + parameters: + hostNetwork: false + min: 0 + max: 0 \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml new file mode 100644 index 00000000..8407e3e9 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml @@ -0,0 +1,48 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnetworkingports + annotations: + description: Controls usage of host networking and ports. +spec: + crd: + spec: + names: + kind: K8sPSPHostNetworkingPorts + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + hostNetwork: + type: boolean + min: + type: integer + max: + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnetworkingports + violation[{"msg": msg, "details": {}}] { + input_share_hostnetwork(input.review.object) + msg := sprintf("The specified hostNetwork and hostPort are not allowed, pod: %v. Allowed values: %v", [input.review.object.metadata.name, input.parameters]) + } + input_share_hostnetwork(o) { + not input.parameters.hostNetwork + o.spec.hostNetwork + } + input_share_hostnetwork(o) { + hostPort := input_containers[_].ports[_].hostPort + hostPort < input.parameters.min + } + input_share_hostnetwork(o) { + hostPort := input_containers[_].ports[_].hostPort + hostPort > input.parameters.max + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/kustomization.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/kustomization.yaml new file mode 100644 index 00000000..0c01d6d8 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - privileged-containers/template.yaml + - privileged-containers/constraint.yaml + - host-filesystem/template.yaml + - host-filesystem/constraint.yaml + - capabilities/template.yaml + - capabilities/constraint.yaml + - host-network-ports/template.yaml + - host-network-ports/constraint.yaml + - host-namespaces/template.yaml + - host-namespaces/constraint.yaml + - forbidden-sysctls/template.yaml + - forbidden-sysctls/constraint.yaml diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml new file mode 100644 index 00000000..3a2e35f7 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPPrivilegedContainer +metadata: + name: psp-privileged-container +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + - elastic-system diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml new file mode 100644 index 00000000..30952456 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml @@ -0,0 +1,26 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspprivilegedcontainer + annotations: + description: Controls running of privileged containers. +spec: + crd: + spec: + names: + kind: K8sPSPPrivilegedContainer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspprivileged + violation[{"msg": msg, "details": {}}] { + c := input_containers[_] + c.securityContext.privileged + msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext]) + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } diff --git a/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/release.yaml b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/release.yaml new file mode 100644 index 00000000..25efa250 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/enterprise-example.com/platform/opa-gatekeeper/release.yaml @@ -0,0 +1,23 @@ +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: tavros + namespace: gatekeeper-system +spec: + targetNamespace: gatekeeper-system + interval: 10m + chart: + spec: + # https://github.com/open-policy-agent/gatekeeper/blob/master/charts/gatekeeper/values.yaml + chart: gatekeeper + version: 3.5.2 + sourceRef: + kind: HelmRepository + name: opa-gatekeeper + namespace: flux-system + install: + remediation: + retries: 5 + upgrade: + remediation: + retries: 5 diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/flux-system/watches/opa-gatekeeper.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/flux-system/watches/opa-gatekeeper.yaml new file mode 100644 index 00000000..d20f9945 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/flux-system/watches/opa-gatekeeper.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.toolkit.fluxcd.io/v1beta1 +kind: Kustomization +metadata: + name: opa-gatekeeper + namespace: flux-system +spec: + interval: 5m0s + path: ./platform/opa-gatekeeper + sourceRef: + kind: GitRepository + name: tavros + validation: client + prune: true + timeout: 5m0s diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/helmrepo.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/helmrepo.yaml new file mode 100644 index 00000000..24e242e5 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/helmrepo.yaml @@ -0,0 +1,8 @@ +apiVersion: source.toolkit.fluxcd.io/v1beta1 +kind: HelmRepository +metadata: + name: opa-gatekeeper + namespace: flux-system +spec: + interval: 10m + url: https://open-policy-agent.github.io/gatekeeper/charts \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/kustomization.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/kustomization.yaml new file mode 100644 index 00000000..5c54f6b2 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/kustomization.yaml @@ -0,0 +1,7 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - ns.yaml + - helmrepo.yaml + - release.yaml + - policies/ \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/ns.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/ns.yaml new file mode 100644 index 00000000..89ef3f26 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/ns.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: gatekeeper-system diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml new file mode 100644 index 00000000..3389d995 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/constraint.yaml @@ -0,0 +1,17 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPCapabilities +metadata: + name: capabilities-demo +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + parameters: + allowedCapabilities: + - NET_ADMIN + requiredDropCapabilities: [] diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml new file mode 100644 index 00000000..9fa16be7 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/capabilities/template.yaml @@ -0,0 +1,67 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspcapabilities + annotations: + description: Controls Linux capabilities. +spec: + crd: + spec: + names: + kind: K8sPSPCapabilities + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedCapabilities: + type: array + items: + type: string + requiredDropCapabilities: + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package capabilities + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + has_disallowed_capabilities(container) + msg := sprintf("container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.containers[_] + missing_drop_capabilities(container) + msg := sprintf("container <%v> is not dropping all required capabilities. Container must drop all of %v", [container.name, input.parameters.requiredDropCapabilities]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + has_disallowed_capabilities(container) + msg := sprintf("init container <%v> has a disallowed capability. Allowed capabilities are %v", [container.name, get_default(input.parameters, "allowedCapabilities", "NONE")]) + } + violation[{"msg": msg}] { + container := input.review.object.spec.initContainers[_] + missing_drop_capabilities(container) + msg := sprintf("init container <%v> is not dropping all required capabilities. Container must drop all of %v", [container.name, input.parameters.requiredDropCapabilities]) + } + has_disallowed_capabilities(container) { + allowed := {c | c := input.parameters.allowedCapabilities[_]} + not allowed["*"] + capabilities := {c | c := container.securityContext.capabilities.add[_]} + count(capabilities - allowed) > 0 + } + missing_drop_capabilities(container) { + must_drop := {c | c := input.parameters.requiredDropCapabilities[_]} + dropped := {c | c := container.securityContext.capabilities.drop[_]} + count(must_drop - dropped) > 0 + } + get_default(obj, param, _default) = out { + out = obj[param] + } + get_default(obj, param, _default) = out { + not obj[param] + not obj[param] == false + out = _default + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml new file mode 100644 index 00000000..d87bada7 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/constraint.yaml @@ -0,0 +1,15 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPForbiddenSysctls +metadata: + name: psp-forbidden-sysctls +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + parameters: + forbiddenSysctls: + - "*" # * may be used to forbid all sysctls + # - kernel.* \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml new file mode 100644 index 00000000..e72aa230 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/forbidden-sysctls/template.yaml @@ -0,0 +1,39 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspforbiddensysctls + annotations: + description: Controls the `sysctl` profile used by containers. +spec: + crd: + spec: + names: + kind: K8sPSPForbiddenSysctls + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + forbiddenSysctls: + type: array + items: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspforbiddensysctls + violation[{"msg": msg, "details": {}}] { + sysctl := input.review.object.spec.securityContext.sysctls[_].name + forbidden_sysctl(sysctl) + msg := sprintf("The sysctl %v is not allowed, pod: %v. Forbidden sysctls: %v", [sysctl, input.review.object.metadata.name, input.parameters.forbiddenSysctls]) + } + # * may be used to forbid all sysctls + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == "*" + } + forbidden_sysctl(sysctl) { + input.parameters.forbiddenSysctls[_] == sysctl + } + forbidden_sysctl(sysctl) { + startswith(sysctl, trim(input.parameters.forbiddenSysctls[_], "*")) + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml new file mode 100644 index 00000000..776f9e36 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/constraint.yaml @@ -0,0 +1,16 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostFilesystem +metadata: + name: psp-host-filesystem +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - elastic-system + - kube-system + parameters: + allowedHostPaths: [] \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml new file mode 100644 index 00000000..6d1f676d --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-filesystem/template.yaml @@ -0,0 +1,106 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostfilesystem + annotations: + description: Controls usage of the host filesystem. +spec: + crd: + spec: + names: + kind: K8sPSPHostFilesystem + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + allowedHostPaths: + type: array + items: + type: object + properties: + readOnly: + type: boolean + pathPrefix: + type: string + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostfilesystem + violation[{"msg": msg, "details": {}}] { + volume := input_hostpath_volumes[_] + allowedPaths := get_allowed_paths(input) + input_hostpath_violation(allowedPaths, volume) + msg := sprintf("HostPath volume %v is not allowed, pod: %v. Allowed path: %v", [volume, input.review.object.metadata.name, allowedPaths]) + } + input_hostpath_violation(allowedPaths, volume) { + # An empty list means all host paths are blocked + allowedPaths == [] + } + input_hostpath_violation(allowedPaths, volume) { + not input_hostpath_allowed(allowedPaths, volume) + } + get_allowed_paths(arg) = out { + not arg.parameters + out = [] + } + get_allowed_paths(arg) = out { + not arg.parameters.allowedHostPaths + out = [] + } + get_allowed_paths(arg) = out { + out = arg.parameters.allowedHostPaths + } + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + not allowedHostPath.readOnly == true + } + input_hostpath_allowed(allowedPaths, volume) { + allowedHostPath := allowedPaths[_] + path_matches(allowedHostPath.pathPrefix, volume.hostPath.path) + allowedHostPath.readOnly + not writeable_input_volume_mounts(volume.name) + } + writeable_input_volume_mounts(volume_name) { + container := input_containers[_] + mount := container.volumeMounts[_] + mount.name == volume_name + not mount.readOnly + } + # This allows "/foo", "/foo/", "/foo/bar" etc., but + # disallows "/fool", "/etc/foo" etc. + path_matches(prefix, path) { + a := path_array(prefix) + b := path_array(path) + prefix_matches(a, b) + } + path_array(p) = out { + p != "/" + out := split(trim(p, "/"), "/") + } + # This handles the special case for "/", since + # split(trim("/", "/"), "/") == [""] + path_array("/") = [] + prefix_matches(a, b) { + count(a) <= count(b) + not any_not_equal_upto(a, b, count(a)) + } + any_not_equal_upto(a, b, n) { + a[i] != b[i] + i < n + } + input_hostpath_volumes[v] { + v := input.review.object.spec.volumes[_] + has_field(v, "hostPath") + } + # has_field returns whether an object has a field + has_field(object, field) = true { + object[field] + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml new file mode 100644 index 00000000..8b5378f4 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/constraint.yaml @@ -0,0 +1,13 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNamespace +metadata: + name: psp-host-namespace +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml new file mode 100644 index 00000000..7cbd259a --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-namespaces/template.yaml @@ -0,0 +1,25 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnamespace + annotations: + description: Controls usage of host namespaces. +spec: + crd: + spec: + names: + kind: K8sPSPHostNamespace + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnamespace + violation[{"msg": msg, "details": {}}] { + input_share_hostnamespace(input.review.object) + msg := sprintf("Sharing the host namespace is not allowed: %v", [input.review.object.metadata.name]) + } + input_share_hostnamespace(o) { + o.spec.hostPID + } + input_share_hostnamespace(o) { + o.spec.hostIPC + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml new file mode 100644 index 00000000..0a4566c3 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/constraint.yaml @@ -0,0 +1,19 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPHostNetworkingPorts +metadata: + name: psp-host-network-ports +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + - elastic-system + - jaeger + parameters: + hostNetwork: false + min: 0 + max: 0 \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml new file mode 100644 index 00000000..8407e3e9 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/host-network-ports/template.yaml @@ -0,0 +1,48 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spsphostnetworkingports + annotations: + description: Controls usage of host networking and ports. +spec: + crd: + spec: + names: + kind: K8sPSPHostNetworkingPorts + validation: + # Schema for the `parameters` field + openAPIV3Schema: + type: object + properties: + hostNetwork: + type: boolean + min: + type: integer + max: + type: integer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spsphostnetworkingports + violation[{"msg": msg, "details": {}}] { + input_share_hostnetwork(input.review.object) + msg := sprintf("The specified hostNetwork and hostPort are not allowed, pod: %v. Allowed values: %v", [input.review.object.metadata.name, input.parameters]) + } + input_share_hostnetwork(o) { + not input.parameters.hostNetwork + o.spec.hostNetwork + } + input_share_hostnetwork(o) { + hostPort := input_containers[_].ports[_].hostPort + hostPort < input.parameters.min + } + input_share_hostnetwork(o) { + hostPort := input_containers[_].ports[_].hostPort + hostPort > input.parameters.max + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } \ No newline at end of file diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/kustomization.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/kustomization.yaml new file mode 100644 index 00000000..0c01d6d8 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/kustomization.yaml @@ -0,0 +1,15 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization +resources: + - privileged-containers/template.yaml + - privileged-containers/constraint.yaml + - host-filesystem/template.yaml + - host-filesystem/constraint.yaml + - capabilities/template.yaml + - capabilities/constraint.yaml + - host-network-ports/template.yaml + - host-network-ports/constraint.yaml + - host-namespaces/template.yaml + - host-namespaces/constraint.yaml + - forbidden-sysctls/template.yaml + - forbidden-sysctls/constraint.yaml diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml new file mode 100644 index 00000000..3a2e35f7 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/constraint.yaml @@ -0,0 +1,14 @@ +apiVersion: constraints.gatekeeper.sh/v1beta1 +kind: K8sPSPPrivilegedContainer +metadata: + name: psp-privileged-container +spec: + match: + kinds: + - apiGroups: + - "" + kinds: + - Pod + excludedNamespaces: + - kube-system + - elastic-system diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml new file mode 100644 index 00000000..30952456 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/policies/privileged-containers/template.yaml @@ -0,0 +1,26 @@ +apiVersion: templates.gatekeeper.sh/v1beta1 +kind: ConstraintTemplate +metadata: + name: k8spspprivilegedcontainer + annotations: + description: Controls running of privileged containers. +spec: + crd: + spec: + names: + kind: K8sPSPPrivilegedContainer + targets: + - target: admission.k8s.gatekeeper.sh + rego: | + package k8spspprivileged + violation[{"msg": msg, "details": {}}] { + c := input_containers[_] + c.securityContext.privileged + msg := sprintf("Privileged container is not allowed: %v, securityContext: %v", [c.name, c.securityContext]) + } + input_containers[c] { + c := input.review.object.spec.containers[_] + } + input_containers[c] { + c := input.review.object.spec.initContainers[_] + } diff --git a/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/release.yaml b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/release.yaml new file mode 100644 index 00000000..25efa250 --- /dev/null +++ b/tests/integration/targets/playbooks/provision_playbook/example.com/platform/opa-gatekeeper/release.yaml @@ -0,0 +1,23 @@ +apiVersion: helm.toolkit.fluxcd.io/v2beta1 +kind: HelmRelease +metadata: + name: tavros + namespace: gatekeeper-system +spec: + targetNamespace: gatekeeper-system + interval: 10m + chart: + spec: + # https://github.com/open-policy-agent/gatekeeper/blob/master/charts/gatekeeper/values.yaml + chart: gatekeeper + version: 3.5.2 + sourceRef: + kind: HelmRepository + name: opa-gatekeeper + namespace: flux-system + install: + remediation: + retries: 5 + upgrade: + remediation: + retries: 5