1
0
Fork 0
mirror of https://github.com/kyverno/policy-reporter.git synced 2024-12-15 17:50:58 +00:00

Add customFields to missing targets

Signed-off-by: Frank Jogeleit <frank.jogeleit@web.de>
This commit is contained in:
Frank Jogeleit 2022-10-17 10:31:11 +02:00
parent ab90514fc3
commit 573a1108c7
16 changed files with 224 additions and 99 deletions

View file

@ -1,5 +1,11 @@
# Changelog # Changelog
# 2.13.2
* Policy Reporter
* Add `customFields` property to missing targets: `Elasticsearch`, `S3`, `Webhook`, `Kinesis`
* Policy Reporter UI
* Create Links out of URL property values
# 2.13.1 # 2.13.1
* Policy Reporter * Policy Reporter

View file

@ -4,9 +4,9 @@ dependencies:
version: 2.4.1 version: 2.4.1
- name: ui - name: ui
repository: "" repository: ""
version: 2.6.4 version: 2.6.5
- name: kyvernoPlugin - name: kyvernoPlugin
repository: "" repository: ""
version: 1.4.3 version: 1.4.3
digest: sha256:688fdfcd63fee5b3b9e24b8a15591590235ddab3967b48ae2768e00762b2e66c digest: sha256:34f738ba910f4eeddb3b278fa73fd891bb19f7327bffa850d7f8300c967b7edb
generated: "2022-09-23T11:22:26.239174+02:00" generated: "2022-10-17T10:19:27.566911+02:00"

View file

@ -5,8 +5,8 @@ description: |
It creates Prometheus Metrics and can send rule validation events to different targets like Loki, Elasticsearch, Slack or Discord It creates Prometheus Metrics and can send rule validation events to different targets like Loki, Elasticsearch, Slack or Discord
type: application type: application
version: 2.13.1 version: 2.13.2
appVersion: 2.10.1 appVersion: 2.10.2
icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png
home: https://kyverno.github.io/policy-reporter home: https://kyverno.github.io/policy-reporter
@ -21,7 +21,7 @@ dependencies:
version: "2.4.1" version: "2.4.1"
- name: ui - name: ui
condition: ui.enabled condition: ui.enabled
version: "2.6.4" version: "2.6.5"
- name: kyvernoPlugin - name: kyvernoPlugin
condition: kyvernoPlugin.enabled condition: kyvernoPlugin.enabled
version: "1.4.3" version: "1.4.3"

View file

@ -3,5 +3,5 @@ name: ui
description: Policy Reporter UI description: Policy Reporter UI
type: application type: application
version: 2.6.4 version: 2.6.5
appVersion: 1.6.6 appVersion: 1.6.7

View file

@ -4,7 +4,7 @@ image:
registry: ghcr.io registry: ghcr.io
repository: kyverno/policy-reporter-ui repository: kyverno/policy-reporter-ui
pullPolicy: IfNotPresent pullPolicy: IfNotPresent
tag: 1.6.6 tag: 1.6.7
# possible default displayModes: light/dark # possible default displayModes: light/dark
displayMode: "" displayMode: ""

View file

@ -38,6 +38,10 @@ elasticsearch:
sources: sources:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
{{- with .Values.target.elasticsearch.customFields }}
customFields:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.target.elasticsearch.filter }} {{- with .Values.target.elasticsearch.filter }}
filter: filter:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
@ -126,6 +130,10 @@ webhook:
sources: sources:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
{{- with .Values.target.webhook.customFields }}
customFields:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.target.webhook.filter }} {{- with .Values.target.webhook.filter }}
filter: filter:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
@ -160,6 +168,10 @@ s3:
sources: sources:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
{{- with .Values.target.s3.customFields }}
customFields:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.target.s3.filter }} {{- with .Values.target.s3.filter }}
filter: filter:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
@ -182,6 +194,10 @@ kinesis:
sources: sources:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}
{{- end }} {{- end }}
{{- with .Values.target.kinesis.customFields }}
customFields:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- with .Values.target.kinesis.filter }} {{- with .Values.target.kinesis.filter }}
filter: filter:
{{- toYaml . | nindent 4 }} {{- toYaml . | nindent 4 }}

View file

