mirror of
https://github.com/kyverno/policy-reporter.git
synced 2024-12-15 17:50:58 +00:00
Add support for elasticSearch typeless API (#387)
* Add support for elasticSearch typeless API Signed-off-by: guipal <guillermo.palacio@docplanner.com>
This commit is contained in:
parent
bf13160e57
commit
c73670a8f9
8 changed files with 53 additions and 5 deletions
|
@ -30,13 +30,14 @@ elasticsearch:
|
||||||
skipTLS: {{ .Values.target.elasticsearch.skipTLS }}
|
skipTLS: {{ .Values.target.elasticsearch.skipTLS }}
|
||||||
username: {{ .Values.target.elasticsearch.username | quote }}
|
username: {{ .Values.target.elasticsearch.username | quote }}
|
||||||
password: {{ .Values.target.elasticsearch.password | quote }}
|
password: {{ .Values.target.elasticsearch.password | quote }}
|
||||||
apiKey: {{ .Values.target.elasticsearch.password | quote }}
|
apiKey: {{ .Values.target.elasticsearch.apiKey | quote }}
|
||||||
secretRef: {{ .Values.target.elasticsearch.secretRef | quote }}
|
secretRef: {{ .Values.target.elasticsearch.secretRef | quote }}
|
||||||
mountedSecret: {{ .Values.target.elasticsearch.mountedSecret | quote }}
|
mountedSecret: {{ .Values.target.elasticsearch.mountedSecret | quote }}
|
||||||
index: {{ .Values.target.elasticsearch.index | default "policy-reporter" | quote }}
|
index: {{ .Values.target.elasticsearch.index | default "policy-reporter" | quote }}
|
||||||
rotation: {{ .Values.target.elasticsearch.rotation | default "daily" | quote }}
|
rotation: {{ .Values.target.elasticsearch.rotation | default "daily" | quote }}
|
||||||
minimumPriority: {{ .Values.target.elasticsearch.minimumPriority | quote }}
|
minimumPriority: {{ .Values.target.elasticsearch.minimumPriority | quote }}
|
||||||
skipExistingOnStartup: {{ .Values.target.elasticsearch.skipExistingOnStartup }}
|
skipExistingOnStartup: {{ .Values.target.elasticsearch.skipExistingOnStartup }}
|
||||||
|
typelessApi: {{ .Values.target.elasticsearch.typelessApi }}
|
||||||
{{- with .Values.target.elasticsearch.sources }}
|
{{- with .Values.target.elasticsearch.sources }}
|
||||||
sources:
|
sources:
|
||||||
{{- toYaml . | nindent 4 }}
|
{{- toYaml . | nindent 4 }}
|
||||||
|
|
|
@ -377,6 +377,8 @@ target:
|
||||||
sources: []
|
sources: []
|
||||||
# Skip already existing PolicyReportResults on startup
|
# Skip already existing PolicyReportResults on startup
|
||||||
skipExistingOnStartup: true
|
skipExistingOnStartup: true
|
||||||
|
# https://www.elastic.co/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0 keeping as false for retrocompatibility.
|
||||||
|
typelessApi: false
|
||||||
# Added as additional properties to each elasticsearch event
|
# Added as additional properties to each elasticsearch event
|
||||||
customFields: {}
|
customFields: {}
|
||||||
# filter results send by namespaces, policies and priorities
|
# filter results send by namespaces, policies and priorities
|
||||||
|
|
|
@ -110,6 +110,7 @@ type Elasticsearch struct {
|
||||||
Password string `mapstructure:"password"`
|
Password string `mapstructure:"password"`
|
||||||
ApiKey string `mapstructure:"apiKey"`
|
ApiKey string `mapstructure:"apiKey"`
|
||||||
Channels []*Elasticsearch `mapstructure:"channels"`
|
Channels []*Elasticsearch `mapstructure:"channels"`
|
||||||
|
TypelessApi bool `mapstructure:"typelessApi"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Slack configuration
|
// Slack configuration
|
||||||
|
|
|
@ -411,6 +411,7 @@ func (f *TargetFactory) createElasticsearchClient(config, parent *Elasticsearch)
|
||||||
setFallback(&config.ApiKey, parent.ApiKey)
|
setFallback(&config.ApiKey, parent.ApiKey)
|
||||||
setFallback(&config.Index, parent.Index, "policy-reporter")
|
setFallback(&config.Index, parent.Index, "policy-reporter")
|
||||||
setFallback(&config.Rotation, parent.Rotation, elasticsearch.Daily)
|
setFallback(&config.Rotation, parent.Rotation, elasticsearch.Daily)
|
||||||
|
setBool(&config.TypelessApi, parent.TypelessApi)
|
||||||
|
|
||||||
config.MapBaseParent(parent.TargetBaseOptions)
|
config.MapBaseParent(parent.TargetBaseOptions)
|
||||||
|
|
||||||
|
@ -426,6 +427,7 @@ func (f *TargetFactory) createElasticsearchClient(config, parent *Elasticsearch)
|
||||||
Index: config.Index,
|
Index: config.Index,
|
||||||
CustomFields: config.CustomFields,
|
CustomFields: config.CustomFields,
|
||||||
HTTPClient: http.NewClient(config.Certificate, config.SkipTLS),
|
HTTPClient: http.NewClient(config.Certificate, config.SkipTLS),
|
||||||
|
TypelessApi: config.TypelessApi,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,6 +829,9 @@ func (f *TargetFactory) mapSecretValues(config any, ref, mountedSecret string) {
|
||||||
if values.ApiKey != "" {
|
if values.ApiKey != "" {
|
||||||
c.ApiKey = values.ApiKey
|
c.ApiKey = values.ApiKey
|
||||||
}
|
}
|
||||||
|
if values.TypelessApi != false {
|
||||||
|
c.TypelessApi = values.TypelessApi
|
||||||
|
}
|
||||||
|
|
||||||
case *S3:
|
case *S3:
|
||||||
if values.AccessKeyID != "" {
|
if values.AccessKeyID != "" {
|
||||||
|
|
|
@ -40,6 +40,7 @@ func newFakeClient() v1.SecretInterface {
|
||||||
"credentials": []byte(`{"token": "token", "type": "authorized_user"}`),
|
"credentials": []byte(`{"token": "token", "type": "authorized_user"}`),
|
||||||
"database": []byte("database"),
|
"database": []byte("database"),
|
||||||
"dsn": []byte(""),
|
"dsn": []byte(""),
|
||||||
|
"typelessApi": []byte("false"),
|
||||||
},
|
},
|
||||||
}).CoreV1().Secrets("default")
|
}).CoreV1().Secrets("default")
|
||||||
}
|
}
|
||||||
|
@ -58,6 +59,7 @@ func mountSecret() {
|
||||||
Credentials: `{"token": "token", "type": "authorized_user"}`,
|
Credentials: `{"token": "token", "type": "authorized_user"}`,
|
||||||
Database: "database",
|
Database: "database",
|
||||||
DSN: "",
|
DSN: "",
|
||||||
|
TypelessApi: false,
|
||||||
}
|
}
|
||||||
file, _ := json.MarshalIndent(secretValues, "", " ")
|
file, _ := json.MarshalIndent(secretValues, "", " ")
|
||||||
_ = os.WriteFile(mountedSecret, file, 0o644)
|
_ = os.WriteFile(mountedSecret, file, 0o644)
|
||||||
|
@ -339,6 +341,11 @@ func Test_GetValuesFromSecret(t *testing.T) {
|
||||||
if apiKey != "apiKey" {
|
if apiKey != "apiKey" {
|
||||||
t.Errorf("Expected apiKey from secret, got %s", apiKey)
|
t.Errorf("Expected apiKey from secret, got %s", apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typelessApi := client.FieldByName("typelessApi").Bool()
|
||||||
|
if typelessApi != false {
|
||||||
|
t.Errorf("Expected typelessApi false value from secret, got %t", typelessApi)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Get Discord values from Secret", func(t *testing.T) {
|
t.Run("Get Discord values from Secret", func(t *testing.T) {
|
||||||
|
@ -651,6 +658,11 @@ func Test_GetValuesFromMountedSecret(t *testing.T) {
|
||||||
if apiKey != "apiKey" {
|
if apiKey != "apiKey" {
|
||||||
t.Errorf("Expected apiKey from secret, got %s", apiKey)
|
t.Errorf("Expected apiKey from secret, got %s", apiKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typelessApi := client.FieldByName("typelessApi").Bool()
|
||||||
|
if typelessApi != false {
|
||||||
|
t.Errorf("Expected typelessApi false value from secret, got %t", typelessApi)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Get Discord values from MountedSecret", func(t *testing.T) {
|
t.Run("Get Discord values from MountedSecret", func(t *testing.T) {
|
||||||
|
|
|
@ -3,6 +3,8 @@ package secrets
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
|
"strconv"
|
||||||
|
|
||||||
corev1 "k8s.io/api/core/v1"
|
corev1 "k8s.io/api/core/v1"
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
@ -25,6 +27,7 @@ type Values struct {
|
||||||
Credentials string `json:"credentials,omitempty"`
|
Credentials string `json:"credentials,omitempty"`
|
||||||
Database string `json:"database,omitempty"`
|
Database string `json:"database,omitempty"`
|
||||||
DSN string `json:"dsn,omitempty"`
|
DSN string `json:"dsn,omitempty"`
|
||||||
|
TypelessApi bool `json:"typelessApi,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Client interface {
|
type Client interface {
|
||||||
|
@ -124,6 +127,13 @@ func (c *k8sClient) Get(ctx context.Context, name string) (Values, error) {
|
||||||
values.Credentials = string(credentials)
|
values.Credentials = string(credentials)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if typelessApi, ok := secret.Data["typelessApi"]; ok {
|
||||||
|
values.TypelessApi, err = strconv.ParseBool(string(typelessApi))
|
||||||
|
if err != nil {
|
||||||
|
values.TypelessApi = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return values, nil
|
return values, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ func newFakeClient() v1.SecretInterface {
|
||||||
"accountID": []byte("accountID"),
|
"accountID": []byte("accountID"),
|
||||||
"database": []byte("database"),
|
"database": []byte("database"),
|
||||||
"dsn": []byte("dsn"),
|
"dsn": []byte("dsn"),
|
||||||
|
"typelessApi": []byte("false"),
|
||||||
},
|
},
|
||||||
}).CoreV1().Secrets("default")
|
}).CoreV1().Secrets("default")
|
||||||
}
|
}
|
||||||
|
@ -94,6 +95,10 @@ func Test_Client(t *testing.T) {
|
||||||
if values.DSN != "dsn" {
|
if values.DSN != "dsn" {
|
||||||
t.Errorf("Unexpected DSN: %s", values.DSN)
|
t.Errorf("Unexpected DSN: %s", values.DSN)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if values.TypelessApi {
|
||||||
|
t.Errorf("Unexpected TypelessApi: %t", values.TypelessApi)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Get values from not existing secret", func(t *testing.T) {
|
t.Run("Get values from not existing secret", func(t *testing.T) {
|
||||||
|
|
|
@ -19,6 +19,8 @@ type Options struct {
|
||||||
Rotation string
|
Rotation string
|
||||||
CustomFields map[string]string
|
CustomFields map[string]string
|
||||||
HTTPClient http.Client
|
HTTPClient http.Client
|
||||||
|
// https://www.elastic.co/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0
|
||||||
|
TypelessApi bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rotation Enum
|
// Rotation Enum
|
||||||
|
@ -42,19 +44,28 @@ type client struct {
|
||||||
rotation Rotation
|
rotation Rotation
|
||||||
customFields map[string]string
|
customFields map[string]string
|
||||||
client http.Client
|
client http.Client
|
||||||
|
// https://www.elastic.co/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0
|
||||||
|
typelessApi bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *client) Send(result v1alpha2.PolicyReportResult) {
|
func (e *client) Send(result v1alpha2.PolicyReportResult) {
|
||||||
var host string
|
var host string
|
||||||
|
var apiSuffix string
|
||||||
|
if e.typelessApi {
|
||||||
|
apiSuffix = "_doc"
|
||||||
|
} else {
|
||||||
|
apiSuffix = "event"
|
||||||
|
}
|
||||||
|
|
||||||
switch e.rotation {
|
switch e.rotation {
|
||||||
case None:
|
case None:
|
||||||
host = e.host + "/" + e.index + "/event"
|
host = e.host + "/" + e.index + "/" + apiSuffix
|
||||||
case Annually:
|
case Annually:
|
||||||
host = e.host + "/" + e.index + "-" + time.Now().Format("2006") + "/event"
|
host = e.host + "/" + e.index + "-" + time.Now().Format("2006") + "/" + apiSuffix
|
||||||
case Monthly:
|
case Monthly:
|
||||||
host = e.host + "/" + e.index + "-" + time.Now().Format("2006.01") + "/event"
|
host = e.host + "/" + e.index + "-" + time.Now().Format("2006.01") + "/" + apiSuffix
|
||||||
default:
|
default:
|
||||||
host = e.host + "/" + e.index + "-" + time.Now().Format("2006.01.02") + "/event"
|
host = e.host + "/" + e.index + "-" + time.Now().Format("2006.01.02") + "/" + apiSuffix
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(e.customFields) > 0 {
|
if len(e.customFields) > 0 {
|
||||||
|
@ -98,5 +109,6 @@ func NewClient(options Options) target.Client {
|
||||||
options.Rotation,
|
options.Rotation,
|
||||||
options.CustomFields,
|
options.CustomFields,
|
||||||
options.HTTPClient,
|
options.HTTPClient,
|
||||||
|
options.TypelessApi,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue