Skip to content

Commit

Permalink
Merge pull request #19 from kcl-lang/add-more-container-validation-mo…
Browse files Browse the repository at this point in the history
…dels

feat: add more container validation models
  • Loading branch information
Peefy authored Oct 11, 2023
2 parents e338636 + 149bdbe commit d2338c4
Show file tree
Hide file tree
Showing 72 changed files with 1,101 additions and 0 deletions.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions examples/validation/disallow-anonymous/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "disallow-anonymous"
version = "0.0.1"
21 changes: 21 additions & 0 deletions examples/validation/disallow-anonymous/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"""Disallows associating ClusterRole and Role resources
to the system:anonymous user and system:unauthenticated group.
"""

schema Params:
allowedRoles?: [str]

params: Params = option("params")

# Define the validation function
validate = lambda item {
if item.kind in ["ClusterRoleBinding"]:
if item.roleRef.name not in (params.allowedRoles or []):
if any subject in item.subjects {
subject.name in ["system:unauthenticated", "system:anonymous"]
}:
assert False, "Unauthenticated user reference is not allowed in for ${item.kind}: ${item.metadata.name}"
item
}
# Validate All resource
items = [validate(i) for i in option("items")]
31 changes: 31 additions & 0 deletions examples/validation/disallow-anonymous/suite/bad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: disallow-anonymous
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Disallows associating ClusterRole and Role resources
to the system:anonymous user and system:unauthenticated group.
spec:
params:
allowedRoles:
- cluster-role-1
source: ./examples/validation/disallow-anonymous/main.k
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-role-binding-2
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-role-2
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:unauthenticated
32 changes: 32 additions & 0 deletions examples/validation/disallow-anonymous/suite/good.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: disallow-anonymous
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Disallows associating ClusterRole and Role resources
to the system:anonymous user and system:unauthenticated group.
spec:
params:
allowedRoles:
- cluster-role-1
source: ./examples/validation/disallow-anonymous/main.k
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-role-binding-1
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-role-1
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:authenticated
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:unauthenticated

Empty file.
Empty file.
3 changes: 3 additions & 0 deletions examples/validation/disallowed-image-repos/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "disallowed-image-repos"
version = "0.0.1"
23 changes: 23 additions & 0 deletions examples/validation/disallowed-image-repos/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
"""Disallowed container repositories that begin with a string from the specified list.
"""

# The list of prefixes a container image is allowed to have.
repos: [str] = option("params").repos or []

# Define the validation function
validate = lambda item {
containers = []
if item.kind == "Pod" and repos:
containers = (item.spec.containers or []) + (item.spec.phemeralContainers or []) + (item.spec.initContainers or [])
elif item.kind == "Deployment":
containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.phemeralContainers or []) + (item.spec.template.spec.initContainers or [])
images: [str] = [c.image for c in containers]
assert all image in images {
all repo in repos {
not image.startswith(repo)
}
} if images and repos, """Use of image is disallowed for ${item.kind}: ${item.metadata.name}, valid repos ${repos}"""
item
}
# Validate All resource
items = [validate(i) for i in option("items")]
28 changes: 28 additions & 0 deletions examples/validation/disallowed-image-repos/suite/bad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: disallowed-image-repos
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Disallowed container repositories that begin with a string from the specified list.
spec:
params:
repos:
- "k8s.gcr.io/"
source: ./examples/validation/disallowed-image-repos/main.k
---
apiVersion: v1
kind: Pod
metadata:
name: pod
spec:
containers:
- name: kcl
image: k8s.gcr.io/kcl
args:
- "kcl"
ephemeralContainers:
- name: kcl
image: k8s.gcr.io/kcl
28 changes: 28 additions & 0 deletions examples/validation/disallowed-image-repos/suite/good.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: disallowed-image-repos
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Disallowed container repositories that begin with a string from the specified list.
spec:
params:
repos:
- "k8s.gcr.io/"
source: ./examples/validation/disallowed-image-repos/main.k
---
apiVersion: v1
kind: Pod
metadata:
name: pod
spec:
containers:
- name: kcl
image: kcllang/kcl
args:
- "kcl"
ephemeralContainers:
- name: kcl
image: kcllang/kcl
Empty file.
3 changes: 3 additions & 0 deletions examples/validation/horizontal-pod-auto-scaler/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "horizontal-pod-auto-scaler"
version = "0.0.1"
35 changes: 35 additions & 0 deletions examples/validation/horizontal-pod-auto-scaler/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
"""Disallow the following scenarios when deploying `HorizontalPodAutoscalers`
1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint
2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread`
3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet).
"""

schema Params:
minimumReplicaSpread: int = 0
ranges: [Range]

check:
minimumReplicaSpread >= 0
len(ranges) > 0

schema Range:
min_replicas: int
max_replicas: int

check:
0 <= min_replicas < max_replicas

params: Params = option("params")

