Skip to content

Commit 18719ab

Browse files
authored
Support custom constraint (templates) (#553)
* Support custom constraint (templates) * Remove logging parameter from renderTemplate * Move template rendering into own func * Add acceptance test * Add tests
1 parent 3f954e3 commit 18719ab

13 files changed

+455
-42
lines changed

acceptance.bats

+6
Original file line numberDiff line numberDiff line change
@@ -23,3 +23,9 @@
2323
[ "$status" -eq 0 ]
2424
git diff --quiet -- test/
2525
}
26+
27+
@test "[CREATE] Creating constraints using --constraint-custom-template-file, --constraint-template-custom-template-file and --output matches expected output" {
28+
run ./build/konstraint create test --constraint-custom-template-file internal/commands/constraint_template.tpl --constraint-template-custom-template-file internal/commands/constrainttemplate_template.tpl --partial-constraints --output test/custom
29+
[ "$status" -eq 0 ]
30+
git diff --quiet -- test/custom
31+
}

docs/cli/konstraint_create.md

+8-6
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,14 @@ Create constraints with the Gatekeeper enforcement action set to dryrun
2222
### Options
2323

2424
```
25-
--constraint-template-version string Set the version of ConstraintTemplates (default "v1beta1")
26-
-d, --dryrun Sets the enforcement action of the constraints to dryrun, overriding the @enforcement tag
27-
-h, --help help for create
28-
-o, --output string Specify an output directory for the Gatekeeper resources
29-
--partial-constraints Generate partial Constraints for policies with parameters
30-
--skip-constraints Skip generation of constraints
25+
--constraint-custom-template-file string Path to a custom template file to generate constraints
26+
--constraint-template-custom-template-file string Path to a custom template file to generate constraint templates
27+
--constraint-template-version string Set the version of ConstraintTemplates (default "v1beta1")
28+
-d, --dryrun Sets the enforcement action of the constraints to dryrun, overriding the @enforcement tag
29+
-h, --help help for create
30+
-o, --output string Specify an output directory for the Gatekeeper resources
31+
--partial-constraints Generate partial Constraints for policies with parameters
32+
--skip-constraints Skip generation of constraints
3133
```
3234

3335
### SEE ALSO

docs/constraint_creation.md

