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

ci: testing with cel policies #519

Merged
merged 27 commits into from
May 22, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
c1b9241
testing with cel policies
JaydipGabani May 2, 2024
aa12045
--set enableK8sNativeValidation=false for rego engine
JaydipGabani May 2, 2024
67b246f
fixing uploading artifacts in ci
JaydipGabani May 2, 2024
1a4e6d1
removing blank line
JaydipGabani May 2, 2024
120407b
adding engine rego
JaydipGabani May 3, 2024
be18548
adding engine rego
JaydipGabani May 3, 2024
bf316d9
correcting required label cel policy
JaydipGabani May 6, 2024
d560171
Merge branch 'master' into CEL-source
JaydipGabani May 6, 2024
45e9b6a
removing CEL from policies
JaydipGabani May 8, 2024
f7b47b8
Using sed to modify gk.yml
JaydipGabani May 8, 2024
18cd62a
adding required label policy and fixing deployment for gk
JaydipGabani May 9, 2024
a965f5a
fixing ci
JaydipGabani May 9, 2024
fbd06cc
adding not allowed label value example for required label policy
JaydipGabani May 9, 2024
960614d
testing cel with 3.16+
JaydipGabani May 10, 2024
ad3ab1d
changing required label cel
JaydipGabani May 10, 2024
77fc249
only testing rego for 3.15
JaydipGabani May 10, 2024
58a9b57
fixing ci
JaydipGabani May 10, 2024
466d8eb
fixing ci
JaydipGabani May 10, 2024
b9ab792
fixing examples
JaydipGabani May 10, 2024
f8a4a7e
fixing CEL code
JaydipGabani May 11, 2024
f07d100
fixing ci
JaydipGabani May 11, 2024
823c3bb
fixing ci
JaydipGabani May 11, 2024
6d917f7
Merge branch 'master' into CEL-source
JaydipGabani May 13, 2024
a4dce92
merging with master
JaydipGabani May 14, 2024
89a2df0
merging in master and testing with gk 3.16.1
JaydipGabani May 22, 2024
6fe0ef2
testing with gk 3.16.1
JaydipGabani May 22, 2024
bfb2e89
testing with gk 3.16.2
JaydipGabani May 22, 2024
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
21 changes: 15 additions & 6 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,29 +65,35 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
gatekeeper: [ "release-3.13", "release-3.14" ]
name: "Integration test on Gatekeeper ${{ matrix.gatekeeper }}"
gatekeeper: [ "3.15.1", "3.16.0" ]
engine: [ "cel", "rego" ]
JaydipGabani marked this conversation as resolved.
Show resolved Hide resolved
name: "Integration test on Gatekeeper ${{ matrix.gatekeeper }} for ${{ matrix.engine }} policies"
steps:
- name: Harden Runner
if: ${{ (matrix.gatekeeper == '3.15.1' && matrix.engine == 'rego') || matrix.gatekeeper == '3.16.0' }} # remove this condition once 3.17 is out
sozercan marked this conversation as resolved.
Show resolved Hide resolved
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
with:
egress-policy: audit

- name: Check out code into the Go module directory
if: ${{ (matrix.gatekeeper == '3.15.1' && matrix.engine == 'rego') || matrix.gatekeeper == '3.16.0' }}
uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5

- name: Bootstrap integration test
if: ${{ (matrix.gatekeeper == '3.15.1' && matrix.engine == 'rego') || matrix.gatekeeper == '3.16.0' }}
run: |
mkdir -p $GITHUB_WORKSPACE/bin
echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
make integration-bootstrap
make deploy GATEKEEPER_VERSION=${{ matrix.gatekeeper }}
make deploy GATEKEEPER_VERSION=${{ matrix.gatekeeper }} POLICY_ENGINE=${{ matrix.engine }}

- name: Run integration test
if: ${{ (matrix.gatekeeper == '3.15.1' && matrix.engine == 'rego') || matrix.gatekeeper == '3.16.0' }}
run: |
make test-integration