@ -292,6 +292,8 @@ target:
sources: [] sources: []
# Skip already existing PolicyReportResults on startup # Skip already existing PolicyReportResults on startup
skipExistingOnStartup: true skipExistingOnStartup: true
# Added as additional properties to each elasticsearch event
customField: {}
# filter results send by namespaces, policies and priorities # filter results send by namespaces, policies and priorities
filter: {} filter: {}
# add additional elasticsearch channels with different configurations and filters # add additional elasticsearch channels with different configurations and filters
@ -398,6 +400,8 @@ target:
sources: [] sources: []
# Skip already existing PolicyReportResults on startup # Skip already existing PolicyReportResults on startup
skipExistingOnStartup: true skipExistingOnStartup: true
# Added as additional properties to each webhook event
customField: {}
# filter results send by namespaces, policies and priorities # filter results send by namespaces, policies and priorities
filter: {} filter: {}
# add additional webhook channels with different configurations and filters # add additional webhook channels with different configurations and filters
@ -424,6 +428,8 @@ target:
sources: [] sources: []
# Skip already existing PolicyReportResults on startup # Skip already existing PolicyReportResults on startup
skipExistingOnStartup: true skipExistingOnStartup: true
# Added as additional properties to each s3 event
customField: {}
# filter results send by namespaces, policies and priorities # filter results send by namespaces, policies and priorities
filter: {} filter: {}
# add additional s3 channels with different configurations and filters # add additional s3 channels with different configurations and filters
@ -448,6 +454,8 @@ target:
sources: [] sources: []
# Skip already existing PolicyReportResults on startup # Skip already existing PolicyReportResults on startup
skipExistingOnStartup: true skipExistingOnStartup: true
# Added as additional properties to each kinesis event
customField: {}
# filter results send by namespaces, policies and priorities # filter results send by namespaces, policies and priorities
filter: {} filter: {}
# add additional s3 channels with different configurations and filters # add additional s3 channels with different configurations and filters

View file

@ -52,6 +52,7 @@ type Elasticsearch struct {
Username string `mapstructure:"username"` Username string `mapstructure:"username"`
Password string `mapstructure:"password"` Password string `mapstructure:"password"`
SecretRef string `mapstructure:"secretRef"` SecretRef string `mapstructure:"secretRef"`
CustomFields map[string]string `mapstructure:"customFields"`
SkipExisting bool `mapstructure:"skipExistingOnStartup"` SkipExisting bool `mapstructure:"skipExistingOnStartup"`
MinimumPriority string `mapstructure:"minimumPriority"` MinimumPriority string `mapstructure:"minimumPriority"`
Filter TargetFilter `mapstructure:"filter"` Filter TargetFilter `mapstructure:"filter"`
@ -118,6 +119,7 @@ type Webhook struct {
Certificate string `mapstructure:"certificate"` Certificate string `mapstructure:"certificate"`
Headers map[string]string `mapstructure:"headers"` Headers map[string]string `mapstructure:"headers"`
SecretRef string `mapstructure:"secretRef"` SecretRef string `mapstructure:"secretRef"`
CustomFields map[string]string `mapstructure:"customFields"`
SkipExisting bool `mapstructure:"skipExistingOnStartup"` SkipExisting bool `mapstructure:"skipExistingOnStartup"`
MinimumPriority string `mapstructure:"minimumPriority"` MinimumPriority string `mapstructure:"minimumPriority"`
Filter TargetFilter `mapstructure:"filter"` Filter TargetFilter `mapstructure:"filter"`
@ -135,6 +137,7 @@ type S3 struct {
Prefix string `mapstructure:"prefix"` Prefix string `mapstructure:"prefix"`
Bucket string `mapstructure:"bucket"` Bucket string `mapstructure:"bucket"`
SecretRef string `mapstructure:"secretRef"` SecretRef string `mapstructure:"secretRef"`
CustomFields map[string]string `mapstructure:"customFields"`
SkipExisting bool `mapstructure:"skipExistingOnStartup"` SkipExisting bool `mapstructure:"skipExistingOnStartup"`
MinimumPriority string `mapstructure:"minimumPriority"` MinimumPriority string `mapstructure:"minimumPriority"`
Filter TargetFilter `mapstructure:"filter"` Filter TargetFilter `mapstructure:"filter"`
@ -151,6 +154,7 @@ type Kinesis struct {
Endpoint string `mapstructure:"endpoint"` Endpoint string `mapstructure:"endpoint"`
StreamName string `mapstructure:"streamName"` StreamName string `mapstructure:"streamName"`
SecretRef string `mapstructure:"secretRef"` SecretRef string `mapstructure:"secretRef"`
CustomFields map[string]string `mapstructure:"customFields"`
SkipExisting bool `mapstructure:"skipExistingOnStartup"` SkipExisting bool `mapstructure:"skipExistingOnStartup"`
MinimumPriority string `mapstructure:"minimumPriority"` MinimumPriority string `mapstructure:"minimumPriority"`
Filter TargetFilter `mapstructure:"filter"` Filter TargetFilter `mapstructure:"filter"`

View file

@ -16,6 +16,7 @@ type Options struct {
Password string Password string
Index string Index string
Rotation string Rotation string
CustomFields map[string]string
HTTPClient http.Client HTTPClient http.Client
} }
@ -37,6 +38,7 @@ type client struct {
username string username string
password string password string
rotation Rotation rotation Rotation
customFields map[string]string
client http.Client client http.Client
} }
@ -53,6 +55,20 @@ func (e *client) Send(result report.Result) {
host = e.host + "/" + e.index + "-" + time.Now().Format("2006.01.02") + "/event" host = e.host + "/" + e.index + "-" + time.Now().Format("2006.01.02") + "/event"
} }
if len(e.customFields) > 0 {
props := make(map[string]string, 0)
for property, value := range e.customFields {
props[property] = value
}
for property, value := range result.Properties {
props[property] = value
}
result.Properties = props
}
req, err := http.CreateJSONRequest(e.Name(), "POST", host, result) req, err := http.CreateJSONRequest(e.Name(), "POST", host, result)
if err != nil { if err != nil {
return return
@ -75,6 +91,7 @@ func NewClient(options Options) target.Client {
options.Username, options.Username,
options.Password, options.Password,
options.Rotation, options.Rotation,
options.CustomFields,
options.HTTPClient, options.HTTPClient,
} }
} }