+5
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ violation[{"msg": msg}] {
103103
}
104104
```
105105

106+
### Custom templates for Constraint and/or ConstraintTemplate resources
107+
108+
In some cases there might be the need to further customize the rendered Constraint and ConstraintTemplates. This is particularly helpful, if you want to create e.g. template for Helm charts, where certain values are additional fields to be rendered through Helm.
109+
You can provide custom templates through the `--constraint-template-custom-template-file` and `--constraint-custom-template-file` command line flags.
110+
106111
### Skipping generation of the Constraint and/or ConstraintTemplate resource
107112

108113
In some scenarios, you may wish for Konstraint to skip the generation of the `Constraint` resource for a policy and manage that externally. To do so, add the `skipConstraint: true` annotation in the custom metadata section.

go.mod

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
module github.com/plexsystems/konstraint
22

3-
go 1.23.0
3+
go 1.23.4
44

55
require (
6+
github.com/go-sprout/sprout v1.0.0
7+
github.com/google/go-cmp v0.6.0
68
github.com/open-policy-agent/frameworks/constraint v0.0.0-20220218180203-c2a0d8cdf85a
79
github.com/open-policy-agent/opa v1.1.0
810
github.com/sirupsen/logrus v1.9.3
@@ -16,6 +18,8 @@ require (
1618

1719
require (
1820
cel.dev/expr v0.19.0 // indirect
21+
dario.cat/mergo v1.0.1 // indirect
22+
github.com/Masterminds/semver/v3 v3.3.1 // indirect
1923
github.com/OneOfOne/xxhash v1.2.8 // indirect
2024
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
2125
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
@@ -34,14 +38,17 @@ require (
3438
github.com/google/cel-go v0.22.0 // indirect
3539
github.com/google/gnostic-models v0.6.8 // indirect
3640
github.com/google/gofuzz v1.2.0 // indirect
41+
github.com/google/uuid v1.6.0 // indirect
3742
github.com/hashicorp/hcl v1.0.0 // indirect
3843
github.com/inconshreveable/mousetrap v1.1.0 // indirect
3944
github.com/josharian/intern v1.0.0 // indirect
4045
github.com/json-iterator/go v1.1.12 // indirect
4146
github.com/klauspost/compress v1.17.11 // indirect
4247
github.com/magiconair/properties v1.8.7 // indirect
4348
github.com/mailru/easyjson v0.7.7 // indirect
49+
github.com/mitchellh/copystructure v1.2.0 // indirect
4450
github.com/mitchellh/mapstructure v1.5.0 // indirect
51+
github.com/mitchellh/reflectwalk v1.0.2 // indirect
4552
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
4653
github.com/modern-go/reflect2 v1.0.2 // indirect
4754
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -55,7 +62,7 @@ require (
5562
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
5663
github.com/sourcegraph/conc v0.3.0 // indirect
5764
github.com/spf13/afero v1.11.0 // indirect
58-
github.com/spf13/cast v1.6.0 // indirect
65+
github.com/spf13/cast v1.7.1 // indirect
5966
github.com/spf13/pflag v1.0.5 // indirect
6067
github.com/stoewer/go-strcase v1.3.0 // indirect
6168
github.com/subosito/gotenv v1.6.0 // indirect
@@ -65,9 +72,9 @@ require (
6572
go.opentelemetry.io/otel v1.34.0 // indirect
6673
go.opentelemetry.io/otel/trace v1.34.0 // indirect
6774
go.uber.org/multierr v1.11.0 // indirect
75+
golang.org/x/crypto v0.32.0 // indirect
6876
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
6977
golang.org/x/net v0.34.0 // indirect
70-
golang.org/x/oauth2 v0.24.0 // indirect
7178
golang.org/x/sync v0.11.0 // indirect
7279
golang.org/x/sys v0.29.0 // indirect
7380
google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect

go.sum

+17-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
cel.dev/expr v0.19.0 h1:lXuo+nDhpyJSpWxpPVi5cPUwzKb+dsdOiw6IreM5yt0=
22
cel.dev/expr v0.19.0/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
3+
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
4+
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
5+
github.com/Masterminds/semver/v3 v3.3.1 h1:QtNSWtVZ3nBfk8mAOu/B6v7FMJ+NHTIgUPi7rj+4nv4=
6+
github.com/Masterminds/semver/v3 v3.3.1/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
37
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
48
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
59
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
@@ -54,6 +58,8 @@ github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En
5458
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
5559
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
5660
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
61+
github.com/go-sprout/sprout v1.0.0 h1:4uxG1fZbUxfXB2OsjwzyIOK4lZQEhsksib17vVAZqOs=
62+
github.com/go-sprout/sprout v1.0.0/go.mod h1:I6ifgKakZI/NOkFyZueoS5N0qENvI5ZWcWT7oM34vsE=
5763
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
5864
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
5965
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
@@ -108,8 +114,12 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
108114
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
109115
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
110116
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
117+
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
118+
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
111119
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
112120
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
121+
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
122+
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
113123
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
114124
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
115125
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -157,8 +167,8 @@ github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9yS
157167
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
158168
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
159169
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
160-
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
161-
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
170+
github.com/spf13/cast v1.7.1 h1:cuNEagBQEHWN1FnbGEjCXL2szYEXqfJPbP2HNUaca9Y=
171+
github.com/spf13/cast v1.7.1/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
162172
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
163173
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
164174
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -170,6 +180,7 @@ github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8w
170180
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
171181
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
172182
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
183+
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
173184
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
174185
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
175186
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -227,6 +238,8 @@ go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
227238
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
228239
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
229240
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
241+
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
242+
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
230243
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
231244
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
232245
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -237,8 +250,8 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
237250
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
238251
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
239252
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
240-
golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE=
241-
golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
253+
golang.org/x/oauth2 v0.23.0 h1:PbgcYx2W7i4LvjJWEbf0ngHV6qJYr86PkAV3bXdLEbs=
254+
golang.org/x/oauth2 v0.23.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
242255
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
243256
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
244257
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This is a custom template for constraints
2+
apiVersion: constraints.gatekeeper.sh/v1beta1
3+
kind: {{ .Kind }}
4+
metadata:
5+
{{- if .Annotations }}
6+
annotations: {{- .Annotations | toIndentYAML 2 | nindent 4 }}
7+
{{- end }}
8+
{{- if .Labels }}
9+
labels: {{ .Labels | toIndentYAML 2 | nindent 4 }}
10+
{{- end }}
11+
name: {{ .Name }}
12+
spec:
13+
{{- if .Matchers }}
14+
match: {{- .GetAnnotation "matchers" | toIndentYAML 2 | nindent 4 }}
15+
{{- end }}
16+
{{- if ne .Enforcement "deny" }}
17+
enforcementAction: {{ .Enforcement }}
18+
{{- end -}}
19+
{{- if .AnnotationParameters }}
20+
parameters: {{- .AnnotationParameters | toIndentYAML 2 | nindent 4 }}
21+
{{- end }}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# This is a custom template for a constraint template
2+
apiVersion: templates.gatekeeper.sh/v1
3+
kind: ConstraintTemplate
4+
metadata:
5+
name: {{ .Name }}
6+
spec:
7+
crd:
8+
spec:
9+
names:
10+
kind: {{ .Kind }}
11+
{{- if .AnnotationParameters }}
12+
validation:
13+
openAPIV3Schema:
14+
properties: {{- .AnnotationParameters | toJSON | fromJSON | toIndentYAML 2 | nindent 12 }}
15+
{{- end }}
16+
targets:
17+
- libs: {{- range .Dependencies }}
18+
- |- {{- . | nindent 6 -}}
19+
{{ end }}
20+
rego: |- {{- .Source | nindent 6 }}
21+
target: admission.k8s.gatekeeper.sh

0 commit comments

Comments
 (0)