Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create target config proposal #68

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
158 changes: 158 additions & 0 deletions proposals/target_config.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
# Meta
[meta]: #meta
- Name: (Target Configuration CRD for policy reporter)
- Start Date: (2025-01-14)
- Author(s): (aerosouund)

# Table of Contents
[table-of-contents]: #table-of-contents
- [Meta](#meta)
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Proposal](#proposal)
- [Implementation](#implementation)
- [Unresolved Questions](#unresolved-questions)

# Overview

The [policy reporter](https://github.com/kyverno/policy-reporter) takes in configuration for targets that it will send policy reports to through a flag `--config` which points to a file that can have a structure which is documented [here](https://kyverno.github.io/policy-reporter/core/targets). This document aims to define a CRD that will be used to provide the same functionality as this config file. giving administrators the ability to manage targets with this CRD.

A single CRD equals exactly one target. For example if you want to send to multiple slack channels, you need a CRD per channel


# Proposal

The CRD is proposed to have the following structure. The resource is non namespaced, and by default applies to all existing namespaces.

```yaml
apiVersion: policyreporter.io/v1alpha1
kind: TargetConfig
metadata:
name: test
status:
sendStatus:
- eventID: 179db659-a29f-42c5-a9c2-4106d01ea339
succeeded: true
messagee: Send OK
- eventID: 179db759-a22t-4hf5-al12-4106d01hdbn8
succeded: false
message: Got response 403
conditions:
- type: InSync
status: "True"
reason: SendReportSuccess
message: "Sent with report with status 200"
lastTransitionTime: "2025-01-07T14:00:00Z"
spec:
targetType: string
config:
filter:
namespaces:
include: ["team-a-*"]
priorities:
exclude: ["info", "debug"]
policies:
include: ["require-*"]
# immutable field
secretRef: string
minimumSeverity: string
skipExistingOnStartup: bool
```

The `sendStatus` field shows the last 3 or 4 sends as a summmary for the admin.

The conditions can be one of `InSync`, `OutOfSync`, `Unavailable`. Each of them means:
1- `InSync`: The target is active and all the reports that should be sent to it are sent
2- `OutOfSync`: The last send was successful but there are new reports to be sent to the target
3- `Unavailable`: The last send errored
4- `Invalid`: The config couldn't be parsed into the config schema expected by a target of the same type


# Examples

S3:

```yaml
apiVersion: policyreporter.io/v1alpha1
kind: TargetConfig
metadata:
name: s3-target
spec:
targetType: s3
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you should consider to use different keys per target. config would be to generic, makes it hard to describe which field is required for which target or even available for a given target type. Makes also the use of the explain command for a given target type easier.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was thinking of this as well, the benefit of doing this was simplicity in my opinion.
if we want to be more descriptive we can use s3Config, slackConfig.. etc. and the spec can contain any single one of those keys

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean different CRDs per Target? Might be to much. As in my example you can use spec.s3, spec.slack etc. to group target specfic configuration. You can still keep global configurations like filter or secretRef directly under spec.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, same CRD. but its spec is defined as

spec:
  # general keys
  s3: ...  # you can only have one of these
  slack: ...

and we can include the general keys separate from each individual config, i suggested this in case at any point in the future we created a struct that an array of those individual configs. in such a case each array item will be its own full config. what do you think ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks better to me.

in such a case each array item will be its own full config. what do you think ?

could be a future feature but nothing I would prioritize because it makes many things just more complicated without much benefit. We should keep it simple for now.

config:
endpoint: 'https://s3.amazonaws.com'
region: 'eu-west-1'
bucket: 'policy-reporter'
accessKeyId: 'redacted'
secretAccessKey: 'redacted'
minimumSeverity: warning
skipExistingOnStartup: true
```

Slack (Inline):

```yaml
apiVersion: policyreporter.io/v1alpha1
kind: TargetConfig
metadata:
name: slack-target
spec:
targetType: slack-inline
config:
minimumSeverity: warning
skipExistingOnStartup: true
webhook: "https://hooks.slack.com/services/456..."
filter:
namespaces:
include: ["team-b-*"]
Comment on lines +95 to +107
Copy link
Member

@fjogeleit fjogeleit Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

example

Suggested change
apiVersion: policyreporter.io/v1alpha1
kind: TargetConfig
metadata:
name: slack-target
spec:
targetType: slack-inline
config:
minimumSeverity: warning
skipExistingOnStartup: true
webhook: "https://hooks.slack.com/services/456..."
filter:
namespaces:
include: ["team-b-*"]
apiVersion: policyreporter.io/v1alpha1
kind: Target
metadata:
name: slack-target
spec:
slack:
webhook: "https://hooks.slack.com/services/456..."
filter:
namespaces:
include: ["team-b-*"]
minimumSeverity: warning
skipExistingOnStartup: true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, i will commit those suggestions if we are settled on the structure in the above conversation. in general i do agree with you that it makes the crd more readable

```

Slack (Channel):

```yaml
apiVersion: policyreporter.io/v1alpha1
kind: TargetConfig
metadata:
name: slack-target
spec:
targetType: slack-channel
config:
skipExistingOnStartup: false
secretRef: "team-a-slack-webhook"
filter:
namespaces:
include: ["team-a-*"]
```


# Implementation

The new CRD will have an informer. On receiving an event, a new `Target` will be created and added to the collection struct saved by the resolver.


```golang
type Resolver struct {
...
targetClients *target.Collection // this is what gets appended to
...
}
```

The new informer will be introduced in the client `Sync` method

```golang
func (k *k8sPolicyReportClient) Sync(stopper chan struct{}) error {
factory := metadatainformer.NewSharedInformerFactory(k.metaClient, 15*time.Minute)

var cpolrInformer cache.SharedIndexInformer

polrInformer := k.configureInformer(factory.ForResource(polrResource).Informer())

// targetconfig informer will be added here, the informer needs to have access to the Resolver type
// which may mean that a pointer to the target collection might be introduced as a dependency to the client
// which is the collection used that will be used by the informer and the resolver.
```

# Unresolved Questions

- Similar groupings for things like aws credentials can be put under a single key, for example `awsConfig`