Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: adding CEL for psp-host-network-ports policy #544

Merged
merged 6 commits into from
Jun 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: 1.1.0
name: k8spsphostnetworkingports
displayName: Host Networking Ports
createdAt: "2024-06-04T00:04:23Z"
description: Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and `hostPorts` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces
digest: b4b275420d181ab6a007360e37bdda6356b0d2692982f192fbb2aa37d18bbe3b
license: Apache-2.0
homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/host-network-ports
keywords:
- gatekeeper
- open-policy-agent
- policies
readme: |-
# Host Networking Ports
Controls usage of host network namespace by pod containers. Specific ports must be specified. Corresponds to the `hostNetwork` and `hostPorts` fields in a PodSecurityPolicy. For more information, see https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces
install: |-
### Usage
```shell
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/pod-security-policy/host-network-ports/1.1.0/template.yaml
```
provider:
name: Gatekeeper Library
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
resources:
- template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
name: psp-host-network-ports
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
hostNetwork: true
min: 80
max: 9000
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
name: psp-host-network
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
hostNetwork: false
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-host-networking-ports-disallowed
labels:
app: nginx-host-networking-ports
spec:
hostNetwork: true
ephemeralContainers:
- name: nginx
image: nginx
ports:
- containerPort: 9001
hostPort: 9001
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-host-networking-ports-allowed
labels:
app: nginx-host-networking-ports
spec:
hostNetwork: false
containers:
- name: nginx
image: nginx
ports:
- containerPort: 9000
hostPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Pod
metadata:
name: nginx-host-networking-ports-disallowed
labels:
app: nginx-host-networking-ports
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx
ports:
- containerPort: 9001
hostPort: 9001
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
kind: AdmissionReview
apiVersion: admission.k8s.io/v1beta1
request:
operation: "UPDATE"
object:
apiVersion: v1
kind: Pod
metadata:
name: nginx-host-networking-ports-disallowed
labels:
app: nginx-host-networking-ports
spec:
hostNetwork: true
containers:
- name: nginx
image: nginx
ports:
- containerPort: 9001
hostPort: 9001
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
kind: Suite
apiVersion: test.gatekeeper.sh/v1alpha1
metadata:
name: host-network-ports
tests:
- name: use-of-host-networking-ports-blocked
template: template.yaml
constraint: samples/psp-host-network-ports/constraint.yaml
cases:
- name: example-disallowed
object: samples/psp-host-network-ports/example_disallowed.yaml
assertions:
- violations: yes
- name: example-allowed
object: samples/psp-host-network-ports/example_allowed.yaml
assertions:
- violations: no
- name: disallowed-ephemeral
object: samples/psp-host-network-ports/disallowed_ephemeral.yaml
assertions:
- violations: yes
- name: update
object: samples/psp-host-network-ports/update.yaml
assertions:
- violations: no
- name: use-of-host-network-blocked
template: template.yaml
constraint: samples/psp-host-network-ports/constraint_block_host_network.yaml
cases:
- name: example-disallowed
object: samples/psp-host-network-ports/example_disallowed.yaml
assertions:
- violations: yes
- name: example-allowed
object: samples/psp-host-network-ports/example_allowed.yaml
assertions:
- violations: no
- name: disallowed-ephemeral
object: samples/psp-host-network-ports/disallowed_ephemeral.yaml
assertions:
- violations: yes
- name: update
object: samples/psp-host-network-ports/update.yaml
assertions:
- violations: no
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8spsphostnetworkingports
annotations:
metadata.gatekeeper.sh/title: "Host Networking Ports"
metadata.gatekeeper.sh/version: 1.1.0
description: >-
Controls usage of host network namespace by pod containers. Specific
ports must be specified. Corresponds to the `hostNetwork` and
`hostPorts` fields in a PodSecurityPolicy. For more information, see
https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces
spec:
crd:
spec:
names:
kind: K8sPSPHostNetworkingPorts
validation:
# Schema for the `parameters` field
openAPIV3Schema:
type: object
description: >-
Controls usage of host network namespace by pod containers. Specific
ports must be specified. Corresponds to the `hostNetwork` and
`hostPorts` fields in a PodSecurityPolicy. For more information, see
https://kubernetes.io/docs/concepts/policy/pod-security-policy/#host-namespaces
properties:
exemptImages:
description: >-
Any container that uses an image that matches an entry in this list will be excluded
from enforcement. Prefix-matching can be signified with `*`. For example: `my-image-*`.

