Skip to content

Commit 0919e1d

Browse files
committed
Support custom constraint (templates)
1 parent 67e69cd commit 0919e1d

File tree

6 files changed

+144
-24
lines changed

6 files changed

+144
-24
lines changed

go.mod

+10-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/plexsystems/konstraint
33
go 1.23.0
44

55
require (
6+
github.com/Masterminds/sprig/v3 v3.3.0
67
github.com/open-policy-agent/frameworks/constraint v0.0.0-20220218180203-c2a0d8cdf85a
78
github.com/open-policy-agent/opa v0.69.0
89
github.com/sirupsen/logrus v1.9.3
@@ -15,6 +16,9 @@ require (
1516
)
1617

1718
require (
19+
dario.cat/mergo v1.0.1 // indirect
20+
github.com/Masterminds/goutils v1.1.1 // indirect
21+
github.com/Masterminds/semver/v3 v3.3.0 // indirect
1822
github.com/OneOfOne/xxhash v1.2.8 // indirect
1923
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
2024
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d // indirect
@@ -38,14 +42,17 @@ require (
3842
github.com/google/gofuzz v1.2.0 // indirect
3943
github.com/google/uuid v1.6.0 // indirect
4044
github.com/hashicorp/hcl v1.0.0 // indirect
45+
github.com/huandu/xstrings v1.5.0 // indirect
4146
github.com/imdario/mergo v0.3.13 // indirect
4247
github.com/inconshreveable/mousetrap v1.1.0 // indirect
4348
github.com/josharian/intern v1.0.0 // indirect
4449
github.com/json-iterator/go v1.1.12 // indirect
4550
github.com/klauspost/compress v1.17.9 // indirect
4651
github.com/magiconair/properties v1.8.7 // indirect
4752
github.com/mailru/easyjson v0.7.7 // indirect
53+
github.com/mitchellh/copystructure v1.2.0 // indirect
4854
github.com/mitchellh/mapstructure v1.5.0 // indirect
55+
github.com/mitchellh/reflectwalk v1.0.2 // indirect
4956
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
5057
github.com/modern-go/reflect2 v1.0.2 // indirect
5158
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
@@ -57,16 +64,18 @@ require (
5764
github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475 // indirect
5865
github.com/sagikazarmark/locafero v0.4.0 // indirect
5966
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
67+
github.com/shopspring/decimal v1.4.0 // indirect
6068
github.com/sourcegraph/conc v0.3.0 // indirect
6169
github.com/spf13/afero v1.11.0 // indirect
62-
github.com/spf13/cast v1.6.0 // indirect
70+
github.com/spf13/cast v1.7.0 // indirect
6371
github.com/spf13/pflag v1.0.5 // indirect
6472
github.com/stoewer/go-strcase v1.2.0 // indirect
6573
github.com/subosito/gotenv v1.6.0 // indirect
6674
github.com/x448/float16 v0.8.4 // indirect
6775
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
6876
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
6977
go.uber.org/multierr v1.11.0 // indirect
78+
golang.org/x/crypto v0.27.0 // indirect
7079
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
7180
golang.org/x/net v0.29.0 // indirect
7281
golang.org/x/oauth2 v0.22.0 // indirect

go.sum

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,11 @@
1+
dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s=
2+
dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk=
3+
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
4+
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
5+
github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0=
6+
github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
7+
github.com/Masterminds/sprig/v3 v3.3.0 h1:mQh0Yrg1XPo6vjYXgtf5OtijNAKJRNcTdOOGZe3tPhs=
8+
github.com/Masterminds/sprig/v3 v3.3.0/go.mod h1:Zy1iXRYNqNLUolqCpL4uhk6SHUMAOSCzdgBfDb35Lz0=
19
github.com/OneOfOne/xxhash v1.2.8 h1:31czK/TI9sNkxIKfaUfGlU47BAxQ0ztGgd9vPyqimf8=
210
github.com/OneOfOne/xxhash v1.2.8/go.mod h1:eZbhyaAYD41SGSSsnmcpxVoRiQ/MPUTjUdIIOT9Um7Q=
311
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
@@ -90,6 +98,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0 h1:bkypFPDjIYGfCYD5mRBvpqxfYX1
9098
github.com/grpc-ecosystem/grpc-gateway/v2 v2.20.0/go.mod h1:P+Lt/0by1T8bfcF3z737NnSbmxQAppXMRziHUxPOC8k=
9199
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
92100
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
101+
github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI=
102+
github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
93103
github.com/imdario/mergo v0.3.13 h1:lFzP57bqS/wsqKssCGmtLAb8A0wKjLGrve2q3PPVcBk=
94104
github.com/imdario/mergo v0.3.13/go.mod h1:4lJ1jqUDcsbIECGy0RUJAXNIhg+6ocWgb1ALK2O4oXg=
95105
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -115,8 +125,12 @@ github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0V
115125
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
116126
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
117127
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
128+
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
129+
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
118130
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
119131
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
132+
github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ=
133+
github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
120134
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
121135
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
122136
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -160,14 +174,16 @@ github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6ke
160174
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
161175
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
162176
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
177+
github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k=
178+
github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME=
163179
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
164180
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
165181
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
166182
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
167183
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
168184
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
169-
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
170-
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
185+
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
186+
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
171187
github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
172188
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
173189
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
@@ -234,6 +250,8 @@ go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
234250
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
235251
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
236252
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
253+
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
254+
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
237255
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 h1:GoHiUyI/Tp2nVkLI2mCxVkOjsbSXD66ic0XW0js0R9g=
238256
golang.org/x/exp v0.0.0-20230905200255-921286631fa9/go.mod h1:S2oDrQGGwySpoQPVqRShND87VCbxmc6bL1Yd2oYrm6k=
239257
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
apiVersion: constraints.gatekeeper.sh/v1beta1
2+
kind: {{ .Kind }}
3+
metadata:
4+
{{- if .Annotations }}
5+
annotations: {{- range $key, $value := .Annotations }}
6+
{{ $key }}: {{ $value }}
7+
{{ end -}}
8+
{{ end -}}
9+
{{- if .Labels }}
10+
labels: {{- range $key, $value := .Labels }}
11+
{{ $key }}: {{ $value }}
12+
{{ end -}}
13+
{{ end -}}
14+
name: {{ .Name }}
15+
spec:
16+
match:
17+
kinds:
18+
{{- if ne .Enforcement "deny" }}
19+
enforcementAction: {{ .Enforcement }}
20+
{{- end -}}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
apiVersion: templates.gatekeeper.sh/v1
2+
kind: ConstraintTemplate
3+
metadata:
4+
name: {{ .Name }}
5+
spec:
6+
crd:
7+
spec:
8+
names:
9+
kind: {{ .Kind }}
10+
targets:
11+
- libs: {{- range .Dependencies }}
12+
- |- {{- . | nindent 6 -}}
13+
{{ end }}
14+
rego: |- {{- .Source | nindent 6 }}
15+
target: admission.k8s.gatekeeper.sh

internal/commands/create.go

+77-20
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
package commands
22

33
import (
4+
"bytes"
45
"encoding/json"
56
"fmt"
67
"os"
78
"path/filepath"
9+
"text/template"
810

911
"github.com/plexsystems/konstraint/internal/rego"
1012

13+
"github.com/Masterminds/sprig/v3"
1114
v1 "github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1"
1215
"github.com/open-policy-agent/frameworks/constraint/pkg/apis/templates/v1beta1"
1316
log "github.com/sirupsen/logrus"
@@ -50,10 +53,21 @@ Create constraints with the Gatekeeper enforcement action set to dryrun
5053
if err := viper.BindPFlag("constraint-template-version", cmd.PersistentFlags().Lookup("constraint-template-version")); err != nil {
5154
return fmt.Errorf("bind constraint-template-version flag: %w", err)
5255
}
56+
if err := viper.BindPFlag("constraint-template-custom-template-file", cmd.PersistentFlags().Lookup("constraint-template-custom-template-file")); err != nil {
57+
return fmt.Errorf("bind constraint-template-custom-template-file flag: %w", err)
58+
}
59+
if err := viper.BindPFlag("constraint-custom-template-file", cmd.PersistentFlags().Lookup("constraint-custom-template-file")); err != nil {
60+
return fmt.Errorf("bind constraint-custom-template-file flag: %w", err)
61+
}
62+
5363
if err := viper.BindPFlag("partial-constraints", cmd.PersistentFlags().Lookup("partial-constraints")); err != nil {
5464
return fmt.Errorf("bind partial-constraints flag: %w", err)
5565
}
5666

67+
if cmd.PersistentFlags().Lookup("constraint-template-custom-template-file").Changed && cmd.PersistentFlags().Lookup("constraint-template-version").Changed {
68+
return fmt.Errorf("need to set either constraint-template-custom-template-file or constraint-template-version")
69+
}
70+
5771
path := "."
5872
if len(args) > 0 {
5973
path = args[0]
@@ -68,6 +82,8 @@ Create constraints with the Gatekeeper enforcement action set to dryrun
6882
cmd.PersistentFlags().Bool("skip-constraints", false, "Skip generation of constraints")
6983
cmd.PersistentFlags().String("constraint-template-version", "v1beta1", "Set the version of ConstraintTemplates")
7084
cmd.PersistentFlags().Bool("partial-constraints", false, "Generate partial Constraints for policies with parameters")
85+
cmd.PersistentFlags().String("constraint-template-custom-template-file", "", "Path to a custom template file to generate constraint templates")
86+
cmd.PersistentFlags().String("constraint-custom-template-file", "", "Path to a custom template file to generate constraints")
7187

7288
return &cmd
7389
}
@@ -107,21 +123,36 @@ func runCreateCommand(path string) error {
107123
}
108124

109125
constraintTemplateVersion := viper.GetString("constraint-template-version")
126+
constraintTemplateCustomTemplateFile := viper.GetString("constraint-template-custom-template-file")
127+
110128
var constraintTemplate any
111-
switch constraintTemplateVersion {
112-
case "v1":
113-
constraintTemplate = getConstraintTemplatev1(violation, logger)
114-
case "v1beta1":
115-
constraintTemplate = getConstraintTemplatev1beta1(violation, logger)
116-
default:
117-
return fmt.Errorf("unsupported API version for constrainttemplate: %s", constraintTemplateVersion)
118-
}
129+
var constraintTemplateBytes []byte
119130

120-
constraintTemplateBytes, err := yaml.Marshal(constraintTemplate)
121-
if err != nil {
122-
return fmt.Errorf("marshal constrainttemplate: %w", err)
123-
}
131+
if constraintTemplateCustomTemplateFile != "" {
132+
customTemplate, err := os.ReadFile(constraintTemplateCustomTemplateFile)
133+
if err != nil {
134+
return fmt.Errorf("unable to open/read template file: %w", err)
135+
}
136+
constraintTemplateBytes, err = renderTemplate(violation, customTemplate, logger)
137+
if err != nil {
138+
return fmt.Errorf("unable to render custom template: %w", err)
139+
}
140+
} else {
141+
switch constraintTemplateVersion {
142+
case "v1":
143+
constraintTemplate = getConstraintTemplatev1(violation, logger)
144+
case "v1beta1":
145+
constraintTemplate = getConstraintTemplatev1beta1(violation, logger)
146+
default:
147+
return fmt.Errorf("unsupported API version for constrainttemplate: %s", constraintTemplateVersion)
148+
}
149+
constraintTemplateBytes, err = yaml.Marshal(constraintTemplate)
124150

151+
if err != nil {
152+
return fmt.Errorf("marshal constrainttemplate: %w", err)
153+
}
154+
155+
}
125156
if err := os.WriteFile(filepath.Join(outputDir, templateFileName), constraintTemplateBytes, 0644); err != nil {
126157
return fmt.Errorf("writing template: %w", err)
127158
}
@@ -137,16 +168,28 @@ func runCreateCommand(path string) error {
137168
continue
138169
}
139170

140-
constraint, err := getConstraint(violation, logger)
141-
if err != nil {
142-
return fmt.Errorf("get constraint: %w", err)
143-
}
171+
constraintCustomTemplateFile := viper.GetString("constraint-custom-template-file")
172+
var constraintBytes []byte
173+
if constraintCustomTemplateFile != "" {
174+
customTemplate, err := os.ReadFile(constraintCustomTemplateFile)
175+
if err != nil {
176+
return fmt.Errorf("unable to open/read template file: %w", err)
177+
}
178+
constraintBytes, err = renderTemplate(violation, customTemplate, logger)
179+
if err != nil {
180+
return fmt.Errorf("unable to render custom constraint: %w", err)
181+
}
182+
} else {
183+
constraint, err := getConstraint(violation, logger)
184+
if err != nil {
185+
return fmt.Errorf("get constraint: %w", err)
186+
}
144187

145-
constraintBytes, err := yaml.Marshal(constraint)
146-
if err != nil {
147-
return fmt.Errorf("marshal constraint: %w", err)
188+
constraintBytes, err = yaml.Marshal(constraint)
189+
if err != nil {
190+
return fmt.Errorf("marshal constraint: %w", err)
191+
}
148192
}
149-
150193
if err := os.WriteFile(filepath.Join(outputDir, constraintFileName), constraintBytes, 0644); err != nil {
151194
return fmt.Errorf("writing constraint: %w", err)
152195
}
@@ -157,6 +200,20 @@ func runCreateCommand(path string) error {
157200
return nil
158201
}
159202

203+
func renderTemplate(violation rego.Rego, appliedTemplate []byte, _ *log.Entry) ([]byte, error) {
204+
t, err := template.New("template").Funcs(sprig.FuncMap()).Parse(string(appliedTemplate))
205+
if err != nil {
206+
return nil, fmt.Errorf("parsing template: %w", err)
207+
}
208+
buf := new(bytes.Buffer)
209+
210+
if err := t.Execute(buf, violation); err != nil {
211+
return nil, fmt.Errorf("executing template: %w", err)
212+
}
213+
214+
return buf.Bytes(), nil
215+
}
216+
160217
func getConstraintTemplatev1(violation rego.Rego, logger *log.Entry) *v1.ConstraintTemplate {
161218
constraintTemplate := v1.ConstraintTemplate{
162219
TypeMeta: metav1.TypeMeta{

internal/commands/document.go

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import (
1111

1212
"github.com/plexsystems/konstraint/internal/rego"
1313

14+
"github.com/Masterminds/sprig/v3"
1415
log "github.com/sirupsen/logrus"
1516
"github.com/spf13/cobra"
1617
"github.com/spf13/viper"
@@ -111,7 +112,7 @@ func runDocCommand(path string) error {
111112
appliedTemplate = string(b)
112113
}
113114

114-
t, err := template.New("docs").Parse(appliedTemplate)
115+
t, err := template.New("docs").Funcs(sprig.FuncMap()).Parse(appliedTemplate)
115116

116117
if err != nil {
117118
return fmt.Errorf("parsing template: %w", err)

0 commit comments

Comments
 (0)