Skip to content

Commit

Permalink
feat: add more container validation models
Browse files Browse the repository at this point in the history
  • Loading branch information
Peefy committed Oct 10, 2023
1 parent e338636 commit 7eb8cc3
Show file tree
Hide file tree
Showing 17 changed files with 393 additions and 0 deletions.
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

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
3 changes: 3 additions & 0 deletions examples/validation/validate-container-requests/kcl.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[package]
name = "validate-container-requests"
version = "0.0.1"
44 changes: 44 additions & 0 deletions examples/validation/validate-container-requests/main.k
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
"""Requires containers to have memory and CPU requests set and constrains
requests to be within the specified maximum values.

https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
"""

schema Params:
cpu?: str
memory?: str

params: Params = option("params")

canonify_cpu = lambda cpu: str -> float {
result = 0
if cpu:
if cpu[-1] == "m":
result = int(cpu[:-1])
else:
result = int(cpu) * 1000
result
}

# Define the validation function
validate = lambda item {
cpu = ""
memory = ""
if item.kind == "Pod":
containers = (item.spec.containers or []) + (item.spec.initContainers or [])
elif item.kind == "Deployment":
containers = (item.spec.template.spec.containers or []) + (item.spec.template.spec.initContainers or [])
if containers:
cpu_list: [str] = [c.resources.requests.cpu for c in containers if c?.resources?.requests?.cpu]
memory_list: [str] = [c.resources.requests.memory for c in containers if c?.resources?.requests?.memory]
if params.cpu:
disallowed_cpu_list = [cpu for cpu in cpu_list if canonify_cpu(cpu) > canonify_cpu(params.cpu)]
assert not disallowed_cpu_list, "container cpu limit list '${disallowed_cpu_list}' is higher than the maximum allowed of ${params.cpu}"
if params.memory:
disallowed_memory_list = [memory for memory in memory_list if int(memory) > int(params.memory)]
assert not disallowed_memory_list, "container memory limit list '${disallowed_memory_list}' is higher than the maximum allowed of ${params.memory}"
# Return the resource
item
}
# Validate All resource
items = [validate(i) for i in option("items")]
30 changes: 30 additions & 0 deletions examples/validation/validate-container-requests/suite/bad.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
apiVersion: krm.kcl.dev/v1alpha1
kind: KCLRun
metadata:
name: validate-container-requests
annotations:
krm.kcl.dev/version: 0.0.1
krm.kcl.dev/type: validation
documentation: >-
Requires containers to have memory and CPU requests set and constrains
requests to be within the specified maximum values.
https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/
spec:
params:
cpu: "200m"
memory: "1Gi"
source: ./examples/validation/validate-container-requests/main.k
---
apiVersion: v1
kind: Pod
metadata:
name: allowed
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: "100m"
memory: "2Gi"
Loading

0 comments on commit 7eb8cc3

Please sign in to comment.