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

feat: add requiresSyncData and verify-sync test #251

Merged
merged 9 commits into from
Nov 10, 2022
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
8 changes: 8 additions & 0 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,14 @@ jobs:
- name: Run script
run: |
make require-suites
require_sync:
runs-on: ubuntu-latest
name: "Require a sync.yaml file and metadata.gatekeeper.sh/requiresSyncData annotation for every template.yaml using data.inventory"
steps:
- uses: actions/checkout@v2
- name: Run script
run: |
make require-sync
sozercan marked this conversation as resolved.
Show resolved Hide resolved
apeabody marked this conversation as resolved.
Show resolved Hide resolved
gator-verify:
runs-on: ubuntu-latest
name: "Verify assertions in suite.yaml files"
Expand Down
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ GOMPLATE_VERSION ?= 3.10.0
REPO_ROOT := $(shell git rev-parse --show-toplevel)
WEBSITE_SCRIPT_DIR := $(REPO_ROOT)/scripts/website
ARTIFACTHUB_SCRIPT_DIR := $(REPO_ROOT)/scripts/artifacthub
REQUIRE_SYNC_SCRIPT_DIR := $(REPO_ROOT)/scripts/require-sync

integration-bootstrap:
# Download and install kind
Expand Down Expand Up @@ -61,6 +62,10 @@ __build-gomplate:
require-suites:
./scripts/require-suites.sh

.PHONY: require-sync
require-sync:
cd $(REQUIRE_SYNC_SCRIPT_DIR); go run main.go --path="$(REPO_ROOT)/library" --sync-file=true

