459 lines
17 KiB
YAML
459 lines
17 KiB
YAML
apiVersion: policy.open-cluster-management.io/v1
|
|
kind: Policy
|
|
metadata:
|
|
name: policy-gatekeeper-livenessprobe
|
|
annotations:
|
|
policy.open-cluster-management.io/standards: NIST SP 800-53
|
|
policy.open-cluster-management.io/categories: CM Configuration Management
|
|
policy.open-cluster-management.io/controls: CM-2 Baseline Configuration
|
|
spec:
|
|
remediationAction: enforce
|
|
disabled: false
|
|
policy-templates:
|
|
- objectDefinition:
|
|
apiVersion: policy.open-cluster-management.io/v1
|
|
kind: ConfigurationPolicy
|
|
metadata:
|
|
name: policy-gatekeeper-containerlivenessprobenotset
|
|
spec:
|
|
remediationAction: enforce
|
|
severity: low
|
|
object-templates:
|
|
- complianceType: musthave
|
|
objectDefinition:
|
|
apiVersion: templates.gatekeeper.sh/v1beta1
|
|
kind: ConstraintTemplate
|
|
metadata:
|
|
creationTimestamp: null
|
|
name: containerlivenessprobenotset
|
|
spec:
|
|
crd:
|
|
spec:
|
|
names:
|
|
kind: ContainerLivenessprobeNotset
|
|
targets:
|
|
- libs:
|
|
- |
|
|
package lib.konstraint
|
|
|
|
default is_gatekeeper = false
|
|
|
|
is_gatekeeper {
|
|
has_field(input, "review")
|
|
has_field(input.review, "object")
|
|
}
|
|
|
|
object = input {
|
|
not is_gatekeeper
|
|
}
|
|
|
|
object = input.review.object {
|
|
is_gatekeeper
|
|
}
|
|
|
|
format(msg) = gatekeeper_format {
|
|
is_gatekeeper
|
|
gatekeeper_format = {"msg": msg}
|
|
}
|
|
|
|
format(msg) = msg {
|
|
not is_gatekeeper
|
|
}
|
|
|
|
name = object.metadata.name
|
|
|
|
kind = object.kind
|
|
|
|
has_field(obj, field) {
|
|
obj[field]
|
|
}
|
|
|
|
missing_field(obj, field) = true {
|
|
obj[field] == ""
|
|
}
|
|
|
|
missing_field(obj, field) = true {
|
|
not has_field(obj, field)
|
|
}
|
|
|
|
is_service {
|
|
lower(kind) == "service"
|
|
}
|
|
|
|
is_statefulset {
|
|
lower(kind) == "statefulset"
|
|
}
|
|
|
|
is_daemonset {
|
|
lower(kind) == "daemonset"
|
|
}
|
|
|
|
is_deployment {
|
|
lower(kind) == "deployment"
|
|
}
|
|
|
|
is_pod {
|
|
lower(kind) == "pod"
|
|
}
|
|
|
|
is_namespace {
|
|
lower(kind) == "namespace"
|
|
}
|
|
|
|
is_workload {
|
|
containers[_]
|
|
}
|
|
|
|
pod_containers(pod) = all_containers {
|
|
keys = {"containers", "initContainers"}
|
|
all_containers = [c | keys[k]; c = pod.spec[k][_]]
|
|
}
|
|
|
|
containers[container] {
|
|
pods[pod]
|
|
all_containers = pod_containers(pod)
|
|
container = all_containers[_]
|
|
}
|
|
|
|
containers[container] {
|
|
all_containers = pod_containers(object)
|
|
container = all_containers[_]
|
|
}
|
|
|
|
container_images[image] {
|
|
containers[container]
|
|
image = container.image
|
|
}
|
|
|
|
container_images[image] {
|
|
image = object.spec.image
|
|
}
|
|
|
|
split_image(image) = [image, "latest"] {
|
|
not contains(image, ":")
|
|
}
|
|
|
|
split_image(image) = [image_name, tag] {
|
|
[image_name, tag] = split(image, ":")
|
|
}
|
|
|
|
pods[pod] {
|
|
is_statefulset
|
|
pod = object.spec.template
|
|
}
|
|
|
|
pods[pod] {
|
|
is_daemonset
|
|
pod = object.spec.template
|
|
}
|
|
|
|
pods[pod] {
|
|
is_deployment
|
|
pod = object.spec.template
|
|
}
|
|
|
|
pods[pod] {
|
|
is_pod
|
|
pod = object
|
|
}
|
|
|
|
volumes[volume] {
|
|
pods[pod]
|
|
volume = pod.spec.volumes[_]
|
|
}
|
|
|
|
mem_multiple("E") = 1000000000000000000000 { true }
|
|
|
|
mem_multiple("P") = 1000000000000000000 { true }
|
|
|
|
mem_multiple("T") = 1000000000000000 { true }
|
|
|
|
mem_multiple("G") = 1000000000000 { true }
|
|
|
|
mem_multiple("M") = 1000000000 { true }
|
|
|
|
mem_multiple("k") = 1000000 { true }
|
|
|
|
mem_multiple("") = 1000 { true }
|
|
|
|
mem_multiple("m") = 1 { true }
|
|
|
|
mem_multiple("Ki") = 1024000 { true }
|
|
|
|
mem_multiple("Mi") = 1048576000 { true }
|
|
|
|
mem_multiple("Gi") = 1073741824000 { true }
|
|
|
|
mem_multiple("Ti") = 1099511627776000 { true }
|
|
|
|
mem_multiple("Pi") = 1125899906842624000 { true }
|
|
|
|
mem_multiple("Ei") = 1152921504606846976000 { true }
|
|
|
|
get_suffix(mem) = suffix {
|
|
not is_string(mem)
|
|
suffix := ""
|
|
}
|
|
|
|
get_suffix(mem) = suffix {
|
|
is_string(mem)
|
|
count(mem) > 0
|
|
suffix := substring(mem, count(mem) - 1, -1)
|
|
mem_multiple(suffix)
|
|
}
|
|
|
|
get_suffix(mem) = suffix {
|
|
is_string(mem)
|
|
count(mem) > 1
|
|
suffix := substring(mem, count(mem) - 2, -1)
|
|
mem_multiple(suffix)
|
|
}
|
|
|
|
get_suffix(mem) = suffix {
|
|
is_string(mem)
|
|
count(mem) > 1
|
|
not mem_multiple(substring(mem, count(mem) - 1, -1))
|
|
not mem_multiple(substring(mem, count(mem) - 2, -1))
|
|
suffix := ""
|
|
}
|
|
|
|
get_suffix(mem) = suffix {
|
|
is_string(mem)
|
|
count(mem) == 1
|
|
not mem_multiple(substring(mem, count(mem) - 1, -1))
|
|
suffix := ""
|
|
}
|
|
|
|
get_suffix(mem) = suffix {
|
|
is_string(mem)
|
|
count(mem) == 0
|
|
suffix := ""
|
|
}
|
|
|
|
canonify_mem(orig) = new {
|
|
is_number(orig)
|
|
new := orig * 1000
|
|
}
|
|
|
|
canonify_mem(orig) = new {
|
|
not is_number(orig)
|
|
suffix := get_suffix(orig)
|
|
raw := replace(orig, suffix, "")
|
|
re_match("^[0-9]+$", raw)
|
|
new := to_number(raw) * mem_multiple(suffix)
|
|
}
|
|
|
|
canonify_storage(orig) = new {
|
|
is_number(orig)
|
|
new := orig
|
|
}
|
|
|
|
canonify_storage(orig) = new {
|
|
not is_number(orig)
|
|
suffix := get_suffix(orig)
|
|
raw := replace(orig, suffix, "")
|
|
re_match("^[0-9]+$", raw)
|
|
new := to_number(raw) * mem_multiple(suffix)
|
|
}
|
|
|
|
canonify_cpu(orig) = new {
|
|
is_number(orig)
|
|
new := orig * 1000
|
|
}
|
|
|
|
canonify_cpu(orig) = new {
|
|
not is_number(orig)
|
|
endswith(orig, "m")
|
|
new := to_number(replace(orig, "m", ""))
|
|
}
|
|
|
|
canonify_cpu(orig) = new {
|
|
not is_number(orig)
|
|
not endswith(orig, "m")
|
|
re_match("^[0-9]+$", orig)
|
|
new := to_number(orig) * 1000
|
|
}
|
|
|
|
dropped_capability(container, cap) {
|
|
container.securityContext.capabilities.drop[_] == cap
|
|
}
|
|
|
|
added_capability(container, cap) {
|
|
container.securityContext.capabilities.add[_] == cap
|
|
}
|
|
|
|
no_read_only_filesystem(c) {
|
|
not has_field(c, "securityContext")
|
|
}
|
|
|
|
no_read_only_filesystem(c) {
|
|
has_field(c, "securityContext")
|
|
not has_field(c.securityContext, "readOnlyRootFilesystem")
|
|
}
|
|
|
|
priviledge_escalation_allowed(c) {
|
|
not has_field(c, "securityContext")
|
|
}
|
|
|
|
priviledge_escalation_allowed(c) {
|
|
has_field(c, "securityContext")
|
|
has_field(c.securityContext, "allowPrivilegeEscalation")
|
|
}
|
|
- |-
|
|
package lib.openshift
|
|
|
|
import data.lib.konstraint
|
|
|
|
is_deploymentconfig {
|
|
lower(konstraint.object.apiVersion) == "apps.openshift.io/v1"
|
|
lower(konstraint.object.kind) == "deploymentconfig"
|
|
}
|
|
|
|
is_route {
|
|
lower(konstraint.object.apiVersion) == "route.openshift.io/v1"
|
|
lower(konstraint.object.kind) == "route"
|
|
}
|
|
|
|
is_workload_kind {
|
|
is_deploymentconfig
|
|
}
|
|
|
|
is_workload_kind {
|
|
konstraint.is_statefulset
|
|
}
|
|
|
|
is_workload_kind {
|
|
konstraint.is_daemonset
|
|
}
|
|
|
|
is_workload_kind {
|
|
konstraint.is_deployment
|
|
}
|
|
|
|
is_all_kind {
|
|
is_workload_kind
|
|
}
|
|
|
|
is_all_kind {
|
|
konstraint.is_service
|
|
}
|
|
|
|
is_all_kind {
|
|
is_route
|
|
}
|
|
|
|
pods[pod] {
|
|
is_deploymentconfig
|
|
pod = konstraint.object.spec.template
|
|
}
|
|
|
|
pods[pod] {
|
|
pod = konstraint.pods[_]
|
|
}
|
|
|
|
containers[container] {
|
|
pods[pod]
|
|
all_containers = konstraint.pod_containers(pod)
|
|
container = all_containers[_]
|
|
}
|
|
|
|
containers[container] {
|
|
container = konstraint.containers[_]
|
|
}
|
|
rego: |-
|
|
package ocp.bestpractices.container_livenessprobe_notset
|
|
|
|
import data.lib.konstraint
|
|
import data.lib.openshift
|
|
|
|
violation[msg] {
|
|
openshift.is_workload_kind
|
|
|
|
container := openshift.containers[_]
|
|
|
|
konstraint.missing_field(container, "livenessProbe")
|
|
obj := konstraint.object
|
|
|
|
msg := konstraint.format(sprintf("%s/%s: container '%s' has no livenessProbe. See: https://docs.openshift.com/container-platform/latest/applications/application-health.html", [obj.kind, obj.metadata.name, container.name]))
|
|
}
|
|
target: admission.k8s.gatekeeper.sh
|
|
- complianceType: musthave
|
|
objectDefinition:
|
|
apiVersion: constraints.gatekeeper.sh/v1beta1
|
|
kind: ContainerLivenessprobeNotset
|
|
metadata:
|
|
name: containerlivenessprobenotset
|
|
spec:
|
|
enforcementAction: dryrun
|
|
match:
|
|
kinds:
|
|
- apiGroups:
|
|
- apps.openshift.io
|
|
- apps
|
|
kinds:
|
|
- DeploymentConfig
|
|
- DaemonSet
|
|
- Deployment
|
|
- StatefulSet
|
|
- objectDefinition:
|
|
apiVersion: policy.open-cluster-management.io/v1
|
|
kind: ConfigurationPolicy
|
|
metadata:
|
|
name: policy-gatekeeper-audit-liveness
|
|
spec:
|
|
remediationAction: inform # will be overridden by remediationAction in parent policy
|
|
severity: low
|
|
object-templates:
|
|
- complianceType: musthave
|
|
objectDefinition:
|
|
apiVersion: constraints.gatekeeper.sh/v1beta1
|
|
kind: ContainerLivenessprobeNotset
|
|
metadata:
|
|
name: containerlivenessprobenotset
|
|
status:
|
|
totalViolations: 0
|
|
- objectDefinition:
|
|
apiVersion: policy.open-cluster-management.io/v1
|
|
kind: ConfigurationPolicy
|
|
metadata:
|
|
name: policy-gatekeeper-admission-liveness
|
|
spec:
|
|
remediationAction: inform # will be overridden by remediationAction in parent policy
|
|
severity: low
|
|
object-templates:
|
|
- complianceType: mustnothave
|
|
objectDefinition:
|
|
apiVersion: v1
|
|
kind: Event
|
|
metadata:
|
|
namespace: openshift-gatekeeper-system # set it to the actual namespace where gatekeeper is running if different
|
|
annotations:
|
|
constraint_action: deny
|
|
constraint_kind: ContainerLivenessprobeNotset
|
|
constraint_name: containerlivenessprobenotset
|
|
event_type: violation
|
|
---
|
|
apiVersion: policy.open-cluster-management.io/v1
|
|
kind: PlacementBinding
|
|
metadata:
|
|
name: binding-policy-gatekeeper-containerlivenessprobenotset
|
|
placementRef:
|
|
name: placement-policy-gatekeeper-containerlivenessprobenotset
|
|
kind: PlacementRule
|
|
apiGroup: apps.open-cluster-management.io
|
|
subjects:
|
|
- name: policy-gatekeeper-livenessprobe
|
|
kind: Policy
|
|
apiGroup: policy.open-cluster-management.io
|
|
---
|
|
apiVersion: apps.open-cluster-management.io/v1
|
|
kind: PlacementRule
|
|
metadata:
|
|
name: placement-policy-gatekeeper-containerlivenessprobenotset
|
|
spec:
|
|
clusterConditions:
|
|
- status: "True"
|
|
type: ManagedClusterConditionAvailable
|
|
clusterSelector:
|
|
matchExpressions:
|
|
- { key: policy, operator: In, values: ["opa"] } |