It is recommended that users use the fully-qualified Docker image name (e.g. start with a domain name)
in order to avoid unexpectedly exempting images from an untrusted repository.
type: array
items:
type: string
hostNetwork:
description: "Determines if the policy allows the use of HostNetwork in the pod spec."
type: boolean
min:
description: "The start of the allowed port range, inclusive."
type: integer
max:
description: "The end of the allowed port range, inclusive."
type: integer
targets:
- target: admission.k8s.gatekeeper.sh
code:
- engine: K8sNativeValidation
source:
variables:
- name: containers
expression: 'has(variables.anyObject.spec.containers) ? variables.anyObject.spec.containers : []'
- name: initContainers
expression: 'has(variables.anyObject.spec.initContainers) ? variables.anyObject.spec.initContainers : []'
- name: ephemeralContainers
expression: 'has(variables.anyObject.spec.ephemeralContainers) ? variables.anyObject.spec.ephemeralContainers : []'
- name: exemptImagePrefixes
expression: |
!has(variables.params.exemptImages) ? [] :
variables.params.exemptImages.filter(image, image.endsWith("*")).map(image, string(image).replace("*", ""))
- name: exemptImageExplicit
expression: |
!has(variables.params.exemptImages) ? [] :
variables.params.exemptImages.filter(image, !image.endsWith("*"))
- name: exemptImages
expression: |
(variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container,
container.image in variables.exemptImageExplicit ||
variables.exemptImagePrefixes.exists(exemption, string(container.image).startsWith(exemption)))
- name: badContainers
expression: |
(variables.containers + variables.initContainers + variables.ephemeralContainers).filter(container,
!(container.image in variables.exemptImages) &&
(
(!has(variables.params.hostNetwork) || !variables.params.hostNetwork ? (has(variables.anyObject.spec.hostNetwork) && variables.anyObject.spec.hostNetwork) : false) ||
(container.ports.all(port, has(port.hostPort) && has(variables.params.min) && port.hostPort < variables.params.min)) ||
(container.ports.all(port, has(port.hostPort) && has(variables.params.max) && port.hostPort > variables.params.max))
)
)
validations:
- expression: '(has(request.operation) && request.operation == "UPDATE") || size(variables.badContainers) == 0'
messageExpression: '"The specified hostNetwork and hostPort are not allowed, pod: " + variables.anyObject.metadata.name + ". Allowed values: " + variables.params'
- engine: Rego
source:
rego: |
package k8spsphostnetworkingports

import data.lib.exclude_update.is_update
import data.lib.exempt_container.is_exempt

violation[{"msg": msg, "details": {}}] {
# spec.hostNetwork field is immutable.
not is_update(input.review)

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(_) {
hostPort := input_containers[_].ports[_].hostPort
hostPort < input.parameters.min
}

input_share_hostnetwork(_) {
hostPort := input_containers[_].ports[_].hostPort
hostPort > input.parameters.max
}

input_containers[c] {
c := input.review.object.spec.containers[_]
not is_exempt(c)
}

input_containers[c] {
c := input.review.object.spec.initContainers[_]
not is_exempt(c)
}

input_containers[c] {
c := input.review.object.spec.ephemeralContainers[_]
not is_exempt(c)
}
libs:
- |
package lib.exclude_update

is_update(review) {
review.operation == "UPDATE"
}
- |
package lib.exempt_container

is_exempt(container) {
exempt_images := object.get(object.get(input, "parameters", {}), "exemptImages", [])
img := container.image
exemption := exempt_images[_]
_matches_exemption(img, exemption)
}

_matches_exemption(img, exemption) {
not endswith(exemption, "*")
exemption == img
}

_matches_exemption(img, exemption) {
endswith(exemption, "*")
prefix := trim_suffix(exemption, "*")
startswith(img, prefix)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPHostNetworkingPorts
metadata:
name: psp-host-network
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
hostNetwork: false
20 changes: 20 additions & 0 deletions library/pod-security-policy/host-network-ports/suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,23 @@ tests:
object: samples/psp-host-network-ports/update.yaml
assertions:
- violations: no
- name: use-of-host-network-blocked
template: template.yaml
constraint: samples/psp-host-network-ports/constraint_block_host_network.yaml
cases:
- name: example-disallowed
object: samples/psp-host-network-ports/example_disallowed.yaml
assertions:
- violations: yes
- name: example-allowed
object: samples/psp-host-network-ports/example_allowed.yaml
assertions:
- violations: no
- name: disallowed-ephemeral
object: samples/psp-host-network-ports/disallowed_ephemeral.yaml
assertions:
- violations: yes
- name: update
object: samples/psp-host-network-ports/update.yaml
assertions:
- violations: no
Loading
Loading