# Define the validation function
validate = lambda item {
containers = []
if item.kind == "HorizontalPodAutoscaler":
assert item.spec.maxReplicas - item.spec.minReplicas >= params.minimumReplicaSpread, "The {} <{}> minReplicas {} or maxReplicas {} is not allowed. Allowed ranges: {}".format(item.kind, item.metadata.name, item.spec.minReplicas, item.spec.maxReplicas, params.ranges)
assert all r in params.ranges {
item.spec.minReplicas >= r.min_replicas and item.spec.maxReplicas <= r.max_replicas
}, "The {} <{}> minReplicas {} or maxReplicas {} is not allowed. Allowed ranges: {}".format(item.kind, item.metadata.name, item.spec.minReplicas, item.spec.maxReplicas, params.ranges)
item
}
# Validate All resource
items = [validate(i) for i in option("items")]
40 changes: 40 additions & 0 deletions examples/validation/horizontal-pod-auto-scaler/suite/bad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: horizontal-pod-auto-scaler
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Disallow the following scenarios when deploying `HorizontalPodAutoscalers`
1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint
2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread`
3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet).
spec:
params:
minimumReplicaSpread: 1
ranges:
- min_replicas: 3
max_replicas: 6
source: ./examples/validation/horizontal-pod-auto-scaler/main.k
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa-disallowed-replicas
namespace: default
spec:
minReplicas: 2
maxReplicas: 7
metrics:
- resource:
name: cpu
target:
averageUtilization: 900
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment

39 changes: 39 additions & 0 deletions examples/validation/horizontal-pod-auto-scaler/suite/good.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: horizontal-pod-auto-scaler
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Disallow the following scenarios when deploying `HorizontalPodAutoscalers`
1. Deployment of HorizontalPodAutoscalers with `.spec.minReplicas` or `.spec.maxReplicas` outside the ranges defined in the constraint
2. Deployment of HorizontalPodAutoscalers where the difference between `.spec.minReplicas` and `.spec.maxReplicas` is less than the configured `minimumReplicaSpread`
3. Deployment of HorizontalPodAutoscalers that do not reference a valid `scaleTargetRef` (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet).
spec:
params:
minimumReplicaSpread: 1
ranges:
- min_replicas: 3
max_replicas: 6
source: ./examples/validation/horizontal-pod-auto-scaler/main.k
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: nginx-hpa-allowed
namespace: default
spec:
minReplicas: 3
maxReplicas: 6
metrics:
- resource:
name: cpu
target:
averageUtilization: 900
type: Utilization
type: Resource
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: nginx-deployment
Empty file.
Empty file.
Empty file.
3 changes: 3 additions & 0 deletions examples/validation/psp-allow-privilege-escalation/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "psp-allow-privilege-escalation"
version = "0.0.1"
39 changes: 39 additions & 0 deletions examples/validation/psp-allow-privilege-escalation/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
"""Controls restricting escalation to root privileges. Corresponds to the
`allowPrivilegeEscalation` field in a PodSecurityPolicy. For more
information, see
https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation
"""
import regex

schema Params:
exemptImages?: [str]

params: Params = option("params")

is_exempt = lambda image: str -> bool {
result = False
if params.exemptImages:
result = any exempt_image in params.exemptImages {
(image.startswith(exempt_image.removesuffix("*")) if exempt_image.endswith("*") else exempt_image == image)
}
result
}

# Define the validation function
validate = lambda item {
cpu = ""
memory = ""
containers = []
if item.kind == "Pod":
containers = (item.spec.containers or []) + (item.spec.initContainers or []) + (item.spec.ephemeralContainers or [])
elif item.kind == "Deployment":
containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or []) + (item.spec.template.spec.ephemeralContainers or [])
if containers:
containers = [c for c in containers if not is_exempt(c.image)]
container_list_disallow_privilege_escalation = [c.name for c in containers if c.securityContext?.allowPrivilegeEscalation == True]
assert len(container_list_disallow_privilege_escalation) == 0, "Privilege escalation containers ${container_list_disallow_privilege_escalation} are not allowed for ${item.kind} <${item.metadata.name}>"
# Return the resource
item
}
# Validate All resource
items = [validate(i) for i in option("items")]
27 changes: 27 additions & 0 deletions examples/validation/psp-allow-privilege-escalation/suite/bad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: psp-allow-privilege-escalation
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Controls restricting escalation to root privileges. Corresponds to the
`allowPrivilegeEscalation` field in a PodSecurityPolicy. For more
information, see
https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation
spec:
source: ./examples/validation/psp-allow-privilege-escalation/main.k
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-privilege-escalation-disallowed
labels:
app: nginx-privilege-escalation
spec:
ephemeralContainers:
- name: nginx
image: nginx
securityContext:
allowPrivilegeEscalation: true
27 changes: 27 additions & 0 deletions examples/validation/psp-allow-privilege-escalation/suite/good.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: psp-allow-privilege-escalation
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Controls restricting escalation to root privileges. Corresponds to the
`allowPrivilegeEscalation` field in a PodSecurityPolicy. For more
information, see
https://kubernetes.io/docs/concepts/policy/pod-security-policy/#privilege-escalation
spec:
source: ./examples/validation/psp-allow-privilege-escalation/main.k
---
apiVersion: v1
kind: Pod
metadata:
name: nginx-privilege-escalation-allowed
labels:
app: nginx-privilege-escalation
spec:
containers:
- name: nginx
image: nginx
securityContext:
allowPrivilegeEscalation: false
Loading

0 comments on commit d2338c4

Please sign in to comment.