View file

@ -74,8 +74,13 @@ func Test_ElasticsearchTarget(t *testing.T) {
Index: "policy-reporter", Index: "policy-reporter",
Rotation: elasticsearch.Annually, Rotation: elasticsearch.Annually,
HTTPClient: testClient{callback, 200}, HTTPClient: testClient{callback, 200},
CustomFields: map[string]string{"cluster": "name"},
}) })
client.Send(completeResult) client.Send(completeResult)
if len(completeResult.Properties) > 1 {
t.Error("expected customFields are not added to the actuel result")
}
}) })
t.Run("Send with Monthly Result", func(t *testing.T) { t.Run("Send with Monthly Result", func(t *testing.T) {
callback := func(req *http.Request) { callback := func(req *http.Request) {

View file

@ -15,15 +15,31 @@ import (
// Options to configure the Kinesis target // Options to configure the Kinesis target
type Options struct { type Options struct {
target.ClientOptions target.ClientOptions
CustomFields map[string]string
Kinesis helper.AWSClient Kinesis helper.AWSClient
} }
type client struct { type client struct {
target.BaseClient target.BaseClient
customFields map[string]string
kinesis helper.AWSClient kinesis helper.AWSClient
} }
func (c *client) Send(result report.Result) { func (c *client) Send(result report.Result) {
if len(c.customFields) > 0 {
props := make(map[string]string, 0)
for property, value := range c.customFields {
props[property] = value
}
for property, value := range result.Properties {
props[property] = value
}
result.Properties = props
}
body := new(bytes.Buffer) body := new(bytes.Buffer)
if err := json.NewEncoder(body).Encode(result); err != nil { if err := json.NewEncoder(body).Encode(result); err != nil {
@ -45,6 +61,7 @@ func (c *client) Send(result report.Result) {
func NewClient(options Options) target.Client { func NewClient(options Options) target.Client {
return &client{ return &client{
target.NewBaseClient(options.ClientOptions), target.NewBaseClient(options.ClientOptions),
options.CustomFields,
options.Kinesis, options.Kinesis,
} }
} }

View file

@ -19,6 +19,7 @@ var completeResult = report.Result{
Severity: report.High, Severity: report.High,
Category: "resources", Category: "resources",
Scored: true, Scored: true,
Properties: map[string]string{"version": "1234"},
Resource: report.Resource{ Resource: report.Resource{
APIVersion: "v1", APIVersion: "v1",
Kind: "Deployment", Kind: "Deployment",
@ -61,9 +62,14 @@ func Test_KinesisTarget(t *testing.T) {
ClientOptions: target.ClientOptions{ ClientOptions: target.ClientOptions{
Name: "Kinesis", Name: "Kinesis",
}, },
CustomFields: map[string]string{"cluster": "name"},
Kinesis: &testClient{nil, callback}, Kinesis: &testClient{nil, callback},
}) })
client.Send(completeResult) client.Send(completeResult)
if len(completeResult.Properties) > 1 || completeResult.Properties["cluster"] != "" {
t.Error("expected customFields are not added to the actuel result")
}
}) })
t.Run("Name", func(t *testing.T) { t.Run("Name", func(t *testing.T) {
client := kinesis.NewClient(kinesis.Options{ client := kinesis.NewClient(kinesis.Options{

View file

@ -15,17 +15,33 @@ import (
// Options to configure the Kinesis target // Options to configure the Kinesis target
type Options struct { type Options struct {
target.ClientOptions target.ClientOptions
CustomFields map[string]string
S3 helper.AWSClient S3 helper.AWSClient
Prefix string Prefix string
} }
type client struct { type client struct {
target.BaseClient target.BaseClient
customFields map[string]string
s3 helper.AWSClient s3 helper.AWSClient
prefix string prefix string
} }
func (c *client) Send(result report.Result) { func (c *client) Send(result report.Result) {
if len(c.customFields) > 0 {
props := make(map[string]string, 0)
for property, value := range c.customFields {
props[property] = value
}
for property, value := range result.Properties {
props[property] = value
}
result.Properties = props
}
body := new(bytes.Buffer) body := new(bytes.Buffer)
if err := json.NewEncoder(body).Encode(result); err != nil { if err := json.NewEncoder(body).Encode(result); err != nil {
@ -47,6 +63,7 @@ func (c *client) Send(result report.Result) {
func NewClient(options Options) target.Client { func NewClient(options Options) target.Client {
return &client{ return &client{
target.NewBaseClient(options.ClientOptions), target.NewBaseClient(options.ClientOptions),
options.CustomFields,
options.S3, options.S3,
options.Prefix, options.Prefix,
} }

View file

@ -19,6 +19,7 @@ var completeResult = report.Result{
Severity: report.High, Severity: report.High,
Category: "resources", Category: "resources",
Scored: true, Scored: true,
Properties: map[string]string{"version": "1234"},
Resource: report.Resource{ Resource: report.Resource{
APIVersion: "v1", APIVersion: "v1",
Kind: "Deployment", Kind: "Deployment",
@ -57,9 +58,14 @@ func Test_S3Target(t *testing.T) {
ClientOptions: target.ClientOptions{ ClientOptions: target.ClientOptions{
Name: "S3", Name: "S3",
}, },
CustomFields: map[string]string{"cluster": "name"},
S3: &testClient{nil, callback}, S3: &testClient{nil, callback},
}) })
client.Send(completeResult) client.Send(completeResult)
if len(completeResult.Properties) > 1 || completeResult.Properties["cluster"] != "" {
t.Error("expected customFields are not added to the actuel result")
}
}) })
t.Run("Name", func(t *testing.T) { t.Run("Name", func(t *testing.T) {
client := s3.NewClient(s3.Options{ client := s3.NewClient(s3.Options{

View file

@ -11,6 +11,7 @@ type Options struct {
target.ClientOptions target.ClientOptions
Host string Host string
Headers map[string]string Headers map[string]string
CustomFields map[string]string
HTTPClient http.Client HTTPClient http.Client
} }
@ -18,10 +19,25 @@ type client struct {
target.BaseClient target.BaseClient
host string host string
headers map[string]string headers map[string]string
customFields map[string]string
client http.Client client http.Client
} }
func (e *client) Send(result report.Result) { func (e *client) Send(result report.Result) {
if len(e.customFields) > 0 {
props := make(map[string]string, 0)
for property, value := range e.customFields {
props[property] = value
}
for property, value := range result.Properties {
props[property] = value
}
result.Properties = props
}
req, err := http.CreateJSONRequest(e.Name(), "POST", e.host, http.NewJSONResult(result)) req, err := http.CreateJSONRequest(e.Name(), "POST", e.host, http.NewJSONResult(result))
if err != nil { if err != nil {
return return
@ -41,6 +57,7 @@ func NewClient(options Options) target.Client {
target.NewBaseClient(options.ClientOptions), target.NewBaseClient(options.ClientOptions),
options.Host, options.Host,
options.Headers, options.Headers,
options.CustomFields,
options.HTTPClient, options.HTTPClient,
} }
} }

View file

@ -27,6 +27,7 @@ var completeResult = report.Result{
Namespace: "default", Namespace: "default",
UID: "536ab69f-1b3c-4bd9-9ba4-274a56188409", UID: "536ab69f-1b3c-4bd9-9ba4-274a56188409",
}, },
Properties: map[string]string{"version": "1234"},
} }
type testClient struct { type testClient struct {
@ -71,9 +72,14 @@ func Test_UITarget(t *testing.T) {
}, },
Host: "http://localhost:8080/webhook", Host: "http://localhost:8080/webhook",
Headers: map[string]string{"X-Code": "1234"}, Headers: map[string]string{"X-Code": "1234"},
CustomFields: map[string]string{"cluster": "name"},
HTTPClient: testClient{callback, 200}, HTTPClient: testClient{callback, 200},
}) })
client.Send(completeResult) client.Send(completeResult)
if len(completeResult.Properties) > 1 || completeResult.Properties["cluster"] != "" {
t.Error("expected customFields are not added to the actuel result")
}
}) })
t.Run("Name", func(t *testing.T) { t.Run("Name", func(t *testing.T) {
client := webhook.NewClient(webhook.Options{ client := webhook.NewClient(webhook.Options{