Last active
September 5, 2021 15:22
-
-
Save sebradloff/9b6f1a273328280533b4feaac12dd829 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: constraints.gatekeeper.sh/v1beta1 | |
kind: ApiGatewayIngressPath01 | |
metadata: | |
name: apigatewayingresspath01 | |
spec: | |
match: | |
kinds: | |
- apiGroups: | |
- networking.k8s.io | |
kinds: | |
- Ingress |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @title Enforce API Gateway Ingress path per service | |
# | |
# There should be one Ingress per service receiving requests at "/api/${resource}". | |
# We do not want seperate services serving traffic on the same top level path. | |
# We should not see "/api/foozles" and "/api/foozles/rejoice" serving traffic | |
# to two seperate services. | |
# | |
# @enforcement deny | |
# @kinds networking.k8s.io/Ingress | |
package api_gateway_ingress_path_01 | |
import data.lib.core | |
policyID := "P0005" | |
identical(obj, resource) { | |
obj.metadata.namespace == resource.metadata.namespace | |
obj.metadata.name == resource.metadata.name | |
} | |
paths_conflict(path1, path2) = result { | |
path1_sub_api := trim_prefix(path1, "/api/") | |
path2_sub_api := trim_prefix(path2, "/api/") | |
# split by '/' because the characted can not be interpreted by rego regex which uses re2 | |
# https://github.com/google/re2/wiki/Syntax | |
path1_arr := split(path1_sub_api, "/") | |
path2_arr := split(path2_sub_api, "/") | |
path1_arr_rsplit := regex.split("[^\\w|-]+", path1_arr[0]) | |
path2_arr_rsplit := regex.split("[^\\w|-]+", path2_arr[0]) | |
result := path1_arr_rsplit[0] == path2_arr_rsplit[0] | |
} | |
violation[msg] { | |
ns := data.inventory.cluster.v1.Namespace[_].metadata.name | |
other_ing := data.inventory.namespace[ns]["networking.k8s.io/v1"].Ingress[_] | |
curr_ing := core.resource | |
not identical(other_ing, curr_ing) | |
curr_ing_path := curr_ing.spec.rules[_].http.paths[_].path | |
other_ing_path := other_ing.spec.rules[_].http.paths[_].path | |
paths_conflict(curr_ing_path, other_ing_path) | |
msg := core.format_with_id(sprintf("%s/%s: http rule with path %s conflicts with %s/%s http rule path %s", [curr_ing.metadata.namespace, curr_ing.metadata.name, curr_ing_path, other_ing.metadata.namespace, other_ing.metadata.name, other_ing_path]), policyID) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package api_gateway_ingress_path_01 | |
test_paths_conflict_same_paths_returns_true { | |
test_paths := ["/api/foozles", "/api/foozles"] | |
results := paths_conflict(test_paths[0], test_paths[1]) | |
results == true | |
} | |
test_paths_conflict_same_root_path_returns_true { | |
test_paths := ["/api/foozles", "/api/foozles/bar"] | |
results := paths_conflict(test_paths[0], test_paths[1]) | |
results == true | |
} | |
test_paths_conflict_diff_root_path_returns_false { | |
test_paths := ["/api/foozles-bar", "/api/foozles/bar"] | |
results := paths_conflict(test_paths[0], test_paths[1]) | |
results == false | |
} | |
test_input_as_conflicting_ingresses_throws_violation { | |
cluster_inv := {"v1": {"Namespace": [create_namespace("default"), create_namespace("foo")]}} | |
ns_inv := {"foo": {"networking.k8s.io/v1": {"Ingress": [create_ingress("foozles", "foo", "/api/foozles(/|$)(.*)"), create_ingress("foo", "foo", "/api/foo(/|$)(.*)")]}}} | |
input := {"review": {"object": create_ingress("foozles-bar", "foo", "/api/foozles/bar(/|$)(.*)")}} | |
results := violation with input as input with data.inventory.cluster as cluster_inv with data.inventory.namespace as ns_inv | |
count(results) == 1 | |
} | |
test_input_non_conflicting_ingress_no_violations { | |
cluster_inv := {"v1": {"Namespace": [create_namespace("default"), create_namespace("foo"), create_namespace("bar")]}} | |
ns_inv := {"foo": {"networking.k8s.io/v1": {"Ingress": [create_ingress("foozles", "foo", "/api/foozles(/|$)(.*)"), create_ingress("foo", "foo", "/api/foo(/|$)(.*)")]}}} | |
input := {"review": {"object": create_ingress("bar", "bar", "/api/bar(/|$)(.*)")}} | |
results := violation with input as input with data.inventory.cluster as cluster_inv with data.inventory.namespace as ns_inv | |
count(results) == 0 | |
} | |
test_input_ingress_already_on_cluster_no_violation { | |
cluster_inv := {"v1": {"Namespace": [create_namespace("default"), create_namespace("foo")]}} | |
ns_inv := {"foo": {"networking.k8s.io/v1": {"Ingress": [create_ingress("foozles", "foo", "/api/foozles(/|$)(.*)"), create_ingress("foo", "foo", "/api/foo(/|$)(.*)")]}}} | |
input := {"review": {"object": create_ingress("foozles", "foo", "/api/foozles(/|$)(.*)")}} | |
results := violation with input as input with data.inventory.cluster as cluster_inv with data.inventory.namespace as ns_inv | |
count(results) == 0 | |
} | |
create_ingress(name, namespace, path) = ing { | |
ing := { | |
"apiVersion": "networking.k8s.io/v1", | |
"kind": "Ingress", | |
"metadata": { | |
"annotations": {"nginx.ingress.kubernetes.io/rewrite-target": "/$2"}, | |
"name": name, | |
"namespace": namespace, | |
}, | |
"spec": {"rules": [{"http": {"paths": [{ | |
"pathType": "Prefix", | |
"path": path, | |
"backend": {"service": { | |
"name": "foo", | |
"port": {"number": 80}, | |
}}, | |
}]}}]}, | |
} | |
} | |
create_namespace(name) = ns { | |
ns := { | |
"apiVersion": "v1", | |
"kind": "Namespace", | |
"metadata": {"name": name}, | |
"spec": {"finalizers": ["kubernetes"]}, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: templates.gatekeeper.sh/v1beta1 | |
kind: ConstraintTemplate | |
metadata: | |
creationTimestamp: null | |
name: apigatewayingresspath01 | |
spec: | |
crd: | |
spec: | |
names: | |
kind: ApiGatewayIngressPath01 | |
targets: | |
- libs: | |
- |- | |
package lib.core | |
default is_gatekeeper = false | |
is_gatekeeper { | |
has_field(input, "review") | |
has_field(input.review, "object") | |
} | |
resource = input.review.object { | |
is_gatekeeper | |
} | |
resource = input { | |
not is_gatekeeper | |
} | |
format(msg) = {"msg": msg} | |
format_with_id(msg, id) = msg_fmt { | |
msg_fmt := { | |
"msg": sprintf("%s: %s", [id, msg]), | |
"details": {"policyID": id}, | |
} | |
} | |
apiVersion = resource.apiVersion | |
name = resource.metadata.name | |
kind = resource.kind | |
labels = resource.metadata.labels | |
annotations = resource.metadata.annotations | |
gv := split(apiVersion, "/") | |
group = gv[0] { | |
contains(apiVersion, "/") | |
} | |
group = "core" { | |
not contains(apiVersion, "/") | |
} | |
version := gv[minus(count(gv), 1)] | |
has_field(obj, field) { | |
not object.get(obj, field, "N_DEFINED") == "N_DEFINED" | |
} | |
missing_field(obj, field) { | |
obj[field] == "" | |
} | |
missing_field(obj, field) { | |
not has_field(obj, field) | |
} | |
rego: |- | |
package api_gateway_ingress_path_01 | |
import data.lib.core | |
policyID := "P0005" | |
identical(obj, resource) { | |
obj.metadata.namespace == resource.metadata.namespace | |
obj.metadata.name == resource.metadata.name | |
} | |
paths_conflict(path1, path2) = result { | |
path1_sub_api := trim_prefix(path1, "/api/") | |
path2_sub_api := trim_prefix(path2, "/api/") | |
# split by '/' because the characted can not be interpreted by rego regex which uses re2 | |
# https://github.com/google/re2/wiki/Syntax | |
path1_arr := split(path1_sub_api, "/") | |
path2_arr := split(path2_sub_api, "/") | |
path1_arr_rsplit := regex.split("[^\\w|-]+", path1_arr[0]) | |
path2_arr_rsplit := regex.split("[^\\w|-]+", path2_arr[0]) | |
result := path1_arr_rsplit[0] == path2_arr_rsplit[0] | |
} | |
violation[msg] { | |
ns := data.inventory.cluster.v1.Namespace[_].metadata.name | |
other_ing := data.inventory.namespace[ns]["networking.k8s.io/v1"].Ingress[_] | |
curr_ing := core.resource | |
not identical(other_ing, curr_ing) | |
curr_ing_path := curr_ing.spec.rules[_].http.paths[_].path | |
other_ing_path := other_ing.spec.rules[_].http.paths[_].path | |
paths_conflict(curr_ing_path, other_ing_path) | |
msg := core.format_with_id(sprintf("%s/%s: http rule with path %s conflicts with %s/%s http rule path %s", [curr_ing.metadata.namespace, curr_ing.metadata.name, curr_ing_path, other_ing.metadata.namespace, other_ing.metadata.name, other_ing_path]), policyID) | |
} | |
target: admission.k8s.gatekeeper.sh | |
status: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: config.gatekeeper.sh/v1alpha1 | |
kind: Config | |
metadata: | |
name: config | |
namespace: gatekeeper-system | |
spec: | |
sync: | |
syncOnly: | |
- group: "networking.k8s.io" | |
version: "v1" | |
kind: "Ingress" | |
- group: "" | |
version: "v1" | |
kind: "Namespace" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: constraints.gatekeeper.sh/v1beta1 | |
kind: ContainerDenyWithoutResourceRequests01 | |
metadata: | |
name: containerdenywithoutresourcerequests01 | |
spec: | |
match: | |
kinds: | |
- apiGroups: | |
- "" | |
kinds: | |
- Pod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @title Containers must have resource requests | |
# | |
# All containers must have resource requests so the scheduler can better binpack each node. | |
# Reading on managing container resources: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | |
# | |
# @enforcement deny | |
# @kinds core/Pod | |
package container_deny_without_resource_requests_01 | |
import data.lib.core | |
import data.lib.pods | |
policyID := "P0003" | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_provided(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource requests cpu and memory must be specified", [core.kind, core.name, container.name]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_memory(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource memory requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.memory]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_cpu(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource cpu requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.cpu]), policyID) | |
} | |
container_requests_provided(container) { | |
container.resources.requests.cpu | |
container.resources.requests.memory | |
} | |
container_requests_zero_memory(container) { | |
not regex.match("^0.*", container.resources.requests.memory) | |
} | |
container_requests_zero_cpu(container) { | |
not regex.match("^0.*", container.resources.requests.cpu) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package container_deny_without_resource_requests_01 | |
test_input_as_pod_both_containers_missing_resource_requests { | |
c1_resources := {} | |
c2_resources := {} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 2 | |
} | |
test_input_as_pod_one_container_missing_resources { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 1 | |
} | |
test_input_as_pod_one_container_zero_cpu { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "0m", "memory": "100Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 1 | |
} | |
test_input_as_pod_one_container_zero_memory { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "10m", "memory": "0Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 1 | |
} | |
test_input_as_pod_one_container_zero_cpu_and_zero_memory { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "0m", "memory": "0Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 2 | |
} | |
test_input_as_pod_all_resource_requests_set_properly { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 0 | |
} | |
pod_input(c1_resources, c2_resources) = output { | |
output = { | |
"kind": "Pod", | |
"metadata": {"name": "test"}, | |
"spec": {"containers": [ | |
{ | |
"name": "test-1", | |
"image": "busybox", | |
"resources": c1_resources, | |
}, | |
{ | |
"name": "test-2", | |
"image": "busybox", | |
"resources": c2_resources, | |
}, | |
]}, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: templates.gatekeeper.sh/v1beta1 | |
kind: ConstraintTemplate | |
metadata: | |
creationTimestamp: null | |
name: containerdenywithoutresourcerequests01 | |
spec: | |
crd: | |
spec: | |
names: | |
kind: ContainerDenyWithoutResourceRequests01 | |
targets: | |
- libs: | |
- |- | |
package lib.core | |
default is_gatekeeper = false | |
is_gatekeeper { | |
has_field(input, "review") | |
has_field(input.review, "object") | |
} | |
resource = input.review.object { | |
is_gatekeeper | |
} | |
resource = input { | |
not is_gatekeeper | |
} | |
format(msg) = {"msg": msg} | |
format_with_id(msg, id) = msg_fmt { | |
msg_fmt := { | |
"msg": sprintf("%s: %s", [id, msg]), | |
"details": {"policyID": id}, | |
} | |
} | |
apiVersion = resource.apiVersion | |
name = resource.metadata.name | |
kind = resource.kind | |
labels = resource.metadata.labels | |
annotations = resource.metadata.annotations | |
gv := split(apiVersion, "/") | |
group = gv[0] { | |
contains(apiVersion, "/") | |
} | |
group = "core" { | |
not contains(apiVersion, "/") | |
} | |
version := gv[minus(count(gv), 1)] | |
has_field(obj, field) { | |
not object.get(obj, field, "N_DEFINED") == "N_DEFINED" | |
} | |
missing_field(obj, field) { | |
obj[field] == "" | |
} | |
missing_field(obj, field) { | |
not has_field(obj, field) | |
} | |
- |- | |
package lib.pods | |
import data.lib.core | |
default pod = false | |
pod = core.resource.spec.template { | |
pod_templates := ["daemonset", "deployment", "job", "replicaset", "replicationcontroller", "statefulset"] | |
lower(core.kind) == pod_templates[_] | |
} | |
pod = core.resource { | |
lower(core.kind) == "pod" | |
} | |
pod = core.resource.spec.jobTemplate.spec.template { | |
lower(core.kind) == "cronjob" | |
} | |
containers[container] { | |
keys = {"containers", "initContainers"} | |
all_containers = [c | keys[k]; c = pod.spec[k][_]] | |
container = all_containers[_] | |
} | |
volumes[volume] { | |
volume = pod.spec.volumes[_] | |
} | |
rego: |- | |
package container_deny_without_resource_requests_01 | |
import data.lib.core | |
import data.lib.pods | |
policyID := "P0003" | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_provided(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource requests cpu and memory must be specified", [core.kind, core.name, container.name]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_memory(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource memory requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.memory]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_cpu(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource cpu requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.cpu]), policyID) | |
} | |
container_requests_provided(container) { | |
container.resources.requests.cpu | |
container.resources.requests.memory | |
} | |
container_requests_zero_memory(container) { | |
not regex.match("^0.*", container.resources.requests.memory) | |
} | |
container_requests_zero_cpu(container) { | |
not regex.match("^0.*", container.resources.requests.cpu) | |
} | |
target: admission.k8s.gatekeeper.sh | |
status: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: constraints.gatekeeper.sh/v1beta1 | |
kind: ContainerDenyWithoutResourceRequests02 | |
metadata: | |
name: containerdenywithoutresourcerequests02 | |
spec: | |
match: | |
kinds: | |
- apiGroups: | |
- apps | |
- batch | |
- "" | |
kinds: | |
- DaemonSet | |
- Deployment | |
- StatefulSet | |
- CronJob | |
- Job | |
- Pod |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @title Containers must have resource requests | |
# | |
# All containers must have resource requests so the scheduler can better binpack each node. | |
# Reading on managing container resources: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ | |
# | |
# @enforcement deny | |
# @kinds apps/DaemonSet apps/Deployment apps/StatefulSet batch/CronJob batch/Job core/Pod | |
package container_deny_without_resource_requests_02 | |
import data.lib.core | |
import data.lib.pods | |
policyID := "P0004" | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_provided(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource requests cpu and memory must be specified", [core.kind, core.name, container.name]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_memory(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource memory requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.memory]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_cpu(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource cpu requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.cpu]), policyID) | |
} | |
container_requests_provided(container) { | |
container.resources.requests.cpu | |
container.resources.requests.memory | |
} | |
container_requests_zero_memory(container) { | |
not regex.match("^0.*", container.resources.requests.memory) | |
} | |
container_requests_zero_cpu(container) { | |
not regex.match("^0.*", container.resources.requests.cpu) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package container_deny_without_resource_requests_02 | |
test_input_as_pod_both_containers_missing_resource_requests { | |
c1_resources := {} | |
c2_resources := {} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 2 | |
} | |
test_input_as_pod_one_container_missing_resources { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 1 | |
} | |
test_input_as_pod_one_container_zero_cpu { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "0m", "memory": "100Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 1 | |
} | |
test_input_as_pod_one_container_zero_memory { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "10m", "memory": "0Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 1 | |
} | |
test_input_as_pod_one_container_zero_cpu_and_zero_memory { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "0m", "memory": "0Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 2 | |
} | |
test_input_as_pod_all_resource_requests_set_properly { | |
c1_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
c2_resources := {"requests": {"cpu": "10m", "memory": "100Mi"}} | |
input := {"review": {"object": pod_input(c1_resources, c2_resources)}} | |
results := violation with input as input | |
count(results) == 0 | |
} | |
pod_input(c1_resources, c2_resources) = output { | |
output = { | |
"kind": "Pod", | |
"metadata": {"name": "test"}, | |
"spec": {"containers": [ | |
{ | |
"name": "test-1", | |
"image": "busybox", | |
"resources": c1_resources, | |
}, | |
{ | |
"name": "test-2", | |
"image": "busybox", | |
"resources": c2_resources, | |
}, | |
]}, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: templates.gatekeeper.sh/v1beta1 | |
kind: ConstraintTemplate | |
metadata: | |
creationTimestamp: null | |
name: containerdenywithoutresourcerequests02 | |
spec: | |
crd: | |
spec: | |
names: | |
kind: ContainerDenyWithoutResourceRequests02 | |
targets: | |
- libs: | |
- |- | |
package lib.core | |
default is_gatekeeper = false | |
is_gatekeeper { | |
has_field(input, "review") | |
has_field(input.review, "object") | |
} | |
resource = input.review.object { | |
is_gatekeeper | |
} | |
resource = input { | |
not is_gatekeeper | |
} | |
format(msg) = {"msg": msg} | |
format_with_id(msg, id) = msg_fmt { | |
msg_fmt := { | |
"msg": sprintf("%s: %s", [id, msg]), | |
"details": {"policyID": id}, | |
} | |
} | |
apiVersion = resource.apiVersion | |
name = resource.metadata.name | |
kind = resource.kind | |
labels = resource.metadata.labels | |
annotations = resource.metadata.annotations | |
gv := split(apiVersion, "/") | |
group = gv[0] { | |
contains(apiVersion, "/") | |
} | |
group = "core" { | |
not contains(apiVersion, "/") | |
} | |
version := gv[minus(count(gv), 1)] | |
has_field(obj, field) { | |
not object.get(obj, field, "N_DEFINED") == "N_DEFINED" | |
} | |
missing_field(obj, field) { | |
obj[field] == "" | |
} | |
missing_field(obj, field) { | |
not has_field(obj, field) | |
} | |
- |- | |
package lib.pods | |
import data.lib.core | |
default pod = false | |
pod = core.resource.spec.template { | |
pod_templates := ["daemonset", "deployment", "job", "replicaset", "replicationcontroller", "statefulset"] | |
lower(core.kind) == pod_templates[_] | |
} | |
pod = core.resource { | |
lower(core.kind) == "pod" | |
} | |
pod = core.resource.spec.jobTemplate.spec.template { | |
lower(core.kind) == "cronjob" | |
} | |
containers[container] { | |
keys = {"containers", "initContainers"} | |
all_containers = [c | keys[k]; c = pod.spec[k][_]] | |
container = all_containers[_] | |
} | |
volumes[volume] { | |
volume = pod.spec.volumes[_] | |
} | |
rego: |- | |
package container_deny_without_resource_requests_02 | |
import data.lib.core | |
import data.lib.pods | |
policyID := "P0004" | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_provided(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource requests cpu and memory must be specified", [core.kind, core.name, container.name]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_memory(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource memory requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.memory]), policyID) | |
} | |
violation[msg] { | |
container := pods.containers[_] | |
not container_requests_zero_cpu(container) | |
msg := core.format_with_id(sprintf("%s/%s/%s: Container resource cpu requests can not have zero value (%s)", [core.kind, core.name, container.name, container.resources.requests.cpu]), policyID) | |
} | |
container_requests_provided(container) { | |
container.resources.requests.cpu | |
container.resources.requests.memory | |
} | |
container_requests_zero_memory(container) { | |
not regex.match("^0.*", container.resources.requests.memory) | |
} | |
container_requests_zero_cpu(container) { | |
not regex.match("^0.*", container.resources.requests.cpu) | |
} | |
target: admission.k8s.gatekeeper.sh | |
status: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: bar | |
spec: | |
replicas: 1 | |
selector: | |
matchLabels: | |
app: bar | |
template: | |
metadata: | |
labels: | |
app: bar | |
spec: | |
containers: | |
- name: bar | |
image: hashicorp/http-echo:0.2.3 | |
args: | |
- "-text=bar" | |
ports: | |
- containerPort: 5678 | |
resources: | |
requests: | |
cpu: 1m | |
memory: 10Mi | |
--- | |
apiVersion: v1 | |
kind: Service | |
metadata: | |
name: bar | |
spec: | |
ports: | |
- port: 80 | |
targetPort: 5678 | |
protocol: TCP | |
name: http | |
selector: | |
app: bar |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: foo | |
spec: | |
replicas: 1 | |
selector: | |
matchLabels: | |
app: foo | |
template: | |
metadata: | |
labels: | |
app: foo | |
spec: | |
containers: | |
- name: foo | |
image: hashicorp/http-echo:0.2.3 | |
args: | |
- "-text=foo" | |
ports: | |
- containerPort: 5678 | |
resources: | |
requests: | |
cpu: 1m | |
memory: 10Mi | |
--- | |
apiVersion: v1 | |
kind: Service | |
metadata: | |
name: foo | |
spec: | |
ports: | |
- port: 80 | |
targetPort: 5678 | |
protocol: TCP | |
name: http | |
selector: | |
app: foo |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: networking.k8s.io/v1 | |
kind: Ingress | |
metadata: | |
annotations: | |
nginx.ingress.kubernetes.io/rewrite-target: /$2 | |
name: foo | |
spec: | |
rules: | |
- http: | |
paths: | |
- pathType: Prefix | |
path: "/api/foozles(/|$)(.*)" | |
backend: | |
service: | |
name: foo | |
port: | |
number: 80 | |
--- | |
apiVersion: networking.k8s.io/v1 | |
kind: Ingress | |
metadata: | |
annotations: | |
nginx.ingress.kubernetes.io/rewrite-target: /$2 | |
name: bar | |
spec: | |
rules: | |
- http: | |
paths: | |
- pathType: Prefix | |
path: "/api/foozles/bar(/|$)(.*)" # will conflict with /api/foozles | |
backend: | |
service: | |
name: bar | |
port: | |
number: 80 | |
--- | |
apiVersion: networking.k8s.io/v1 | |
kind: Ingress | |
metadata: | |
annotations: | |
nginx.ingress.kubernetes.io/rewrite-target: /$2 | |
name: foozles-bar | |
spec: | |
rules: | |
- http: | |
paths: | |
- pathType: Prefix | |
path: "/api/foozles-bar(/|$)(.*)" # should not conflict | |
backend: | |
service: | |
name: foo | |
port: | |
number: 80 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: constraints.gatekeeper.sh/v1beta1 | |
kind: NamespaceTeamLabel01 | |
metadata: | |
name: namespaceteamlabel01 | |
spec: | |
match: | |
kinds: | |
- apiGroups: | |
- "" | |
kinds: | |
- Namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @title Namespaces must have a team label | |
# | |
# Required team label on all namespaces to determine ownership | |
# | |
# @enforcement deny | |
# @kinds core/Namespace | |
package namespace_team_label_01 | |
violation[{"msg": msg, "details": {}}] { | |
resource := input.review.object | |
not resource.metadata.labels.team | |
msg := sprintf("%s: Namespace does not have a required 'team' label", [resource.metadata.name]) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package namespace_team_label_01 | |
test_namespace_without_team_label_is_violation { | |
input := {"review": {"object": { | |
"kind": "Namespace", | |
"metadata": { | |
"labels": {"not": "important"}, | |
"name": "test", | |
}, | |
}}} | |
results := violation with input as input | |
count(results) > 0 | |
} | |
test_namespace_without_labels_is_violation { | |
input := {"review": {"object": { | |
"kind": "Namespace", | |
"metadata": {"name": "test"}, | |
}}} | |
results := violation with input as input | |
count(results) > 0 | |
} | |
test_namespace_with_team_label_is_not_violation { | |
input := {"review": {"object": { | |
"kind": "Namespace", | |
"metadata": { | |
"labels": {"team": "core"}, | |
"name": "test", | |
}, | |
}}} | |
results := violation with input as input | |
count(results) == 0 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: templates.gatekeeper.sh/v1beta1 | |
kind: ConstraintTemplate | |
metadata: | |
creationTimestamp: null | |
name: namespaceteamlabel01 | |
spec: | |
crd: | |
spec: | |
names: | |
kind: NamespaceTeamLabel01 | |
targets: | |
- rego: |- | |
package namespace_team_label_01 | |
violation[{"msg": msg, "details": {}}] { | |
resource := input.review.object | |
not resource.metadata.labels.team | |
msg := sprintf("%s: Namespace does not have a required 'team' label", [resource.metadata.name]) | |
} | |
target: admission.k8s.gatekeeper.sh | |
status: {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: constraints.gatekeeper.sh/v1beta1 | |
kind: NamespaceTeamLabel02 | |
metadata: | |
name: namespaceteamlabel02 | |
spec: | |
match: | |
kinds: | |
- apiGroups: | |
- "" | |
kinds: | |
- Namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# @title Namespaces must have a team label | |
# | |
# Required team label on all namespaces to determine ownership | |
# | |
# @enforcement deny | |
# @kinds core/Namespace | |
package namespace_team_label_02 | |
import data.lib.core | |
policyID := "P0002" | |
default has_team_label = false | |
has_team_label { | |
core.has_field(core.labels, "team") | |
} | |
violation[msg] { | |
not has_team_label | |
msg := core.format_with_id(sprintf("%s: Namespace does not have a required 'team' label", [core.name]), policyID) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package namespace_team_label_02 | |
test_namespace_without_team_label_is_violation { | |
input := {"review": {"object": { | |
"kind": "Namespace", | |
"metadata": { | |
"labels": {"not": "important"}, | |
"name": "test", | |
}, | |
}}} | |
results := violation with input as input | |
count(results) > 0 | |
} | |
test_namespace_without_labels_is_violation { | |
input := {"review": {"object": { | |
"kind": "Namespace", | |
"metadata": {"name": "test"}, | |
}}} | |
results := violation with input as input | |
count(results) > 0 | |
} | |
test_namespace_with_team_label_is_not_violation { | |
input := {"review": {"object": { | |
"kind": "Namespace", | |
"metadata": { | |
"labels": {"team": "core"}, | |
"name": "test", | |
}, | |
}}} | |
results := violation with input as input | |
count(results) == 0 | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: templates.gatekeeper.sh/v1beta1 | |
kind: ConstraintTemplate | |
metadata: | |
creationTimestamp: null | |
name: namespaceteamlabel02 | |
spec: | |
crd: | |
spec: | |
names: | |
kind: NamespaceTeamLabel02 | |
targets: | |
- libs: | |
- |- | |
package lib.core | |
default is_gatekeeper = false | |
is_gatekeeper { | |
has_field(input, "review") | |
has_field(input.review, "object") | |
} | |
resource = input.review.object { | |
is_gatekeeper | |
} | |
resource = input { | |
not is_gatekeeper | |
} | |
format(msg) = {"msg": msg} | |
format_with_id(msg, id) = msg_fmt { | |
msg_fmt := { | |
"msg": sprintf("%s: %s", [id, msg]), | |
"details": {"policyID": id}, | |
} | |
} | |
apiVersion = resource.apiVersion | |
name = resource.metadata.name | |
kind = resource.kind | |
labels = resource.metadata.labels | |
annotations = resource.metadata.annotations | |
gv := split(apiVersion, "/") | |
group = gv[0] { | |
contains(apiVersion, "/") | |
} | |
group = "core" { | |
not contains(apiVersion, "/") | |
} | |
version := gv[minus(count(gv), 1)] | |
has_field(obj, field) { | |
not object.get(obj, field, "N_DEFINED") == "N_DEFINED" | |
} | |
missing_field(obj, field) { | |
obj[field] == "" | |
} | |
missing_field(obj, field) { | |
not has_field(obj, field) | |
} | |
rego: |- | |
package namespace_team_label_02 | |
import data.lib.core | |
policyID := "P0002" | |
default has_team_label = false | |
has_team_label { | |
core.has_field(core.labels, "team") | |
} | |
violation[msg] { | |
not has_team_label | |
msg := core.format_with_id(sprintf("%s: Namespace does not have a required 'team' label", [core.name]), policyID) | |
} | |
target: admission.k8s.gatekeeper.sh | |
status: {} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment