Skip to content

Commit

Permalink
source filter
Browse files Browse the repository at this point in the history
Signed-off-by: Frank Jogeleit <frank.jogeleit@lovoo.com>
  • Loading branch information
Frank Jogeleit committed Apr 28, 2024
1 parent 4ae4ec8 commit fb9c5ba
Show file tree
Hide file tree
Showing 22 changed files with 592 additions and 199 deletions.
45 changes: 31 additions & 14 deletions charts/policy-reporter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,17 +110,15 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| reportFilter.namespaces.include | list | `[]` | |
| reportFilter.namespaces.exclude | list | `[]` | |
| reportFilter.clusterReports.disabled | bool | `false` | |
| database.type | string | `""` | |
| database.database | string | `""` | |
| database.username | string | `""` | |
| database.password | string | `""` | |
| database.host | string | `""` | |
| database.enableSSL | bool | `false` | |
| database.dsn | string | `""` | |
| database.secretRef | string | `""` | |
| database.mountedSecret | string | `""` | |
| sourceFilters | list | `[{"disableClusterReports":false,"kinds":{"exclude":["ReplicaSet"]},"removeControlled":true,"selector":{"source":"kyverno"}}]` | Source based PolicyReport filter |
| sourceFilters[0] | object | `{"disableClusterReports":false,"kinds":{"exclude":["ReplicaSet"]},"removeControlled":true,"selector":{"source":"kyverno"}}` | PolicyReport selector. |
| sourceFilters[0].selector.source | string | `"kyverno"` | select PolicyReport by source |
| sourceFilters[0].removeControlled | bool | `true` | Filter out PolicyReports of controlled Pods and Jobs |
| sourceFilters[0].disableClusterReports | bool | `false` | Filter out ClusterPolicyReports |
| sourceFilters[0].kinds | object | `{"exclude":["ReplicaSet"]}` | Filter out PolicyReports based on the scope resource kind |
| kyverno-plugin.enabled | bool | `false` | |
| trivy-plugin.enabled | bool | `false` | |
| global.labels | object | `{}` | |
| policyPriorities | object | `{}` | |
| basicAuth.username | string | `""` | |
| basicAuth.password | string | `""` | |
| basicAuth.secretRef | string | `""` | |
Expand All @@ -134,6 +132,8 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| emailReports.smtp.password | string | `""` | |
| emailReports.smtp.from | string | `""` | |
| emailReports.smtp.encryption | string | `""` | |
| emailReports.smtp.skipTLS | bool | `false` | |
| emailReports.smtp.certificate | string | `""` | |
| emailReports.summary.enabled | bool | `false` | |
| emailReports.summary.schedule | string | `"0 8 * * *"` | |
| emailReports.summary.activeDeadlineSeconds | int | `300` | |
Expand Down Expand Up @@ -165,6 +165,9 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| target.loki.sources | list | `[]` | |
| target.loki.skipExistingOnStartup | bool | `true` | |
| target.loki.customFields | object | `{}` | |
| target.loki.headers | object | `{}` | |
| target.loki.username | string | `""` | |
| target.loki.password | string | `""` | |
| target.loki.filter | object | `{}` | |
| target.loki.channels | list | `[]` | |
| target.elasticsearch.host | string | `""` | |
Expand All @@ -173,12 +176,14 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| target.elasticsearch.index | string | `"policy-reporter"` | |
| target.elasticsearch.username | string | `""` | |
| target.elasticsearch.password | string | `""` | |
| target.elasticsearch.apiKey | string | `""` | |
| target.elasticsearch.secretRef | string | `""` | |
| target.elasticsearch.mountedSecret | string | `""` | |
| target.elasticsearch.rotation | string | `"daily"` | |
| target.elasticsearch.minimumPriority | string | `""` | |
| target.elasticsearch.sources | list | `[]` | |
| target.elasticsearch.skipExistingOnStartup | bool | `true` | |
| target.elasticsearch.typelessApi | bool | `false` | |
| target.elasticsearch.customFields | object | `{}` | |
| target.elasticsearch.filter | object | `{}` | |
| target.elasticsearch.channels | list | `[]` | |
Expand Down Expand Up @@ -286,9 +291,12 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| target.securityHub.region | string | `""` | |
| target.securityHub.endpoint | string | `""` | |
| target.securityHub.accountID | string | `""` | |
| target.securityHub.productName | string | `""` | |
| target.securityHub.minimumPriority | string | `""` | |
| target.securityHub.sources | list | `[]` | |
| target.securityHub.skipExistingOnStartup | bool | `true` | |
| target.securityHub.cleanup | bool | `false` | |
| target.securityHub.delayInSeconds | int | `2` | |
| target.securityHub.customFields | object | `{}` | |
| target.securityHub.filter | object | `{}` | |
| target.securityHub.channels | list | `[]` | |
Expand All @@ -313,6 +321,15 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| redis.prefix | string | `"policy-reporter"` | |
| redis.username | string | `""` | |
| redis.password | string | `""` | |
| database.type | string | `""` | |
| database.database | string | `""` | |
| database.username | string | `""` | |
| database.password | string | `""` | |
| database.host | string | `""` | |
| database.enableSSL | bool | `false` | |
| database.dsn | string | `""` | |
| database.secretRef | string | `""` | |
| database.mountedSecret | string | `""` | |
| podDisruptionBudget.minAvailable | int | `1` | Configures the minimum available pods for policy-reporter disruptions. Cannot be used if `maxUnavailable` is set. |
| podDisruptionBudget.maxUnavailable | string | `nil` | Configures the maximum unavailable pods for policy-reporter disruptions. Cannot be used if `minAvailable` is set. |
| nodeSelector | object | `{}` | |
Expand All @@ -332,7 +349,7 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| ui.image.registry | string | `"ghcr.io"` | Image registry |
| ui.image.repository | string | `"kyverno/policy-reporter-ui"` | Image repository |
| ui.image.pullPolicy | string | `"IfNotPresent"` | Image PullPolicy |
| ui.image.tag | string | `"2.0.0-alpha.37"` | Image tag Defaults to `Chart.AppVersion` if omitted |
| ui.image.tag | string | `"2.0.0-alpha.47"` | Image tag Defaults to `Chart.AppVersion` if omitted |
| ui.replicaCount | int | `1` | Deployment replica count |
| ui.tempDir | string | `"/tmp"` | Temporary Directory to persist session data for authentication |
| ui.logging.encoding | string | `"console"` | log encoding possible encodings are console and json |
Expand All @@ -356,10 +373,10 @@ Check the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-get
| ui.oauth.secretRef | string | `""` | Provide OpenID Connect configuration via Secret supported keys: `provider`, `clientId`, `clientSecret` |
| ui.displayMode | string | `""` | DisplayMode dark/light uses the OS configured prefered color scheme as default |
| ui.customBoards | list | `[]` | Additional customizable dashboards |
| ui.sources | list | `[{"exceptions":false,"excludes":{"namespaceKinds":["Pod","Job","ReplicaSet"],"results":["warn","error"]},"name":"kyverno"}]` | source specific configurations |
| ui.sources[0] | object | `{"exceptions":false,"excludes":{"namespaceKinds":["Pod","Job","ReplicaSet"],"results":["warn","error"]},"name":"kyverno"}` | kyverno specific UI confiurations |
| ui.sources | list | `[{"exceptions":false,"excludes":{"results":["warn","error"]},"name":"kyverno"}]` | source specific configurations |
| ui.sources[0] | object | `{"exceptions":false,"excludes":{"results":["warn","error"]},"name":"kyverno"}` | kyverno specific UI confiurations |
| ui.sources[0].exceptions | bool | `false` | enabled action button to generate PolicyExceptions from the UI |
| ui.sources[0].excludes | object | `{"namespaceKinds":["Pod","Job","ReplicaSet"],"results":["warn","error"]}` | exclude Pod, Job and Replica resources from kyverno results by default if no kinds are specified |
| ui.sources[0].excludes | object | `{"results":["warn","error"]}` | exclude Pod, Job and Replica resources from kyverno results by default if no kinds are specified |
| ui.clusters | list | `[{"name":"Default","secretRef":"policy-report-ui-default-cluster"}]` | Connected Policy Reporter APIs |
| ui.imagePullSecrets | list | `[]` | Image pull secrets for image verification policies, this will define the `--imagePullSecrets` argument |
| ui.serviceAccount.create | bool | `true` | Create ServiceAccount |
Expand Down
5 changes: 5 additions & 0 deletions charts/policy-reporter/configs/core.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,11 @@ reportFilter:
clusterReports:
disabled: {{ .Values.reportFilter.clusterReports.disabled }}

{{- with .Values.sourceFilters }}
sourceFilters:
{{- toYaml . | nindent 2 }}
{{- end }}

leaderElection:
enabled: {{ or .Values.leaderElection.enabled (gt (int .Values.replicaCount) 1) }}
releaseOnCancel: {{ .Values.leaderElection.releaseOnCancel }}
Expand Down
37 changes: 33 additions & 4 deletions charts/policy-reporter/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,20 @@ reportFilter:
# Disable the processing of ClusterPolicyReports
disabled: false

# -- Source based PolicyReport filter
sourceFilters:
# -- PolicyReport selector.
- selector:
# -- select PolicyReport by source
source: kyverno
# -- Filter out PolicyReports of controlled Pods and Jobs
removeControlled: true
# -- Filter out ClusterPolicyReports
disableClusterReports: false
# -- Filter out PolicyReports based on the scope resource kind
kinds:
exclude: [ReplicaSet]

kyverno-plugin:
enabled: false

Expand Down Expand Up @@ -655,6 +669,25 @@ redis:
username: ""
password: ""

database:
# Database Type, supported: mysql, postgres, mariadb
type: ""
database: "" # Database Name
username: ""
password: ""
host: ""
enableSSL: false
# instead of configure the individual values you can also provide an DSN string
# example postgres: postgres://postgres:password@localhost:5432/postgres?sslmode=disable
# example mysql: root:password@tcp(localhost:3306)/test?tls=false
dsn: ""
# configure an existing secret as source for your values
# supported fields: username, password, host, dsn, database
secretRef: ""
# use an mounted secret as source for your values, required the information in JSON format
# supported fields: username, password, host, dsn, database
mountedSecret: ""

# enabled if replicaCount > 1
podDisruptionBudget:
# -- Configures the minimum available pods for policy-reporter disruptions.
Expand Down Expand Up @@ -804,10 +837,6 @@ ui:
exceptions: false
# -- exclude Pod, Job and Replica resources from kyverno results by default if no kinds are specified
excludes:
namespaceKinds:
- Pod
- Job
- ReplicaSet
results:
- warn
- error
Expand Down
14 changes: 14 additions & 0 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,19 @@ type MetricsFilter struct {
Sources ValueFilter `mapstructure:"sources"`
}

type ReportSelector struct {
Source string `mapstructure:"source"`
}

type SourceFilter struct {
Selector ReportSelector `mapstructure:"selector"`
Kinds ValueFilter `mapstructure:"kinds"`
Sources ValueFilter `mapstructure:"sources"`
Namespaces ValueFilter `mapstructure:"namespaces"`
RemoveControlled bool `mapstructure:"removeControlled"`
DisableClusterReports bool `mapstructure:"disableClusterReports"`
}

// SMTP configuration
type SMTP struct {
Host string `mapstructure:"host"`
Expand Down Expand Up @@ -165,6 +178,7 @@ type Config struct {
Metrics Metrics `mapstructure:"metrics"`
REST REST `mapstructure:"rest"`
ReportFilter ReportFilter `mapstructure:"reportFilter"`
SourceFilters []SourceFilter `mapstructure:"sourceFilters"`
Redis Redis `mapstructure:"redis"`
Profiling Profiling `mapstructure:"profiling"`
EmailReports EmailReports `mapstructure:"emailReports"`
Expand Down
53 changes: 51 additions & 2 deletions pkg/config/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ import (
"github.com/kyverno/policy-reporter/pkg/email"
"github.com/kyverno/policy-reporter/pkg/email/summary"
"github.com/kyverno/policy-reporter/pkg/email/violations"
"github.com/kyverno/policy-reporter/pkg/helper"
"github.com/kyverno/policy-reporter/pkg/kubernetes"
"github.com/kyverno/policy-reporter/pkg/kubernetes/jobs"
"github.com/kyverno/policy-reporter/pkg/kubernetes/namespaces"
"github.com/kyverno/policy-reporter/pkg/kubernetes/pods"
"github.com/kyverno/policy-reporter/pkg/kubernetes/secrets"
"github.com/kyverno/policy-reporter/pkg/leaderelection"
"github.com/kyverno/policy-reporter/pkg/listener"
Expand Down Expand Up @@ -190,10 +193,30 @@ func (r *Resolver) Queue() (*kubernetes.Queue, error) {
return nil, err
}

pods, err := r.PodClient()
if err != nil {
return nil, err
}

jobs, err := r.JobClient()
if err != nil {
return nil, err
}

return kubernetes.NewQueue(
kubernetes.NewDebouncer(1*time.Minute, r.EventPublisher()),
workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "report-queue"),
client,
report.NewSourceFilter(pods, jobs, helper.Map(r.config.SourceFilters, func(f SourceFilter) report.SourceValidation {
return report.SourceValidation{
Selector: report.ReportSelector{Source: f.Selector.Source},
Kinds: ToRuleSet(f.Kinds),
Sources: ToRuleSet(f.Sources),
Namespaces: ToRuleSet(f.Namespaces),
RemoveControlled: f.RemoveControlled,
DisableClusterReports: f.DisableClusterReports,
}
})),
), nil
}

Expand Down Expand Up @@ -302,6 +325,32 @@ func (r *Resolver) NamespaceClient() (namespaces.Client, error) {
), nil
}