.PHONY: generate-website-docs
generate-website-docs:
cd $(WEBSITE_SCRIPT_DIR); go run generate.go
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
version: 1.0.1
name: k8spoddisruptionbudget
displayName: Pod Disruption Budget
createdAt: "2022-11-08T23:45:23Z"
description: |-
Disallow the following scenarios when deploying PodDisruptionBudgets or resources that implement the replica subresource (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet): 1. Deployment of PodDisruptionBudgets with .spec.maxUnavailable == 0 2. Deployment of PodDisruptionBudgets with .spec.minAvailable == .spec.replicas of the resource with replica subresource This will prevent PodDisruptionBudgets from blocking voluntary disruptions such as node draining.
https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
digest: fb75feb67ae0a0305bbdc8ed54b92fe4888ddc68d8279acb78a37f77c4e2a008
license: Apache-2.0
homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/poddisruptionbudget
keywords:
- gatekeeper
- open-policy-agent
- policies
readme: |-
# Pod Disruption Budget
Disallow the following scenarios when deploying PodDisruptionBudgets or resources that implement the replica subresource (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet): 1. Deployment of PodDisruptionBudgets with .spec.maxUnavailable == 0 2. Deployment of PodDisruptionBudgets with .spec.minAvailable == .spec.replicas of the resource with replica subresource This will prevent PodDisruptionBudgets from blocking voluntary disruptions such as node draining.
https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
install: |-
### Usage
```shell
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/poddisruptionbudget/1.0.1/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: K8sPodDisruptionBudget
metadata:
name: pod-distruption-budget
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment", "ReplicaSet", "StatefulSet"]
- apiGroups: ["policy"]
kinds: ["PodDisruptionBudget"]
- apiGroups: [""]
kinds: ["ReplicationController"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-allowed-1
namespace: default
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
example: allowed-deployment-1
template:
metadata:
labels:
app: nginx
example: allowed-deployment-1
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-allowed-2
namespace: default
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
example: allowed-deployment-2
template:
metadata:
labels:
app: nginx
example: allowed-deployment-2
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: nginx-pdb-allowed
namespace: default
spec:
maxUnavailable: 1
selector:
matchLabels:
foo: bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment-disallowed
namespace: default
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
example: disallowed-deployment
template:
metadata:
labels:
app: nginx
example: disallowed-deployment
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: nginx-pdb-disallowed
namespace: default
spec:
maxUnavailable: 0
selector:
matchLabels:
foo: bar
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: inventory-nginx-pdb-allowed-1
namespace: default
spec:
minAvailable: 2
selector:
matchLabels:
app: nginx
example: allowed-deployment-1
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: inventory-nginx-pdb-allowed-2
namespace: default
spec:
maxUnavailable: 1
selector:
matchLabels:
app: nginx
example: allowed-deployment-2
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: inventory-nginx-pdb-disallowed
namespace: default
spec:
minAvailable: 3
selector:
matchLabels:
app: nginx
example: disallowed-deployment
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
kind: Suite
apiVersion: test.gatekeeper.sh/v1alpha1
metadata:
name: poddisruptionbudget
tests:
- name: pod-disruption-budget
template: template.yaml
constraint: samples/poddisruptionbudget/constraint.yaml
cases:
- name: example-allowed-pdb
object: samples/poddisruptionbudget/example_allowed_pdb.yaml
assertions:
- violations: no
- name: example-disallowed-pdb
object: samples/poddisruptionbudget/example_disallowed_pdb.yaml
assertions:
- violations: yes
- name: example-allowed-min-available
object: samples/poddisruptionbudget/example_allowed_deployment1.yaml
inventory:
- samples/poddisruptionbudget/example_inventory_allowed1.yaml
assertions:
- violations: no
- name: example-allowed-max-unavailable
object: samples/poddisruptionbudget/example_allowed_deployment2.yaml
inventory:
- samples/poddisruptionbudget/example_inventory_allowed2.yaml
assertions:
- violations: no
- name: example-disallowed-min-available
object: samples/poddisruptionbudget/example_disallowed_deployment.yaml
inventory:
- samples/poddisruptionbudget/example_inventory_disallowed.yaml
assertions:
- violations: yes
11 changes: 11 additions & 0 deletions artifacthub/library/general/poddisruptionbudget/1.0.1/sync.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
name: config
namespace: "gatekeeper-system"
spec:
sync:
syncOnly:
- group: "policy"
version: "v1"
kind: "PodDisruptionBudget"
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8spoddisruptionbudget
annotations:
metadata.gatekeeper.sh/title: "Pod Disruption Budget"
metadata.gatekeeper.sh/version: 1.0.1
metadata.gatekeeper.sh/requiresSyncData: |
"[
[
{
"groups":["policy"],
"versions": ["v1"],
"kinds": ["PodDisruptionBudget"]
}
]
]"
description: >-
Disallow the following scenarios when deploying PodDisruptionBudgets or resources that implement the replica subresource (e.g. Deployment, ReplicationController, ReplicaSet, StatefulSet):
1. Deployment of PodDisruptionBudgets with .spec.maxUnavailable == 0
2. Deployment of PodDisruptionBudgets with .spec.minAvailable == .spec.replicas of the resource with replica subresource
This will prevent PodDisruptionBudgets from blocking voluntary disruptions such as node draining.

https://kubernetes.io/docs/concepts/workloads/pods/disruptions/
spec:
crd:
spec:
names:
kind: K8sPodDisruptionBudget
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8spoddisruptionbudget

violation[{"msg": msg}] {
input.review.kind.kind == "PodDisruptionBudget"
pdb := input.review.object

not valid_pdb_max_unavailable(pdb)
msg := sprintf(
"PodDisruptionBudget <%v> has maxUnavailable of 0, only positive integers are allowed for maxUnavailable",
[pdb.metadata.name],
)
}

violation[{"msg": msg}] {
obj := input.review.object
pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_]
obj.spec.selector.matchLabels == pdb.spec.selector.matchLabels

not valid_pdb_max_unavailable(pdb)
msg := sprintf(
"%v <%v> has been selected by PodDisruptionBudget <%v> but has maxUnavailable of 0, only positive integers are allowed for maxUnavailable",
[obj.kind, obj.metadata.name, pdb.metadata.name],
)
}

violation[{"msg": msg}] {
obj := input.review.object
pdb := data.inventory.namespace[obj.metadata.namespace]["policy/v1"].PodDisruptionBudget[_]
obj.spec.selector.matchLabels == pdb.spec.selector.matchLabels

not valid_pdb_min_available(obj, pdb)
msg := sprintf(
"%v <%v> has %v replica(s) but PodDisruptionBudget <%v> has minAvailable of %v, PodDisruptionBudget count should always be lower than replica(s), and not used when replica(s) is set to 1",
[obj.kind, obj.metadata.name, obj.spec.replicas, pdb.metadata.name, pdb.spec.minAvailable, obj.spec.replicas],
)
}

valid_pdb_min_available(obj, pdb) {
# default to -1 if minAvailable is not set so valid_pdb_min_available is always true
# for objects with >= 0 replicas. If minAvailable defaults to >= 0, objects with
# replicas field might violate this constraint if they are equal to the default set here
min_available := object.get(pdb.spec, "minAvailable", -1)
obj.spec.replicas > min_available
}

valid_pdb_max_unavailable(pdb) {
# default to 1 if maxUnavailable is not set so valid_pdb_max_unavailable always returns true.
# If maxUnavailable defaults to 0, it violates this constraint because all pods needs to be
# available and no pods can be evicted voluntarily
max_unavailable := object.get(pdb.spec, "maxUnavailable", 1)
max_unavailable > 0
}
16 changes: 16 additions & 0 deletions artifacthub/library/general/storageclass/1.0.1/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# StorageClass

The `StorageClass` constraint blocks the creation of PVCs or StatefulSets
where the specified storage class doesn't exist on the cluster, or that no
storage class at all is specified.

This policy helps prevent workloads from getting stuck indefinitely waiting
for a storage class to provision the persistent storage that will never
happen. This often causes users to get confused as to why their pods are stuck
pending, and requires deleting the StatefulSet and any PVCs it has created along
with redeploying the workload in order to fix. Blocking it up front makes it
much easier to fix before there is a mess to clean up.

**WARNING** This constraint only functions properly
on gatekeeper version 3.9 or above.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: 1.0.1
name: k8sstorageclass
displayName: Storage Class
createdAt: "2022-11-08T23:45:23Z"
description: Requires storage classes to be specified when used. Only Gatekeeper 3.9+ is supported.
digest: 60bc85a9f37888ca1025e0f74d7453fca2296d83a1a71c0752d25afc3b2b1aae
license: Apache-2.0
homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/storageclass
keywords:
- gatekeeper
- open-policy-agent
- policies
readme: |-
# Storage Class
Requires storage classes to be specified when used. Only Gatekeeper 3.9+ is supported.
install: |-
### Usage
```shell
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/storageclass/1.0.1/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: K8sStorageClass
metadata:
name: storageclass
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["PersistentVolumeClaim"]
- apiGroups: ["apps"]
kinds: ["StatefulSet"]
parameters:
includeStorageClassesInMessage: true
Loading