- name: Save logs
if: ${{ (matrix.gatekeeper == '3.15.1' && matrix.engine == 'rego') || matrix.gatekeeper == '3.16.0' }}
run: |
kubectl logs -n gatekeeper-system -l control-plane=controller-manager --tail=-1 > logs-controller.json
kubectl logs -n gatekeeper-system -l control-plane=audit-controller --tail=-1 > logs-audit.json
Expand All @@ -96,7 +102,7 @@ jobs:
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
if: ${{ always() }}
with:
name: logs-int-test-${{ matrix.gatekeeper }}
name: logs-int-test-${{ matrix.gatekeeper }}-${{ matrix.engine }}
path: |
logs-*.json
require_suites:
Expand Down Expand Up @@ -127,7 +133,10 @@ jobs:
make require-sync
gator-verify:
runs-on: ubuntu-latest
name: "Verify assertions in suite.yaml files"
strategy:
matrix:
engine: [ "cel", "rego" ]
name: "Verify assertions in suite.yaml files for ${{ matrix.engine }} policies"
steps:
- name: Harden Runner
uses: step-security/harden-runner@a4aa98b93cab29d9b1101a6143fb8bce00e2eac4 # v2.7.1
Expand All @@ -136,4 +145,4 @@ jobs:

- uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5
- run: |
make verify-gator-dockerized
make verify-gator-dockerized POLICY_ENGINE=${{ matrix.engine }}
28 changes: 22 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ KIND_VERSION ?= 0.17.0
# note: k8s version pinned since KIND image availability lags k8s releases
KUBERNETES_VERSION ?= 1.26.0
KUSTOMIZE_VERSION ?= 4.5.5
GATEKEEPER_VERSION ?= release-3.11
GATEKEEPER_VERSION ?= 3.16.0
BATS_VERSION ?= 1.8.2
GATOR_VERSION ?= 3.11.0
GATOR_VERSION ?= 3.16.0
GOMPLATE_VERSION ?= 3.11.6
POLICY_ENGINE ?= rego

REPO_ROOT := $(shell git rev-parse --show-toplevel)
WEBSITE_SCRIPT_DIR := $(REPO_ROOT)/scripts/website
Expand All @@ -31,21 +32,36 @@ integration-bootstrap:
TERM=dumb ${GITHUB_WORKSPACE}/bin/kind create cluster --image kindest/node:v${KUBERNETES_VERSION} --wait 5m --config=test/kind_config.yaml

deploy:
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/${GATEKEEPER_VERSION}/deploy/gatekeeper.yaml
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
ifeq ($(POLICY_ENGINE), rego)
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper --create-namespace --version $(GATEKEEPER_VERSION) --set enableK8sNativeValidation=false
else ifeq ($(POLICY_ENGINE), cel)
ifneq ($(GATEKEEPER_VERSION), 3.15.1)
helm install -n gatekeeper-system gatekeeper gatekeeper/gatekeeper --create-namespace --version $(GATEKEEPER_VERSION) --set enableK8sNativeValidation=true
endif
endif

uninstall:
kubectl delete -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/${GATEKEEPER_VERSION}/deploy/gatekeeper.yaml
helm uninstall -n gatekeeper-system gatekeeper

test-integration:
bats -t test/bats/test.bats

.PHONY: verify-gator
verify-gator:
gator verify ./...
ifeq ($(POLICY_ENGINE), rego)
gator verify ./... --experimental-enable-k8s-native-validation=false
else ifeq ($(POLICY_ENGINE), cel)
gator verify ./... --experimental-enable-k8s-native-validation=true
endif