// PodClient resolver method
func (r *Resolver) PodClient() (pods.Client, error) {
clientset, err := r.Clientset()
if err != nil {
return nil, err
}

return pods.NewClient(
clientset.CoreV1(),
gocache.New(15*time.Second, 5*time.Second),
), nil
}

// JobClient resolver method
func (r *Resolver) JobClient() (jobs.Client, error) {
clientset, err := r.Clientset()
if err != nil {
return nil, err
}

return jobs.NewClient(
clientset.BatchV1(),
gocache.New(15*time.Second, 5*time.Second),
), nil
}

func (r *Resolver) TargetFactory() *TargetFactory {
ns, err := r.NamespaceClient()
if err != nil {
Expand Down Expand Up @@ -469,8 +518,8 @@ func (r *Resolver) PolicyReportClient() (report.PolicyReportClient, error) {
return r.policyReportClient, nil
}

func (r *Resolver) ReportFilter() *report.Filter {
return report.NewFilter(
func (r *Resolver) ReportFilter() *report.MetaFilter {
return report.NewMetaFilter(
r.config.ReportFilter.ClusterReports.Disabled,
ToRuleSet(r.config.ReportFilter.Namespaces),
)
Expand Down
46 changes: 46 additions & 0 deletions pkg/kubernetes/jobs/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package jobs

import (
"context"

gocache "github.com/patrickmn/go-cache"
batchv1 "k8s.io/api/batch/v1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/client-go/kubernetes/typed/batch/v1"

"github.com/kyverno/policy-reporter/pkg/kubernetes"
)

type Client interface {
Get(scope *corev1.ObjectReference) (*batchv1.Job, error)
}

type k8sClient struct {
client v1.BatchV1Interface
cache *gocache.Cache
}

func (c *k8sClient) Get(scope *corev1.ObjectReference) (*batchv1.Job, error) {
if cached, ok := c.cache.Get(string(scope.UID)); ok {
return cached.(*batchv1.Job), nil
}

pod, err := kubernetes.Retry(func() (*batchv1.Job, error) {
return c.client.Jobs(scope.Namespace).Get(context.Background(), scope.Name, metav1.GetOptions{})
})
if err != nil {
return nil, err
}

c.cache.Set(string(scope.UID), pod, 0)

return pod, nil
}

func NewClient(client v1.BatchV1Interface, cache *gocache.Cache) Client {
return &k8sClient{
client: client,
cache: cache,
}
}
45 changes: 45 additions & 0 deletions pkg/kubernetes/pods/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package pods

import (
"context"

gocache "github.com/patrickmn/go-cache"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/client-go/kubernetes/typed/core/v1"

"github.com/kyverno/policy-reporter/pkg/kubernetes"
)

type Client interface {
Get(scope *corev1.ObjectReference) (*corev1.Pod, error)
}

type k8sClient struct {
client v1.CoreV1Interface
cache *gocache.Cache
}

func (c *k8sClient) Get(scope *corev1.ObjectReference) (*corev1.Pod, error) {
if cached, ok := c.cache.Get(string(scope.UID)); ok {
return cached.(*corev1.Pod), nil
}

pod, err := kubernetes.Retry(func() (*corev1.Pod, error) {
return c.client.Pods(scope.Namespace).Get(context.Background(), scope.Name, metav1.GetOptions{})
})
if err != nil {
return nil, err
}

c.cache.Set(string(scope.UID), pod, 0)

return pod, nil
}

func NewClient(client v1.CoreV1Interface, cache *gocache.Cache) Client {
return &k8sClient{
client: client,
cache: cache,
}
}
Loading

0 comments on commit fb9c5ba

Please sign in to comment.