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 13 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
14 changes: 9 additions & 5 deletions .github/workflows/workflow.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
gatekeeper: [ "release-3.13", "release-3.14" ]
gatekeeper: [ "release-3.14", "release-3.15" ]
engine: [ "cel", "rego" ]
JaydipGabani marked this conversation as resolved.
Show resolved Hide resolved
name: "Integration test on Gatekeeper ${{ matrix.gatekeeper }}"
steps:
- name: Harden Runner
Expand All @@ -81,7 +82,7 @@ jobs:
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
run: |
Expand All @@ -96,7 +97,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 +128,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 +140,4 @@ jobs:

- uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4
- run: |
make verify-gator-dockerized
make verify-gator-dockerized POLICY_ENGINE=${{ matrix.engine }}
31 changes: 26 additions & 5 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 ?= release-3.15
BATS_VERSION ?= 1.8.2
GATOR_VERSION ?= 3.11.0
GATOR_VERSION ?= 3.15.1
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,7 +32,19 @@ 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
wget https://raw.githubusercontent.com/open-policy-agent/gatekeeper/${GATEKEEPER_VERSION}/deploy/gatekeeper.yaml
ifeq ($(POLICY_ENGINE), rego)
sed -i '/- args:/a \ \ \ \ \ \ \ \ - --validate-template-rego=true' gatekeeper.yaml
JaydipGabani marked this conversation as resolved.
Show resolved Hide resolved
sed -i '/- args:/a \ \ \ \ \ \ \ \ - --experimental-enable-k8s-native-validation=false' gatekeeper.yaml
else ifeq ($(POLICY_ENGINE), cel)
ifeq ($(GATEKEEPER_VERSION), release-3.16)
sed -i '/- args:/a \ \ \ \ \ \ \ \ - --experimental-enable-k8s-native-validation=true' gatekeeper.yaml
else
sed -i '/- args:/a \ \ \ \ \ \ \ \ - --validate-template-rego=false' gatekeeper.yaml
sed -i '/- args:/a \ \ \ \ \ \ \ \ - --experimental-enable-k8s-native-validation=true' gatekeeper.yaml
endif
endif
kubectl apply -f gatekeeper.yaml

uninstall:
kubectl delete -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/${GATEKEEPER_VERSION}/deploy/gatekeeper.yaml
Expand All @@ -41,11 +54,19 @@ test-integration:

.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.0.2
name: k8srequiredlabels
displayName: Required Labels
createdAt: "2024-05-02T19:01:02Z"
description: Requires resources to contain specified labels, with values matching provided regular expressions.
digest: f23618ee55f71e661846ff24d3e06ed0178394be5f6733fa5a14f8b544a8f590
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.0.2/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.0.2/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.0.2/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.0.2
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.0.2
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.0.2
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
metadata.gatekeeper.sh/version: 1.0.2
metadata.gatekeeper.sh/version: 1.1.0

do we want to at least bump the minor version? @maxsmythe @sozercan

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

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" }}

5 changes: 5 additions & 0 deletions src/general/requiredlabels/src.cel
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
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))))'
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please test the regex use case? Maybe even add a test for it?

!string(object.metadata.labels[entry.key]).matches(string(entry.allowedRegex)

This feels incorrect...it should match on the allowedRegex not !. Please test and verify this. The example in GK might also be wrong.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ritazh I think we need it to not match on the allowedRegex. If value do not match the allowedRegex then its a violation otherwise it is not.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the example testing the same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I missed !variable :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ritazh I changed the CEL source. Let me know what you think.

message: "regex mismatch"
ritazh marked this conversation as resolved.
Show resolved Hide resolved
Loading