.PHONY: verify-gator-dockerized
verify-gator-dockerized: __build-gator
$(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./...
ifeq ($(POLICY_ENGINE), rego)
JaydipGabani marked this conversation as resolved.
Show resolved Hide resolved
$(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./... --experimental-enable-k8s-native-validation=false
else ifeq ($(POLICY_ENGINE), cel)
$(docker) run -i -v $(shell pwd):/gatekeeper-library gator-container verify ./... --experimental-enable-k8s-native-validation=true
endif

.PHONY: build-gator
__build-gator:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
version: 1.1.0
name: k8srequiredlabels
displayName: Required Labels
createdAt: "2024-05-10T23:29:29Z"
description: Requires resources to contain specified labels, with values matching provided regular expressions.
digest: 84897cdfe60dbe9c1726581fe0626d254477a176b143a2cff36b5cf24465e8b8
license: Apache-2.0
homeURL: https://open-policy-agent.github.io/gatekeeper-library/website/requiredlabels
keywords:
- gatekeeper
- open-policy-agent
- policies
readme: |-
# Required Labels
Requires resources to contain specified labels, with values matching provided regular expressions.
install: |-
### Usage
```shell
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/artifacthub/library/general/requiredlabels/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,14 @@
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: all-must-have-owner
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Namespace"]
parameters:
message: "All namespaces must have an `owner` label that points to your company username"
labels:
- key: owner
allowedRegex: "^[a-zA-Z]+.agilebank.demo$"
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: allowed-namespace
labels:
owner: user.agilebank.demo
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: disallowed-namespace
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: disallowed-namespace
labels:
owner: user
21 changes: 21 additions & 0 deletions artifacthub/library/general/requiredlabels/1.1.0/suite.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
kind: Suite
apiVersion: test.gatekeeper.sh/v1alpha1
metadata:
name: requiredlabels
tests:
- name: must-have-owner
template: template.yaml
constraint: samples/all-must-have-owner/constraint.yaml
cases:
- name: example-allowed
object: samples/all-must-have-owner/example_allowed.yaml
assertions:
- violations: no
- name: example-disallowed
object: samples/all-must-have-owner/example_disallowed.yaml
assertions:
- violations: yes
- name: example-disallowed-label-value
object: samples/all-must-have-owner/example_disallowed_label_value.yaml
assertions:
- violations: yes
79 changes: 79 additions & 0 deletions artifacthub/library/general/requiredlabels/1.1.0/template.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
annotations:
metadata.gatekeeper.sh/title: "Required Labels"
metadata.gatekeeper.sh/version: 1.1.0
description: >-
Requires resources to contain specified labels, with values matching
provided regular expressions.
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
message:
type: string
labels:
type: array
description: >-
A list of labels and values the object must specify.
items:
type: object
properties:
key:
type: string
description: >-
The required label.
allowedRegex:
type: string
description: >-
If specified, a regular expression the annotation's value
must match. The value must contain at least one match for
the regular expression.
targets:
- target: admission.k8s.gatekeeper.sh
code:
- engine: K8sNativeValidation
source:
validations:
- expression: '(has(object.metadata) && variables.params.labels.all(entry, has(object.metadata.labels) && entry.key in object.metadata.labels))'
messageExpression: '"missing required label, requires all of: " + variables.params.labels.map(entry, entry.key).join(", ")'
- expression: '(has(object.metadata) && variables.params.labels.all(entry, has(object.metadata.labels) && entry.key in object.metadata.labels && string(object.metadata.labels[entry.key]).matches(string(entry.allowedRegex))))'
message: "regex mismatch"
- engine: Rego
source:
rego: |
package k8srequiredlabels

get_message(parameters, _default) := _default {
not parameters.message
}

get_message(parameters, _) := parameters.message

violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_].key}
missing := required - provided
count(missing) > 0
def_msg := sprintf("you must provide labels: %v", [missing])
msg := get_message(input.parameters, def_msg)
}

violation[{"msg": msg}] {
value := input.review.object.metadata.labels[key]
expected := input.parameters.labels[_]
expected.key == key
# do not match if allowedRegex is not defined, or is an empty string
expected.allowedRegex != ""
not regex.match(expected.allowedRegex, value)
def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
msg := get_message(input.parameters, def_msg)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
apiVersion: v1
kind: Namespace
metadata:
name: disallowed-namespace
labels:
owner: user
4 changes: 4 additions & 0 deletions library/general/requiredlabels/suite.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,7 @@ tests:
object: samples/all-must-have-owner/example_disallowed.yaml
assertions:
- violations: yes
- name: example-disallowed-label-value
object: samples/all-must-have-owner/example_disallowed_label_value.yaml
assertions:
- violations: yes
61 changes: 36 additions & 25 deletions library/general/requiredlabels/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
name: k8srequiredlabels
annotations:
metadata.gatekeeper.sh/title: "Required Labels"
metadata.gatekeeper.sh/version: 1.0.1
metadata.gatekeeper.sh/version: 1.1.0
description: >-
Requires resources to contain specified labels, with values matching
provided regular expressions.
Expand Down Expand Up @@ -38,31 +38,42 @@ spec:
the regular expression.
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
code:
- engine: K8sNativeValidation
source:
validations:
- expression: '(has(object.metadata) && variables.params.labels.all(entry, has(object.metadata.labels) && entry.key in object.metadata.labels))'
messageExpression: '"missing required label, requires all of: " + variables.params.labels.map(entry, entry.key).join(", ")'
- expression: '(has(object.metadata) && variables.params.labels.all(entry, has(object.metadata.labels) && entry.key in object.metadata.labels && string(object.metadata.labels[entry.key]).matches(string(entry.allowedRegex))))'
message: "regex mismatch"
- engine: Rego
source:
rego: |
package k8srequiredlabels

get_message(parameters, _default) := _default {
not parameters.message
}
get_message(parameters, _default) := _default {
not parameters.message
}

get_message(parameters, _) := parameters.message
get_message(parameters, _) := parameters.message

violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_].key}
missing := required - provided
count(missing) > 0
def_msg := sprintf("you must provide labels: %v", [missing])
msg := get_message(input.parameters, def_msg)
}
violation[{"msg": msg, "details": {"missing_labels": missing}}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_].key}
missing := required - provided
count(missing) > 0
def_msg := sprintf("you must provide labels: %v", [missing])
msg := get_message(input.parameters, def_msg)
}

violation[{"msg": msg}] {
value := input.review.object.metadata.labels[key]
expected := input.parameters.labels[_]
expected.key == key
# do not match if allowedRegex is not defined, or is an empty string
expected.allowedRegex != ""
not regex.match(expected.allowedRegex, value)
def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
msg := get_message(input.parameters, def_msg)
}

violation[{"msg": msg}] {
value := input.review.object.metadata.labels[key]
expected := input.parameters.labels[_]
expected.key == key
# do not match if allowedRegex is not defined, or is an empty string
expected.allowedRegex != ""
not regex.match(expected.allowedRegex, value)
def_msg := sprintf("Label <%v: %v> does not satisfy allowed regex: %v", [key, value, expected.allowedRegex])
msg := get_message(input.parameters, def_msg)
}
13 changes: 10 additions & 3 deletions src/general/requiredlabels/constraint.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ metadata:
name: k8srequiredlabels
annotations:
metadata.gatekeeper.sh/title: "Required Labels"
metadata.gatekeeper.sh/version: 1.0.1
metadata.gatekeeper.sh/version: 1.1.0
description: >-
Requires resources to contain specified labels, with values matching
provided regular expressions.
Expand Down Expand Up @@ -38,5 +38,12 @@ spec:
the regular expression.
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
{{ file.Read "src/general/requiredlabels/src.rego" | strings.Indent 8 | strings.TrimSuffix "\n" }}
code:
- engine: K8sNativeValidation
source:
{{ file.Read "src/general/requiredlabels/src.cel" | strings.Indent 10 | strings.TrimSuffix "\n" }}
ritazh marked this conversation as resolved.
Show resolved Hide resolved
- engine: Rego
JaydipGabani marked this conversation as resolved.
Show resolved Hide resolved
source:
rego: |
{{ file.Read "src/general/requiredlabels/src.rego" | strings.Indent 12 | strings.TrimSuffix "\n" }}

Loading
Loading