Integrations
Policy Reporter supports different targets to send new PolicyReport results. This makes it possible to create a log or get notified as soon as a new violation is detected. The set of supported tools are based on user requests. Feel free to create an issue or pull request if you need a unsupported integration.
Supported Integrations
- Grafana Loki
- Elasticsearch
- Slack
- Discord
- Microsoft Teams
- S3 Buckets
- AWS Kinesis
- AWS SecurityHub
- Telegram
- GoogleChat
- GoogleCloudStorage
- Webhooks
Integration Features
Filter
To reduce noise and only be notified when you are interested, it is possible to configure different filters per target.
A new default behavior in Policy Reporter v3 is that only violating results (warning, failure or error) of notification targets are processed.
SkipExistingOnStartup
This configuration is available for all targets and ignores already existing results on startup. This avoids duplications and spamming when Policy Reporter restarts. For all targets in the Helm chart, it is set to true
by default, except for SecurityHub, which synchronizes the complete cluster status with AWS SecurityHub.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
skipExistingOnStartup: true
MinimumSeverity
The minimumSeverity
replaces the old minimumPriority
and defines the lowest severity that is processed by the related target.
Possible values and weightings are: info
> low
> medium
> high
> critical
.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
minimumSeverity: 'medium'
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
minimumSeverity: 'medium'
skipExistingOnStartup: true
Sources
A list of PolicyReportResults sources to be processed by the target in question. Wildcards are supported.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
minimumSeverity: 'medium'
skipExistingOnStartup: true
sources: ['kyverno', 'Trivy*']
target:
loki:
config:
host: 'http://loki.monitoring:3000'
minimumSeverity: 'medium'
skipExistingOnStartup: true
sources: ['kyverno', 'Trivy*']
Filter
Can be used to filter on several values of a result or report labels. You can filter on policies
, namespaces
, status
, severities
, sources
and reportLabels
. Each filter requires a include
or exclude
rule, wildacards are supported.
The namespaces
filter also supports a selector
map to filter namespaces based on labels.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
severities:
exclude: ['low', 'info']
status:
exclude: ['error']
reportLabels:
include: ['app', 'owner:team-a', 'monitoring:*']
target:
loki:
config:
host: 'http://loki.monitoring:3000'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
severities:
exclude: ['low', 'info']
status:
exclude: ['error']
reportLabels:
include: ['app', 'owner:team-a', 'monitoring:*']
Channels
With the channels
option, you can define several configurations of the same type for one target. In combination with filters, this allows you to forward your notifications to different target configurations. Channels have the same configuration properties as the main configuration of the target.
Depending on the target different values from the main target will be used as default value in the channel configuration.
Example
The Slack channel configuration of Team B uses the configured webhook URL of the main configuration. It only overwrites the Slack channel
configuration to push the notification in a different Slack Channel as Team A.
target:
slack:
name: Team A
webhook: 'http://slack.webhook.com/12345'
channel: team-a
minimumSeverity: 'medium'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
channels:
- name: Team B
channel: team-b
filter:
namespaces:
selector: { team: team-b }
target:
slack:
name: Team A
config:
webhook: 'http://loki.monitoring:3000'
channel: team-a
minimumSeverity: 'medium'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
channels:
- name: Team B
config:
channel: team-b
filter:
namespaces:
selector: { team: team-b }
SecretRef
Instead of defining your credentials or webhooks directly, you can also use the secretRef
configuration to reference an already existing Secret by name. If the secret does not exist, the target is skipped.
The Secret should contain the related configuration as key. Supported keys are host
, webhook
, channel
, apiKey
, accountId
, typelessApi
, kmsKeyId
, username
, password
, token
, credentials
, accessKeyId
and secretAccessKey
- depending on the related target. Only exception is token, which is dedicated for webhook targets and is added as Authorization header.
The secretRef is also supported for channels, so you can use different secrets for different channels.
Secret Example
apiVersion: v1
kind: Secret
metadata:
name: team-a-slack-webhook
type: Opaque
data:
webhook: aHR0cHM6Ly9ob29rcy5zbGFjay5jb20vc2VydmljZXMvVDAuLi4= # https://hooks.slack.com/services/T0...
channel: dGVhbS1h # team-a
Configuration Example
target:
slack:
name: Team A
secretRef: 'team-a-slack-webhook'
minimumSeverity: 'medium'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
target:
slack:
name: Team A
secretRef: 'team-a-slack-webhook'
minimumSeverity: 'medium'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
MountedSecret
The option mountedSecret
has a similar functionality as secretRef
, the difference is that the value corresponds to a path to a mounted secret within the pod. The mounted file is expected as a JSON file with the same key support as secretRef
. MountedSecret can be used to retrieve values from a central keystore.
Secret Example
apiVersion: v1
kind: Secret
metadata:
name: team-a-slack-webhook
type: Opaque
data:
team-a.json: ewogICJjaGFubmVsIjogInRlYW0tYSIsCiAgIndlYmhvb2siOiAiaHR0cHM6Ly9ob29rcy5zbGFjay5jb20vc2VydmljZXMvVDAuLi4iCn0= # { "channel": "team-a", "webhook": "https://hooks.slack.com/services/T0..." }
Configuration Example
target:
slack:
name: Team A
mountedSecret: '/config/team-a.json'
minimumSeverity: 'medium'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
target:
slack:
name: Team A
mountedSecret: '/config/team-a.json'
minimumSeverity: 'medium'
skipExistingOnStartup: true
filter:
namespaces:
selector: { team: team-a }
CustomFields
CustomFields can be used to add static information to each notification. This could be e.g. the cluster name a result came from.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
customFields:
cluster: Dev 1
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
customFields:
cluster: Dev 1
skipExistingOnStartup: true
HTTP Client Configuration
Most target implementations are HTTP.Client
based and can configurated with e.g. TLS options and custom headers.
SkipTLS
Disables client verification of the server's certificate chain and host name.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
skipTLS: true
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
skipTLS: true
skipExistingOnStartup: true
Certificate
Configure a file path to the root CA certificate in PEM format which should be used to verify the server certificate.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
certificate: '/config/root_ca.pem'
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
certificate: '/config/root_ca.pem'
skipExistingOnStartup: true
Headers
Add additional static headers to each request.
Example
target:
loki:
host: 'http://loki.monitoring:3000'
headers:
X-Token: '12345'
certificate: '/config/root_ca.pem'
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
headers:
X-Token: '12345'
skipExistingOnStartup: true
Integration Setup
Grafana Loki
Policy Reporter can send results directly to Grafana Loki without the need of Promtail. Each result includes all available information as labels as well as a createdBy label with policy-reporter as value. To query all messages from Policy Reporter, use {createdBy="policy-reporter"}
as the query.
Options
Option | Description | Default |
---|---|---|
host | Accessible Host | (required) |
path | API Path | "/api/prom/push" |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Grafana Loki requires a valid and accessible host.
target:
loki:
host: 'http://loki.monitoring:3000'
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://loki.monitoring:3000'
skipExistingOnStartup: true
Elasticsearch
Policy Reporter sends results in a JSON representation and all available information to a customizable index. This index can be expanded by selecting one of the different rotations or none to disable this function. By default Policy Reporter creates a new index on a daily basis.
Options
Option | Description | Default |
---|---|---|
host | Accessible Host | (required) |
username | HTTPBasic Username | |
password | HTTPBasic Password | |
index | Search Index | policy-reporter |
rotation | Adding the rotation date as suffix to the index name. Possible values are daily ,monthly , annually and none . | daily |
typelessApi | Switching to Typeless API | false |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Elasticsearch requires a valid and accessible host.
target:
loki:
host: 'http://elasticsearch.elk-stack:8080'
index: 'policy-reporter'
rotation: 'daily'
skipExistingOnStartup: true
target:
loki:
config:
host: 'http://elasticsearch.elk-stack:8080'
index: 'policy-reporter'
rotation: 'daily'
skipExistingOnStartup: true
Microsoft Teams
Sends notifications about new violations with all available information over the webhook API to Microsoft Teams.
Options
Option | Description | Default |
---|---|---|
webhook | Webhook Endpoint | (required) |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for MS Teams requires a valid and accessible webhook api.
target:
teams:
webhook: 'https://m365x682156.webhook.office.com'
skipExistingOnStartup: true
target:
teams:
config:
webhook: 'https://m365x682156.webhook.office.com'
skipExistingOnStartup: true
Slack
Sends notifications about new violations with all available information over the webhook API to Slack.
Options
Option | Description | Default |
---|---|---|
webhook | Webhook Endpoint | (required) |
channel | Slack Channel | (optional) |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Slack requires a valid and accessible webhook api.
target:
slack:
webhook: 'https://hooks.slack.com/services/...'
skipExistingOnStartup: true
target:
slack:
config:
webhook: 'https://hooks.slack.com/services/...'
skipExistingOnStartup: true
Discord
Sends notifications about new violations with all available information over the webhook API to Discord.
Options
Option | Description | Default |
---|---|---|
webhook | Webhook Endpoint | (required) |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Discord requires a valid and accessible webhook api.
target:
discord:
webhook: 'https://discordapp.com/api/webhooks/...'
skipExistingOnStartup: true
target:
discord:
config:
webhook: 'https://discordapp.com/api/webhooks/...'
skipExistingOnStartup: true
Webhook
Sends new violations with all available information in JSON format to the configured webhook API.
Options
Option | Description | Default |
---|---|---|
webhook | Webhook Endpoint | (required) |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Discord requires a valid and accessible webhook api.
target:
webhook:
webhook: 'https://discordapp.com/api/webhooks/...'
skipExistingOnStartup: true
target:
webhook:
config:
webhook: 'https://discordapp.com/api/webhooks/...'
skipExistingOnStartup: true
Payload
{
"message": "validation error: Running as root is not allowed. The fields spec.securityContext.runAsNonRoot, spec.containers[*].securityContext.runAsNonRoot, and spec.initContainers[*].securityContext.runAsNonRoot must be `true`. Rule check-containers[0] failed at path /spec/securityContext/runAsNonRoot/. Rule check-containers[1] failed at path /spec/containers/0/securityContext/.",
"policy": "require-run-as-non-root",
"rule": "check-containers",
"status": "fail",
"severity": "medium",
"category": "Pod Security Standards (Restricted)",
"scored": true,
"creationTimestamp": "2021-12-04T10:13:02Z",
"resource": {
"apiVersion": "v1",
"kind": "Pod",
"name": "nginx2",
"namespace": "test",
"uid": "ac4d11f3-0aa8-43f0-8056-98f4eae0d956"
}
}
S3 Storage
Policy Reporter can also send results to S3 compatible services like MinIO, Yandex or AWS S3. It persists each result as JSON in the following structure: s3://<bucket>/<prefix>/YYYY-MM-DD/<policy-name>-<result-id>-YYYY-MM-DDTHH:mm:ss.json
Authentication
The S3 integration supports WebIdentidy
, PodIdentity
and Credentials
as authentication mechanisms.
Options
Option | Description | Default |
---|---|---|
bucket | S3 Bucket | (required) |
endpoint | S3 API Endpoint | (optional) |
accessKeyId | For Credentials authentication | (optional) |
secretAccessKey | For Credentials authentication | (optional) |
kmsKeyID | Used for Bucket Encryption | (optional) |
bucketKeyEnabled | Should use Bucket Key for Encryption | false |
serverSideEncryption | Enables server side encryption | false |
region | Region | AWS_REGION ENV |
prefix | Path Prefix | policy-reporter |
pathStyle | Allow client to use path-style addressing | false |
Example
target:
s3:
endpoint: 'https://storage.yandexcloud.net'
region: 'ru-central1'
bucket: 'dev-cluster'
secretAccessKey: 'secretAccessKey'
accessKeyId: 'accessKeyId'
skipExistingOnStartup: true
target:
s3:
config:
endpoint: 'https://storage.yandexcloud.net'
region: 'ru-central1'
bucket: 'dev-cluster'
secretAccessKey: 'secretAccessKey'
accessKeyId: 'accessKeyId'
skipExistingOnStartup: true
Kinesis
Supports Kinesis compatible Services.
Authentication
The AWS integration supports WebIdentidy
, PodIdentity
and Credentials
as authentication mechanisms.
Options
Option | Description | Default |
---|---|---|
streamName | Kinesis Streamname | (required) |
endpoint | Kinesis API Endpoint | (optional) |
accessKeyId | For Credentials authentication | (optional) |
secretAccessKey | For Credentials authentication | (optional) |
region | Region | AWS_REGION ENV |
Example
target:
s3:
endpoint: 'https://kinesis.eu-central-1.amazonaws.com'
region: 'eu-central-1'
streamName: 'dev-cluster'
secretAccessKey: 'secretAccessKey'
accessKeyId: 'accessKeyId'
skipExistingOnStartup: true
target:
s3:
config:
endpoint: 'https://kinesis.eu-central-1.amazonaws.com'
region: 'eu-central-1'
streamName: 'dev-cluster'
secretAccessKey: 'secretAccessKey'
accessKeyId: 'accessKeyId'
skipExistingOnStartup: true
SecurityHub
Supports AWS SecurityHub. Unlike the other integrations its possible to sync the complete cluster status to SecurityHub and automatically update existing findings when the status changed or the related policy or resource was deleted.
Authentication
AWS SecurityHub supports WebIdentidy
, PodIdentity
and Credentials
as authentication mechanisms.
Options
Option | Description | Default |
---|---|---|
accountId | AWS Accound ID | (required) |
endpoint | API Endpoint | (optional) |
accessKeyId | For Credentials authentication | (optional) |
secretAccessKey | For Credentials authentication | (optional) |
productName | Used product name in SH Findings | Policy Reporter |
companyName | Used company name in SH Findings | Kyverno |
delayInSeconds | Delay between report cleanups, may be relevant when reaching AWS RateLimits | 2 |
synchronize | Enables synchronization of resolved findings in SH | true |
region | AWS Region | AWS_REGION ENV |
Example
target:
securityHub:
region: 'eu-central-1'
accountId: 'accountId'
secretAccessKey: 'secretAccessKey'
accessKeyId: 'accessKeyId'
target:
securityHub:
config:
region: 'eu-central-1'
accountId: 'accountId'
secretAccessKey: 'secretAccessKey'
accessKeyId: 'accessKeyId'
Google Cloud Storage
Policy Reporter can also send results to GoogleCloudStorage. It persists each result as JSON in the following structure: <bucket>/<prefix>/YYYY-MM-DD/<policy-name>-<result-id>-YYYY-MM-DDTHH:mm:ss.json
Authentication
GoogleCloudStorage supports PodIdentity
and Credentials
as authentication mechanisms.
Options
Option | Description | Default |
---|---|---|
bucket | Bucket name | (required) |
credentials | Credentials in JSON format | (optional) |
prefix | Path Prefix | policy-reporter |
Example
target:
gcs:
bucket: 'dev-cluster'
target:
gcs:
config:
bucket: 'dev-cluster'
Telegram
Sends notifications about new violations with all available information over the webhook API to Telegram.
Options
Option | Description | Default |
---|---|---|
webhook | Webhook Endpoint | (optional) |
token | Telegram Token | (required) |
chatId | Telegram ChatID | (required) |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Discord requires a valid and accessible webhook api.
target:
telegram:
chatId: "XXX"
token: "XXXX"
skipExistingOnStartup: true
target:
telegram:
config:
chatId: "XXX"
token: "XXXX"
skipExistingOnStartup: true
Google Chat
Sends notifications about new violations with all available information over the webhook API to Google Chat.
Options
Option | Description | Default |
---|---|---|
webhook | Webhook Endpoint | (required) |
skipTLS | skip server cert verification | false |
certificate | path to a root CA in PEM format | (optional) |
headers | map of additional static headers | (optional) |
Example
The minimal configuration for Discord requires a valid and accessible webhook api.
target:
googleChat:
webhook: 'https://chat.googleapis.com/v1/spaces/XXX/messages?key=XXX&token=XXX'
skipExistingOnStartup: true
target:
googleChat:
config:
webhook: 'https://chat.googleapis.com/v1/spaces/XXX/messages?key=XXX&token=XXX'
skipExistingOnStartup: true