diff --git a/apps.yaml b/apps.yaml index fd9dd417cc..da07801e8f 100644 --- a/apps.yaml +++ b/apps.yaml @@ -330,3 +330,11 @@ appsInfo: dependencies: None about: Velero is a tool to back up and restore Kubernetes cluster resources and persistent volumes. integration: When enabled, Velero can be used to automatically create backups of APL platform services. Based on the selected provider, APL installs required plug-ins. APL also installs the Restic integration for Velero to back up and restore almost any type of Kubernetes volume. + policy-reporter: + title: policy-reporter + appVersion: 3.3.1 + repo: https://github.com/kyverno/policy-reporter + maintainers: Frank Jogeleit + license: Apache 2.0 + dependencies: Kyverno + about: 'Policy Reporter watches for PolicyReport Resources. It creates Prometheus Metrics and can send rule validation events to different targets like Loki, Elasticsearch, Slack or Discord ' diff --git a/chart/chart-index/Chart.yaml b/chart/chart-index/Chart.yaml index a241b59825..d8dbb32aa4 100644 --- a/chart/chart-index/Chart.yaml +++ b/chart/chart-index/Chart.yaml @@ -114,3 +114,6 @@ dependencies: - name: velero version: 5.4.1 repository: https://vmware-tanzu.github.io/helm-charts/ + - name: policy-reporter + version: 3.3.1 + repository: https://kyverno.github.io/policy-reporter diff --git a/charts/grafana-dashboards/policy-reporter/cluster-policy-report-details.json b/charts/grafana-dashboards/policy-reporter/cluster-policy-report-details.json new file mode 100644 index 0000000000..13b55e6f10 --- /dev/null +++ b/charts/grafana-dashboards/policy-reporter/cluster-policy-report-details.json @@ -0,0 +1,928 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 18, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"pass\" })", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Policy Pass Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"warn\" })", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Policy Warning Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"fail\" })", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Policy Fail Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 6, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"error\" })", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Policy Error Status", + "type": "stat" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 13, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\" } > 0) by (status)", + "interval": "", + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "title": "Status Timeline", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 14 + }, + "id": 8, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", kind=~\"$kind\", source=~\"$source\", status=\"pass\" }) by (policy,rule,kind,name,status,severity,category,source)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Passed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 8, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "source": 1, + "status": 7 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 22 + }, + "id": 9, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"fail\" }) by (policy,rule,kind,name,status,severity,category,source)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Failed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 8, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "source": 1, + "status": 7 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 30 + }, + "id": 10, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"warn\" }) by (policy,rule,kind,name,status,severity,category,source )", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Warning Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 8, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "source": 1, + "status": 7 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + } + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 11, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"warn\" }) by (policy,rule,kind,name,status,severity,category,source)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Errored Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 8, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "source": 1, + "status": 7 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "Policy Reporter" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "prometheus" + }, + "includeAll": false, + "label": "Datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(cluster_policy_report_result, policy)", + "includeAll": true, + "label": "Policy", + "multi": true, + "name": "policy", + "options": [], + "query": "label_values(cluster_policy_report_result, policy)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(cluster_policy_report_result, category)", + "includeAll": true, + "label": "Category", + "multi": true, + "name": "category", + "options": [], + "query": "label_values(cluster_policy_report_result, category)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(cluster_policy_report_result, severity)", + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "label_values(cluster_policy_report_result, severity)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(cluster_policy_report_result, kind)", + "includeAll": true, + "label": "Kind", + "multi": true, + "name": "kind", + "options": [], + "query": "label_values(cluster_policy_report_result, kind)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": [ + "All" + ], + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(cluster_policy_report_result, source)", + "includeAll": true, + "label": "Source", + "multi": true, + "name": "source", + "options": [], + "query": "label_values(cluster_policy_report_result, source)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "ClusterPolicyReport Details", + "uid": "iyJszGUMk", + "version": 1 +} diff --git a/charts/grafana-dashboards/policy-reporter/policy-report-details.json b/charts/grafana-dashboards/policy-reporter/policy-report-details.json new file mode 100644 index 0000000000..b8b83b6fae --- /dev/null +++ b/charts/grafana-dashboards/policy-reporter/policy-report-details.json @@ -0,0 +1,992 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 19, + "links": [], + "panels": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 3, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"pass\" } > 0) by (namespace)", + "instant": true, + "interval": "", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "Policy Pass Status", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 5, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"fail\" } > 0) by (namespace)", + "instant": true, + "interval": "", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "Policy Fail Status", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 12, + "x": 0, + "y": 8 + }, + "id": 4, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"warn\" } > 0) by (namespace)", + "instant": true, + "interval": "", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "Policy Warning Status", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 2, + "w": 12, + "x": 12, + "y": 8 + }, + "id": 6, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"error\" } > 0) by (namespace)", + "instant": true, + "interval": "", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "Policy Error Status", + "type": "bargauge" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "none" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\" } > 0) by (status, namespace)", + "interval": "", + "legendFormat": "{{namespace}} {{ status }}", + "refId": "A" + } + ], + "title": "Status Timeline", + "type": "timeseries" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 8, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"pass\" }) by (namespace,category,policy,rule,kind,name,severity,status,source )", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Passed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 9, + "category": 2, + "kind": 4, + "name": 5, + "namespace": 3, + "policy": 6, + "rule": 7, + "severity": 2, + "source": 1, + "status": 8 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 24, + "x": 0, + "y": 26 + }, + "id": 9, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"fail\" }) by (namespace,category,policy,rule,kind,name,severity,status,source)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Failed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 9, + "category": 2, + "kind": 4, + "name": 5, + "namespace": 3, + "policy": 6, + "rule": 7, + "severity": 2, + "source": 1, + "status": 8 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 34 + }, + "id": 10, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"warn\" }) by (namespace,category,policy,rule,kind,name,severity,status,source )", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Warning Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 9, + "category": 2, + "kind": 4, + "name": 5, + "namespace": 3, + "policy": 6, + "rule": 7, + "severity": 2, + "source": 1, + "status": 8 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 4, + "w": 24, + "x": 0, + "y": 38 + }, + "id": 11, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=\"error\" }) by (namespace,category,policy,rule,kind,name,severity,status,source )", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "title": "Errored Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "status": false + }, + "indexByName": { + "Time": 0, + "Value": 9, + "category": 1, + "kind": 4, + "name": 5, + "namespace": 3, + "policy": 6, + "rule": 7, + "severity": 2, + "status": 8 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "Policy Reporter" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "prometheus" + }, + "includeAll": false, + "label": "Datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(policy_report_result, policy)", + "includeAll": true, + "label": "Policy", + "multi": true, + "name": "policy", + "options": [], + "query": "label_values(policy_report_result, policy)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(policy_report_result, category)", + "includeAll": true, + "label": "Category", + "multi": true, + "name": "category", + "options": [], + "query": "label_values(policy_report_result, category)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(policy_report_result, severity)", + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "label_values(policy_report_result, severity)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(policy_report_result, namespace)", + "includeAll": true, + "label": "Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": "label_values(policy_report_result, namespace)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(policy_report_result, kind)", + "includeAll": true, + "label": "Kind", + "multi": true, + "name": "kind", + "options": [], + "query": "label_values(policy_report_result, kind)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": [ + "$__all" + ] + }, + "datasource": { + "type": "prometheus", + "uid": "prometheus" + }, + "definition": "label_values(policy_report_result, source)", + "includeAll": true, + "label": "Source", + "multi": true, + "name": "source", + "options": [], + "query": "label_values(policy_report_result, source)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + } + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "PolicyReport Details", + "uid": "Tf1skG8Mz", + "version": 1 +} \ No newline at end of file diff --git a/charts/grafana-dashboards/policy-reporter/policy-reports.json b/charts/grafana-dashboards/policy-reporter/policy-reports.json new file mode 100644 index 0000000000..6736cd1e29 --- /dev/null +++ b/charts/grafana-dashboards/policy-reporter/policy-reports.json @@ -0,0 +1,657 @@ +{ + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": { + "type": "datasource", + "uid": "grafana" + }, + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "fiscalYearStartMonth": 0, + "graphTooltip": 0, + "id": 20, + "links": [], + "panels": [ + { + "datasource": { + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 15, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "displayMode": "gradient", + "legend": { + "calcs": [], + "displayMode": "list", + "placement": "bottom", + "showLegend": false + }, + "maxVizHeight": 300, + "minVizHeight": 10, + "minVizWidth": 0, + "namePlacement": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true, + "sizing": "auto", + "valueMode": "color" + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=~\"fail|error\" } > 0) by (namespace)", + "instant": true, + "interval": "", + "legendFormat": "{{namespace}}", + "refId": "A" + } + ], + "title": "Failing Policies by Namespace", + "type": "bargauge" + }, + { + "datasource": { + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "#EAB839", + "value": 3 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 8, + "w": 9, + "x": 15, + "y": 0 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "vertical", + "percentChangeColorMode": "standard", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showPercentChange": false, + "textMode": "auto", + "wideLayout": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\" } > 0) by (status)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{ status }}", + "refId": "A" + } + ], + "title": "Failing ClusterPolicies", + "type": "stat" + }, + { + "datasource": { + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "color": { + "mode": "palette-classic" + }, + "custom": { + "axisBorderShow": false, + "axisCenteredZero": false, + "axisColorMode": "text", + "axisLabel": "", + "axisPlacement": "auto", + "barAlignment": 0, + "barWidthFactor": 0.6, + "drawStyle": "line", + "fillOpacity": 10, + "gradientMode": "none", + "hideFrom": { + "legend": false, + "tooltip": false, + "viz": false + }, + "insertNulls": false, + "lineInterpolation": "linear", + "lineWidth": 1, + "pointSize": 5, + "scaleDistribution": { + "type": "linear" + }, + "showPoints": "never", + "spanNulls": false, + "stacking": { + "group": "A", + "mode": "none" + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "decimals": 0, + "mappings": [], + "min": 0, + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + }, + "unit": "short" + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsZero", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "op": "gte", + "reducer": "allIsNull", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "legend": true, + "tooltip": true, + "viz": false + } + } + ] + } + ] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 11, + "options": { + "alertThreshold": true, + "legend": { + "calcs": [ + "lastNotNull" + ], + "displayMode": "table", + "placement": "right", + "showLegend": true + }, + "tooltip": { + "hideZeros": false, + "mode": "multi", + "sort": "none" + } + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\" } > 0) by (policy)", + "interval": "", + "legendFormat": "{{ policy }}", + "refId": "A" + }, + { + "datasource": { + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=~\"fail|error\" } > 0) by (policy)", + "interval": "", + "legendFormat": "{{ policy }}", + "refId": "B" + } + ], + "title": "Failing Policies Graph", + "type": "timeseries" + }, + { + "datasource": { + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "align": "auto", + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 7, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "12.0.2", + "targets": [ + { + "datasource": { + "uid": "prometheus" + }, + "expr": "sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", namespace=~\"$namespace\", status=~\"fail|error\" }) by (namespace,policy,rule,kind,name,status,category,severity,source)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "{{namespace}}: {{ policy }}", + "refId": "A" + } + ], + "title": "Failing PolicyRules", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true + }, + "indexByName": { + "category": 1, + "kind": 4, + "name": 5, + "namespace": 3, + "policy": 6, + "rule": 7, + "severity": 2, + "source": 0, + "status": 8 + }, + "renameByName": { + "namespace": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": { + "uid": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "cellOptions": { + "type": "auto" + }, + "inspect": false + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green" + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": 10, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 9, + "options": { + "cellHeight": "sm", + "footer": { + "countRows": false, + "fields": "", + "reducer": [ + "sum" + ], + "show": false + }, + "showHeader": true + }, + "pluginVersion": "10.1.5", + "targets": [ + { + "datasource": { + "uid": "prometheus" + }, + "expr": "sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\" }) by (policy,rule,kind,name,status,category,severity,source)", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "{{ kind }}: {{ name }} - {{ policy }}", + "refId": "A" + } + ], + "title": "Failing ClusterPolicyRules", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "Value": true, + "__name__": true, + "container": true, + "endpoint": true, + "instance": true, + "job": true, + "namespace": true, + "pod": true, + "report": true, + "service": true + }, + "indexByName": { + "category": 1, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "source": 0, + "status": 7 + }, + "renameByName": {} + } + } + ], + "type": "table" + } + ], + "preload": false, + "refresh": "", + "schemaVersion": 41, + "tags": [ + "Policy Reporter" + ], + "templating": { + "list": [ + { + "current": { + "text": "Prometheus", + "value": "prometheus" + }, + "includeAll": false, + "label": "Datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "prometheus" + }, + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, policy)", + "includeAll": true, + "label": "Policy", + "multi": true, + "name": "policy", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, policy)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "prometheus" + }, + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, category)", + "includeAll": true, + "label": "Category", + "multi": true, + "name": "category", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, category)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "prometheus" + }, + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, severity)", + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, severity)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "prometheus" + }, + "definition": "label_values({__name__= \"policy_report_result\", status=~\"fail|error\"}, namespace)", + "includeAll": true, + "label": "Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": "label_values({__name__= \"policy_report_result\", status=~\"fail|error\"}, namespace)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "prometheus" + }, + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, kind)", + "includeAll": true, + "label": "Kind", + "multi": true, + "name": "kind", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, kind)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + }, + { + "allValue": ".*", + "current": { + "text": "All", + "value": "$__all" + }, + "datasource": { + "uid": "prometheus" + }, + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, source)", + "includeAll": true, + "label": "Source", + "multi": true, + "name": "source", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, source)", + "refresh": 2, + "regex": "", + "sort": 5, + "type": "query" + } + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": {}, + "timezone": "", + "title": "PolicyReports", + "uid": "ZkwXrUMnk", + "version": 1 +} \ No newline at end of file diff --git a/charts/policy-reporter/Chart.yaml b/charts/policy-reporter/Chart.yaml new file mode 100644 index 0000000000..16f9091273 --- /dev/null +++ b/charts/policy-reporter/Chart.yaml @@ -0,0 +1,15 @@ +apiVersion: v2 +appVersion: 3.3.1 +description: 'Policy Reporter watches for PolicyReport Resources. It creates Prometheus + Metrics and can send rule validation events to different targets like Loki, Elasticsearch, + Slack or Discord ' +home: https://kyverno.github.io/policy-reporter +icon: https://github.com/kyverno/kyverno/raw/main/img/logo.png +maintainers: +- name: Frank Jogeleit +- name: Ammar Yasser +name: policy-reporter +sources: +- https://github.com/kyverno/policy-reporter +type: application +version: 3.3.1 diff --git a/charts/policy-reporter/README.md b/charts/policy-reporter/README.md new file mode 100644 index 0000000000..6be97fda53 --- /dev/null +++ b/charts/policy-reporter/README.md @@ -0,0 +1,672 @@ +# policy-reporter + +Policy Reporter watches for PolicyReport Resources. +It creates Prometheus Metrics and can send rule validation events to different targets like Loki, Elasticsearch, Slack or Discord + +![Version: 3.3.1](https://img.shields.io/badge/Version-3.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 3.3.1](https://img.shields.io/badge/AppVersion-3.3.1-informational?style=flat-square) + +## Documentation + +You can find detailed Information and Screens about Features and Configurations in the [Documentation](https://kyverno.github.io/policy-reporter-docs). + +## Installation with Helm v3 + +Installation via Helm Repository + +### Add the Helm repository +```bash +helm repo add policy-reporter https://kyverno.github.io/policy-reporter +helm repo update +``` + +### Basic Installation + +The basic installation provides an Prometheus Metrics Endpoint and different REST APIs, for more details have a look at the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-getting-started). + +```bash +helm install policy-reporter policy-reporter/policy-reporter -n policy-reporter --create-namespace +``` + +## Policy Reporter UI + +You can use the Policy Reporter as standalone Application along with the optional UI SubChart. + +### Installation with Policy Reporter UI and Kyverno Plugin enabled + +```bash +helm install policy-reporter policy-reporter/policy-reporter --set plugin.kyverno.enabled=true --set ui.enabled=true -n policy-reporter --create-namespace +kubectl port-forward service/policy-reporter-ui 8082:8080 -n policy-reporter +``` +Open `http://localhost:8082/` in your browser. + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| nameOverride | string | `""` | Override the chart name used for all resources | +| fullnameOverride | string | `"policy-reporter"` | Overwrite the fullname of all resources | +| namespaceOverride | string | `""` | Overwrite the namespace of all resources | +| image.registry | string | `"ghcr.io"` | Image registry | +| image.repository | string | `"kyverno/policy-reporter"` | Image repository | +| image.pullPolicy | string | `"IfNotPresent"` | Image pullPolicy | +| image.tag | string | `nil` | Image tag | +| imagePullSecrets | list | `[]` | Image pullSecrets | +| priorityClassName | string | `""` | Deployment priorityClassName | +| replicaCount | int | `1` | Deployment replica count | +| revisionHistoryLimit | int | `10` | The number of revisions to keep | +| updateStrategy | object | `{}` | Deployment strategy | +| port | object | `{"name":"http","number":8080}` | Container port | +| annotations | object | `{}` | Key/value pairs that are attached to all resources. | +| rbac.enabled | bool | `true` | Create RBAC resources | +| serviceAccount.create | bool | `true` | Create ServiceAccount | +| serviceAccount.automount | bool | `true` | Enable ServiceAccount automount | +| serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount | +| serviceAccount.name | string | `""` | The ServiceAccount name | +| service.enabled | bool | `true` | Create Service | +| service.type | string | `"ClusterIP"` | Service type | +| service.port | int | `8080` | Service port | +| service.annotations | object | `{}` | Service annotations | +| service.labels | object | `{}` | Service labels | +| podSecurityContext | object | `{"fsGroup":1234}` | Security context for the pod | +| securityContext.runAsUser | int | `1234` | | +| securityContext.runAsNonRoot | bool | `true` | | +| securityContext.privileged | bool | `false` | | +| securityContext.allowPrivilegeEscalation | bool | `false` | | +| securityContext.readOnlyRootFilesystem | bool | `true` | | +| securityContext.capabilities.drop[0] | string | `"ALL"` | | +| securityContext.seccompProfile.type | string | `"RuntimeDefault"` | | +| podAnnotations | object | `{}` | Additional annotations to add to each pod | +| podLabels | object | `{}` | Additional labels to add to each pod | +| resources | object | `{}` | Resource constraints | +| networkPolicy.enabled | bool | `false` | Create NetworkPolicy | +| networkPolicy.egress | list | `[{"ports":[{"port":6443,"protocol":"TCP"}],"to":null}]` | Egress rule to allow Kubernetes API Server access | +| networkPolicy.ingress | list | `[]` | | +| ingress.enabled | bool | `false` | Create Ingress This ingress exposes the policy-reporter core app. | +| ingress.className | string | `""` | Ingress className | +| ingress.labels | object | `{}` | Labels for the Ingress | +| ingress.annotations | object | `{}` | Annotations for the Ingress | +| ingress.hosts | string | `nil` | Ingress host list | +| ingress.tls | list | `[]` | Ingress tls list | +| logging.server | bool | `false` | Enables server access logging | +| logging.encoding | string | `"console"` | Log encoding possible encodings are console and json | +| logging.logLevel | int | `0` | Log level default info | +| rest.enabled | bool | `false` | Enables the REST API | +| metrics.enabled | bool | `false` | Enables Prometheus Metrics | +| metrics.mode | string | `"detailed"` | Metric Mode allows to customize labels Allowed values: detailed, simple, custom | +| metrics.customLabels | list | `[]` | List of used labels in custom mode Supported fields are: ["namespace", "rule", "policy", "report" // Report name, "kind" // resource kind, "name" // resource name, "status", "severity", "category", "source"] | +| metrics.filter | object | `{}` | Filter results to reduce cardinality | +| profiling.enabled | bool | `false` | Enable profiling with pprof | +| worker | int | `5` | Amount of queue workers for Report resource processing | +| reportFilter | object | `{}` | Filter Report resources to process | +| sourceConfig | list | `[]` | Customize source specific logic like result ID generation | +| sourceFilters[0].selector.source | string | `"kyverno"` | select Report by source | +| sourceFilters[0].uncontrolledOnly | bool | `true` | Filter out Reports of controlled Pods and Jobs, only works for Reports with scope resource | +| sourceFilters[0].disableClusterReports | bool | `false` | Filter out cluster scoped Reports | +| sourceFilters[0].kinds | object | `{"exclude":["ReplicaSet"]}` | Filter out Reports based on the scope resource kind | +| sourceFilters[1].selector.source | string | `"KyvernoValidatingPolicy"` | select Report by source | +| sourceFilters[1].uncontrolledOnly | bool | `true` | Filter out Reports of controlled Pods and Jobs, only works for Reports with scope resource | +| sourceFilters[1].disableClusterReports | bool | `false` | Filter out cluster scoped Reports | +| sourceFilters[1].kinds | object | `{"exclude":["ReplicaSet"]}` | Filter out Reports based on the scope resource kind | +| global.labels | object | `{}` | additional labels added on each resource | +| basicAuth.username | string | `""` | HTTP BasicAuth username | +| basicAuth.password | string | `""` | HTTP BasicAuth password | +| basicAuth.secretRef | optional | `""` | Secret reference to get username and/or password from | +| emailReports.clusterName | optional | `""` | - Displayed in the email report if configured | +| emailReports.titlePrefix | string | `"Report"` | Title prefix in the email subject | +| emailReports.resources | object | `{}` | Resource constraints for the created CronJobs | +| emailReports.smtp.secret | optional | `""` | Secret reference to provide the complete or partial SMTP configuration | +| emailReports.smtp.host | string | `""` | SMTP Server Host | +| emailReports.smtp.port | int | `465` | SMTP Server Port | +| emailReports.smtp.username | string | `""` | SMTP Username | +| emailReports.smtp.password | string | `""` | SMTP Password | +| emailReports.smtp.from | string | `""` | Displayed from email address | +| emailReports.smtp.encryption | string | `""` | SMTP Encryption Default is none, supports ssl/tls and starttls | +| emailReports.smtp.skipTLS | bool | `false` | Skip SMTP TLS verification | +| emailReports.smtp.certificate | string | `""` | SMTP Server Certificate file path | +| emailReports.summary.enabled | bool | `false` | Enable Summary E-Mail reports | +| emailReports.summary.schedule | string | `"0 8 * * *"` | CronJob schedule | +| emailReports.summary.activeDeadlineSeconds | int | `300` | CronJob activeDeadlineSeconds | +| emailReports.summary.backoffLimit | int | `3` | CronJob backoffLimit | +| emailReports.summary.ttlSecondsAfterFinished | int | `0` | CronJob ttlSecondsAfterFinished | +| emailReports.summary.restartPolicy | string | `"Never"` | CronJob restartPolicy | +| emailReports.summary.to | list | `[]` | List of receiver email addresses | +| emailReports.summary.filter | optional | `{}` | Report filter | +| emailReports.summary.channels | optional | `[]` | Channels can be used to to send only a subset of namespaces / sources to dedicated email addresses | +| emailReports.violations.enabled | bool | `false` | Enable Violation Summary E-Mail reports | +| emailReports.violations.schedule | string | `"0 8 * * *"` | CronJob schedule | +| emailReports.violations.activeDeadlineSeconds | int | `300` | CronJob activeDeadlineSeconds | +| emailReports.violations.backoffLimit | int | `3` | CronJob backoffLimit | +| emailReports.violations.ttlSecondsAfterFinished | int | `0` | CronJob ttlSecondsAfterFinished | +| emailReports.violations.restartPolicy | string | `"Never"` | CronJob restartPolicy | +| emailReports.violations.to | list | `[]` | List of receiver email addresses | +| emailReports.violations.filter | optional | `{}` | Report filter | +| emailReports.violations.channels | optional | `[]` | Channels can be used to to send only a subset of namespaces / sources to dedicated email addresses | +| existingTargetConfig.enabled | bool | `false` | Use an already existing configuration | +| existingTargetConfig.name | string | `""` | Name of the secret with the config | +| existingTargetConfig.subPath | string | `""` | SubPath within the secret (defaults to config.yaml) | +| target.crd | bool | `false` | enable and install TargetConfig CRD | +| target.loki.host | string | `""` | Host Address | +| target.loki.path | string | `""` | Loki API, defaults to "/loki/api/v1/push" | +| target.loki.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.loki.skipTLS | bool | `false` | Skip TLS verification | +| target.loki.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.loki.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.loki.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.loki.sources | list | `[]` | List of sources which should send | +| target.loki.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.loki.customFields | object | `{}` | Added as additional labels | +| target.loki.headers | object | `{}` | Additional HTTP Headers | +| target.loki.username | string | `""` | HTTP BasicAuth username | +| target.loki.password | string | `""` | HTTP BasicAuth password | +| target.loki.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.loki.channels | list | `[]` | List of channels to route results to different configurations | +| target.elasticsearch.host | string | `""` | Host address | +| target.elasticsearch.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.elasticsearch.skipTLS | bool | `false` | Skip TLS verification | +| target.elasticsearch.headers | object | `{}` | Additional HTTP Headers | +| target.elasticsearch.index | string | `"policy-reporter"` | Elasticsearch index (default: policy-reporter) | +| target.elasticsearch.rotation | string | `"daily"` | Elasticsearch index rotation and index suffix Possible values: daily, monthly, annually, none (default: daily) | +| target.elasticsearch.typelessApi | bool | `false` | Enables Elasticsearch typless API https://www.elastic.co/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0 keeping as false for retrocompatibility. | +| target.elasticsearch.username | string | `""` | HTTP BasicAuth username | +| target.elasticsearch.password | string | `""` | HTTP BasicAuth password | +| target.elasticsearch.apiKey | string | `""` | Elasticsearch API Key for api key authentication | +| target.elasticsearch.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.elasticsearch.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.elasticsearch.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.elasticsearch.sources | list | `[]` | List of sources which should send | +| target.elasticsearch.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.elasticsearch.customFields | object | `{}` | Added as additional labels | +| target.elasticsearch.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.elasticsearch.channels | list | `[]` | List of channels to route results to different configurations | +| target.slack.webhook | string | `""` | Webhook Address | +| target.slack.channel | string | `""` | Slack Channel | +| target.slack.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.slack.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.slack.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.slack.sources | list | `[]` | List of sources which should send | +| target.slack.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.slack.customFields | object | `{}` | Added as additional labels | +| target.slack.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.slack.channels | list | `[]` | List of channels to route results to different configurations | +| target.discord.webhook | string | `""` | Webhook Address | +| target.discord.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.discord.skipTLS | bool | `false` | Skip TLS verification | +| target.discord.headers | object | `{}` | Additional HTTP Headers | +| target.discord.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.discord.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.discord.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.discord.sources | list | `[]` | List of sources which should send | +| target.discord.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.discord.customFields | object | `{}` | Added as additional labels | +| target.discord.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.discord.channels | list | `[]` | List of channels to route results to different configurations | +| target.teams.webhook | string | `""` | Webhook Address | +| target.teams.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.teams.skipTLS | bool | `false` | Skip TLS verification | +| target.teams.headers | object | `{}` | Additional HTTP Headers | +| target.teams.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.teams.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.teams.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.teams.sources | list | `[]` | List of sources which should send | +| target.teams.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.teams.customFields | object | `{}` | Added as additional labels | +| target.teams.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.teams.channels | list | `[]` | List of channels to route results to different configurations | +| target.webhook.webhook | string | `""` | Webhook Address | +| target.webhook.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.webhook.skipTLS | bool | `false` | Skip TLS verification | +| target.webhook.headers | object | `{}` | Additional HTTP Headers | +| target.webhook.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.webhook.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.webhook.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.webhook.sources | list | `[]` | List of sources which should send | +| target.webhook.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.webhook.customFields | object | `{}` | Added as additional labels | +| target.webhook.keepalive | object | `{"interval":"0","params":{}}` | Keepalive configuration | +| target.webhook.keepalive.interval | string | `"0"` | Duration string like "30s" for heartbeat interval, '0' - disabled | +| target.webhook.keepalive.params | object | `{}` | Additional parameters to include in heartbeat payload | +| target.webhook.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.webhook.channels | list | `[]` | List of channels to route results to different configurations | +| target.telegram.token | string | `""` | Telegram bot token | +| target.telegram.chatId | string | `""` | Telegram chat id | +| target.telegram.host | optional | `""` | Telegram proxy host | +| target.telegram.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.telegram.skipTLS | bool | `false` | Skip TLS verification | +| target.telegram.headers | object | `{}` | Additional HTTP Headers | +| target.telegram.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.telegram.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.telegram.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.telegram.sources | list | `[]` | List of sources which should send | +| target.telegram.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.telegram.customFields | object | `{}` | Added as additional labels | +| target.telegram.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.telegram.channels | list | `[]` | List of channels to route results to different configurations | +| target.googleChat.webhook | string | `""` | Webhook Address | +| target.googleChat.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.googleChat.skipTLS | bool | `false` | Skip TLS verification | +| target.googleChat.headers | object | `{}` | Additional HTTP Headers | +| target.googleChat.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.googleChat.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.googleChat.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.googleChat.sources | list | `[]` | List of sources which should send | +| target.googleChat.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.googleChat.customFields | object | `{}` | Added as additional labels | +| target.googleChat.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.googleChat.channels | list | `[]` | List of channels to route results to different configurations | +| target.jira.host | string | `""` | JIRA server URL | +| target.jira.username | string | `""` | JIRA username | +| target.jira.password | string | `""` | JIRA password (use password or apiToken, not both) | +| target.jira.apiToken | string | `""` | JIRA API token (use password or apiToken, not both) | +| target.jira.apiVersion | string | `"v3"` | JIRA static labels | +| target.jira.projectKey | string | `""` | JIRA project key | +| target.jira.issueType | string | `""` | JIRA issue type (default: "Bug") | +| target.jira.components | list | `[]` | JIRA component names list | +| target.jira.labels | list | `[]` | JIRA static labels | +| target.jira.summaryTemplate | string | `""` | JIRA summary go template, available values: result, customfield default: "{{ if result.ResourceString }}{{ result.ResourceString }}: {{ end }}Policy Violation: {{ result.Policy }}" | +| target.jira.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.jira.skipTLS | bool | `false` | Skip TLS verification | +| target.jira.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.jira.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.jira.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.jira.sources | list | `[]` | List of sources which should send | +| target.jira.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.jira.customFields | object | `{}` | Added as additional labels | +| target.jira.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.jira.channels | list | `[]` | List of channels to route results to different configurations | +| target.alertManager.host | string | `""` | host address | +| target.alertManager.certificate | string | `""` | Server Certificate file path Can be added under extraVolumes | +| target.alertManager.skipTLS | bool | `false` | Skip TLS verification | +| target.alertManager.headers | object | `{}` | Additional HTTP Headers | +| target.alertManager.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.alertManager.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.alertManager.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.alertManager.sources | list | `[]` | List of sources which should send | +| target.alertManager.skipExistingOnStartup | bool | `true` | Skip already existing PolicyReportResults on startup | +| target.alertManager.customFields | object | `{}` | Added as additional labels | +| target.alertManager.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.alertManager.channels | list | `[]` | List of channels to route results to different configurations | +| target.s3.accessKeyId | optional | `""` | S3 Access key | +| target.s3.secretAccessKey | optional | `""` | S3 SecretAccess key | +| target.s3.region | optional | `""` | S3 Storage region | +| target.s3.endpoint | optional | `""` | S3 Storage endpoint | +| target.s3.bucket | required | `""` | S3 Storage bucket name | +| target.s3.bucketKeyEnabled | bool | `false` | S3 Storage to use an S3 Bucket Key for object encryption with SSE-KMS | +| target.s3.kmsKeyId | string | `""` | S3 Storage KMS Key ID for object encryption with SSE-KMS | +| target.s3.serverSideEncryption | string | `""` | S3 Storage server-side encryption algorithm used when storing this object in Amazon S3, AES256, aws:kms | +| target.s3.pathStyle | bool | `false` | S3 Storage, force path style configuration | +| target.s3.prefix | string | `""` | Used prefix, keys will have format: s3:////YYYY-MM-DD/YYYY-MM-DDTHH:mm:ss.s+01:00.json | +| target.s3.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.s3.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.s3.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.s3.sources | list | `[]` | List of sources which should send | +| target.s3.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.s3.customFields | object | `{}` | Added as additional labels | +| target.s3.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.s3.channels | list | `[]` | List of channels to route results to different configurations | +| target.kinesis.accessKeyId | optional | `""` | Access key | +| target.kinesis.secretAccessKey | optional | `""` | SecretAccess key | +| target.kinesis.region | optional | `""` | Region | +| target.kinesis.endpoint | optional | `""` | Endpoint | +| target.kinesis.streamName | required | `""` | StreamName | +| target.kinesis.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.kinesis.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.kinesis.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.kinesis.sources | list | `[]` | List of sources which should send | +| target.kinesis.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.kinesis.customFields | object | `{}` | Added as additional labels | +| target.kinesis.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.kinesis.channels | list | `[]` | List of channels to route results to different configurations | +| target.securityHub.accessKeyId | optional | `""` | Access key | +| target.securityHub.secretAccessKey | optional | `""` | SecretAccess key | +| target.securityHub.region | optional | `""` | Region | +| target.securityHub.endpoint | optional | `""` | Endpoint | +| target.securityHub.accountId | required | `""` | AccountId | +| target.securityHub.productName | optional | `""` | Used product name, defaults to "Polilcy Reporter" | +| target.securityHub.companyName | optional | `""` | Used company name, defaults to "Kyverno" | +| target.securityHub.synchronize | bool | `true` | Enable cleanup listener for SecurityHub | +| target.securityHub.delayInSeconds | int | `2` | Delay between AWS GetFindings API calls, to avoid hitting the API RequestLimit | +| target.securityHub.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.securityHub.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.securityHub.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.securityHub.sources | list | `[]` | List of sources which should send | +| target.securityHub.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.securityHub.customFields | object | `{}` | Added as additional labels | +| target.securityHub.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.securityHub.channels | list | `[]` | List of channels to route results to different configurations | +| target.gcs.credentials | optional | `""` | GCS (Google Cloud Storage) Service Account Credentials | +| target.gcs.bucket | required | `""` | GCS Bucket | +| target.gcs.secretRef | string | `""` | Read configuration from an already existing Secret | +| target.gcs.mountedSecret | string | `""` | Mounted secret path by Secrets Controller, secret should be in json format | +| target.gcs.minimumSeverity | string | `""` | Minimum severity: "" < info < low < medium < high < critical | +| target.gcs.sources | list | `[]` | List of sources which should send | +| target.gcs.skipExistingOnStartup | bool | `true` | Skip already existing report results on startup | +| target.gcs.customFields | object | `{}` | Added as additional labels | +| target.gcs.filter | object | `{}` | Filter Results which should send to this target Wildcars for namespaces and policies are supported, you can either define exclude or include values Filters are available for all targets except the UI | +| target.gcs.channels | list | `[]` | List of channels to route results to different configurations | +| leaderElection.releaseOnCancel | bool | `true` | | +| leaderElection.leaseDuration | int | `15` | | +| leaderElection.renewDeadline | int | `10` | | +| leaderElection.retryPeriod | int | `2` | | +| redis.enabled | bool | `false` | Enables Redis as external result cache, uses in memory cache by default | +| redis.address | string | `""` | Redis host | +| redis.database | int | `0` | Redis database | +| redis.prefix | string | `"policy-reporter"` | Redis key prefix | +| redis.username | optional | `""` | Username | +| redis.password | optional | `""` | Password | +| database.type | string | `""` | Use an external Database, supported: mysql, postgres, mariadb | +| database.database | string | `""` | Database | +| database.username | string | `""` | Username | +| database.password | string | `""` | Password | +| database.host | string | `""` | Host Address | +| database.enableSSL | bool | `false` | Enables SSL | +| database.dsn | string | `""` | 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 | +| database.secretRef | string | `""` | Read configuration from an existing Secret supported fields: username, password, host, dsn, database | +| 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 | `{}` | Node labels for pod assignment ref: https://kubernetes.io/docs/user-guide/node-selection/ | +| tolerations | list | `[]` | Tolerations for pod assignment ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ | +| affinity | object | `{}` | Anti-affinity to disallow deploying client and master nodes on the same worker node | +| topologySpreadConstraints | list | `[]` | Topology Spread Constraints to better spread pods | +| livenessProbe | object | `{"httpGet":{"path":"/ready","port":"http"}}` | Deployment livenessProbe for policy-reporter | +| readinessProbe | object | `{"httpGet":{"path":"/healthz","port":"http"}}` | Deployment readinessProbe for policy-reporter | +| extraVolumes.volumeMounts | list | `[]` | Deployment volumeMounts | +| extraVolumes.volumes | list | `[]` | Deployment values | +| sqliteVolume | object | `{}` | If set the volume for sqlite is freely configurable below "- name: sqlite". If no value is set an emptyDir is used. | +| envVars | list | `[]` | Allow additional env variables to be added | +| tmpVolume | object | `{}` | Allow custom configuration of the /tmp volume | +| ui.enabled | bool | `false` | Enable Policy Reporter UI | +| 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.4.1"` | Image tag | +| ui.replicaCount | int | `1` | Deployment replica count | +| ui.priorityClassName | string | `""` | Deployment priorityClassName | +| ui.logging.api | bool | `false` | Enables external api request logging | +| ui.logging.server | bool | `false` | Enables server access logging | +| ui.logging.encoding | string | `"console"` | Log encoding possible encodings are console and json | +| ui.logging.logLevel | int | `0` | Log level default info | +| ui.server.port | int | `8080` | Application port | +| ui.server.cors | bool | `true` | Enabled CORS header | +| ui.server.overwriteHost | bool | `true` | Overwrites Request Host with Proxy Host and adds `X-Forwarded-Host` and `X-Origin-Host` headers | +| ui.server.sessions | object | `{"storage":"filesystem","tempDir":"/tmp"}` | session configuration | +| ui.openIDConnect.enabled | bool | `false` | Enable openID Connect authentication | +| ui.openIDConnect.discoveryUrl | string | `""` | OpenID Connect Discovery URL | +| ui.openIDConnect.callbackUrl | string | `""` | OpenID Connect Callback URL | +| ui.openIDConnect.clientId | string | `""` | OpenID Connect ClientID | +| ui.openIDConnect.clientSecret | string | `""` | OpenID Connect ClientSecret | +| ui.openIDConnect.groupClaim | string | `""` | Optional Group Claim to map user groups to the profile groups can be used to define access control for clusters, boards and custom boards. | +| ui.openIDConnect.scopes | list | `[]` | OpenID Connect allowed Scopes | +| ui.openIDConnect.skipTLS | bool | `false` | Skip TLS Verification | +| ui.openIDConnect.certificate | string | `""` | TLS Certificate file path | +| ui.openIDConnect.secretRef | string | `""` | Provide OpenID Connect configuration via Secret supported keys: `discoveryUrl`, `clientId`, `clientSecret`, `certificate`, `skipTLS` | +| ui.oauth.enabled | bool | `false` | Enable openID Connect authentication | +| ui.oauth.provider | string | `""` | OAuth2 Provider supported: amazon, gitlab, github, apple, google, yandex, azuread | +| ui.oauth.callbackUrl | string | `""` | OpenID Connect Callback URL | +| ui.oauth.clientId | string | `""` | OpenID Connect ClientID | +| ui.oauth.clientSecret | string | `""` | OpenID Connect ClientSecret | +| ui.oauth.scopes | list | `[]` | OpenID Connect allowed Scopes | +| ui.oauth.secretRef | string | `""` | Provide OpenID Connect configuration via Secret supported keys: `provider`, `clientId`, `clientSecret` | +| ui.banner | string | `""` | optional banner text | +| ui.logo.path | string | `""` | custom logo path | +| ui.logo.disabled | bool | `false` | disable logo entirely | +| ui.displayMode | string | `""` | DisplayMode dark/light/colorblind/colorblinddark uses the OS configured preferred color scheme as default | +| ui.boards | object | `{}` | Configure access control for all default boards. | +| ui.customBoards | list | `[]` | Additional customizable dashboards | +| ui.sources | list | `[]` | source specific configurations | +| ui.name | string | `"Default"` | | +| ui.clusters | list | `[]` | 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 | +| ui.serviceAccount.automount | bool | `true` | Enable ServiceAccount automount | +| ui.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount | +| ui.serviceAccount.name | string | `""` | The ServiceAccount name | +| ui.sidecarContainers | object | `{}` | Add sidecar containers to the UI deployment sidecarContainers: oauth-proxy: image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0 args: - --upstream=http://127.0.0.1:8080 - --http-address=0.0.0.0:8081 - ... ports: - containerPort: 8081 name: oauth-proxy protocol: TCP resources: {} | +| ui.podAnnotations | object | `{}` | Additional annotations to add to each pod | +| ui.podLabels | object | `{}` | Additional labels to add to each pod | +| ui.updateStrategy | object | `{}` | Deployment update strategy. Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy | +| ui.revisionHistoryLimit | int | `10` | The number of revisions to keep | +| ui.podSecurityContext | object | `{"runAsGroup":1234,"runAsUser":1234}` | Security context for the pod | +| ui.envVars | list | `[]` | Allow additional env variables to be added | +| ui.rbac.enabled | bool | `true` | Create RBAC resources | +| ui.securityContext.runAsUser | int | `1234` | | +| ui.securityContext.runAsNonRoot | bool | `true` | | +| ui.securityContext.privileged | bool | `false` | | +| ui.securityContext.allowPrivilegeEscalation | bool | `false` | | +| ui.securityContext.readOnlyRootFilesystem | bool | `true` | | +| ui.securityContext.capabilities.drop[0] | string | `"ALL"` | | +| ui.securityContext.seccompProfile.type | string | `"RuntimeDefault"` | | +| ui.livenessProbe | object | `{"httpGet":{"path":"/healthz","port":"http"}}` | Deployment livenessProbe for policy-reporter-ui | +| ui.readinessProbe | object | `{"httpGet":{"path":"/healthz","port":"http"}}` | Deployment readinessProbe for policy-reporter-ui | +| ui.service.type | string | `"ClusterIP"` | Service type. | +| ui.service.port | int | `8080` | Service port. | +| ui.service.annotations | object | `{}` | Service annotations. | +| ui.service.labels | object | `{}` | Service labels. | +| ui.service.additionalPorts | list | `[]` | Additional service ports for e.g. Sidecars # - name: authenticated additionalPorts: - name: authenticated port: 8081 targetPort: 8081 | +| ui.ingress.enabled | bool | `false` | Create ingress resource. | +| ui.ingress.port | string | `nil` | Redirect ingress to an additional defined port on the service | +| ui.ingress.className | string | `""` | Ingress class name. | +| ui.ingress.labels | object | `{}` | Ingress labels. | +| ui.ingress.annotations | object | `{}` | Ingress annotations. | +| ui.ingress.hosts | list | `[]` | List of ingress host configurations. | +| ui.ingress.tls | list | `[]` | List of ingress TLS configurations. | +| ui.networkPolicy.enabled | bool | `false` | When true, use a NetworkPolicy to allow ingress to the webhook This is useful on clusters using Calico and/or native k8s network policies in a default-deny setup. | +| ui.networkPolicy.egress | list | `[{"ports":[{"port":6443,"protocol":"TCP"}]}]` | A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. Enables Kubernetes API Server by default | +| ui.networkPolicy.ingress | list | `[]` | A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. | +| ui.resources | object | `{}` | Resource constraints | +| ui.podDisruptionBudget.minAvailable | int | `1` | Configures the minimum available pods for kyvernoPlugin disruptions. Cannot be used if `maxUnavailable` is set. | +| ui.podDisruptionBudget.maxUnavailable | string | `nil` | Configures the maximum unavailable pods for kyvernoPlugin disruptions. Cannot be used if `minAvailable` is set. | +| ui.nodeSelector | object | `{}` | Node labels for pod assignment | +| ui.tolerations | list | `[]` | List of node taints to tolerate | +| ui.affinity | object | `{}` | Affinity constraints. | +| ui.extraVolumes.volumeMounts | list | `[]` | Deployment volumeMounts | +| ui.extraVolumes.volumes | list | `[]` | Deployment values | +| ui.extraConfig | object | `{}` | Extra configuration options appended to UI settings | +| plugin.kyverno.enabled | bool | `false` | Enable Kyverno Plugin | +| plugin.kyverno.image.registry | string | `"ghcr.io"` | Image registry | +| plugin.kyverno.image.repository | string | `"kyverno/policy-reporter/kyverno-plugin"` | Image repository | +| plugin.kyverno.image.pullPolicy | string | `"IfNotPresent"` | Image PullPolicy | +| plugin.kyverno.image.tag | string | `"0.5.0"` | Image tag | +| plugin.kyverno.replicaCount | int | `1` | Deployment replica count | +| plugin.kyverno.priorityClassName | string | `""` | Deployment priorityClassName | +| plugin.kyverno.logging.api | bool | `false` | Enables external API request logging | +| plugin.kyverno.logging.server | bool | `false` | Enables Server access logging | +| plugin.kyverno.logging.encoding | string | `"console"` | log encoding possible encodings are console and json | +| plugin.kyverno.logging.logLevel | int | `0` | log level default info | +| plugin.kyverno.server.port | int | `8080` | Application port | +| plugin.kyverno.blockReports.enabled | bool | `false` | Enables he BlockReport feature | +| plugin.kyverno.blockReports.eventNamespace | string | `"default"` | Watches for Kyverno Events in the configured namespace leave blank to watch in all namespaces | +| plugin.kyverno.blockReports.source | string | `"Kyverno Event"` | Used value for the source field in the created (Cluster)PolicyReports | +| plugin.kyverno.blockReports.results.maxPerReport | int | `200` | Max items per PolicyReport resource | +| plugin.kyverno.blockReports.results.keepOnlyLatest | bool | `false` | Keep only the latest of duplicated events | +| plugin.kyverno.blockReports.policyReport.labels | list | `[]` | Labels for all created (Cluster)PolicyReports | +| plugin.kyverno.blockReports.policyReport.annotations | list | `[]` | Annotations for all created (Cluster)PolicyReports | +| plugin.kyverno.imagePullSecrets | list | `[]` | Image pull secrets for image verification policies, this will define the `--imagePullSecrets` argument | +| plugin.kyverno.serviceAccount.create | bool | `true` | Create ServiceAccount | +| plugin.kyverno.serviceAccount.automount | bool | `true` | Enable ServiceAccount automount | +| plugin.kyverno.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount | +| plugin.kyverno.serviceAccount.name | string | `""` | The ServiceAccount name | +| plugin.kyverno.podAnnotations | object | `{}` | Additional annotations to add to each pod | +| plugin.kyverno.podLabels | object | `{}` | Additional labels to add to each pod | +| plugin.kyverno.updateStrategy | object | `{}` | Deployment update strategy. Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy | +| plugin.kyverno.revisionHistoryLimit | int | `10` | The number of revisions to keep | +| plugin.kyverno.podSecurityContext | object | `{"runAsGroup":1234,"runAsUser":1234}` | Security context for the pod | +| plugin.kyverno.envVars | list | `[]` | Allow additional env variables to be added | +| plugin.kyverno.rbac.enabled | bool | `true` | Create RBAC resources | +| plugin.kyverno.securityContext.runAsUser | int | `1234` | | +| plugin.kyverno.securityContext.runAsNonRoot | bool | `true` | | +| plugin.kyverno.securityContext.privileged | bool | `false` | | +| plugin.kyverno.securityContext.allowPrivilegeEscalation | bool | `false` | | +| plugin.kyverno.securityContext.readOnlyRootFilesystem | bool | `true` | | +| plugin.kyverno.securityContext.capabilities.drop[0] | string | `"ALL"` | | +| plugin.kyverno.securityContext.seccompProfile.type | string | `"RuntimeDefault"` | | +| plugin.kyverno.service.type | string | `"ClusterIP"` | Service type. | +| plugin.kyverno.service.port | int | `8080` | Service port. | +| plugin.kyverno.service.annotations | object | `{}` | Service annotations. | +| plugin.kyverno.service.labels | object | `{}` | Service labels. | +| plugin.kyverno.ingress.enabled | bool | `false` | Create ingress resource. | +| plugin.kyverno.ingress.className | string | `""` | Ingress class name. | +| plugin.kyverno.ingress.labels | object | `{}` | Ingress labels. | +| plugin.kyverno.ingress.annotations | object | `{}` | Ingress annotations. | +| plugin.kyverno.ingress.hosts | list | `[]` | List of ingress host configurations. | +| plugin.kyverno.ingress.tls | list | `[]` | List of ingress TLS configurations. | +| plugin.kyverno.networkPolicy.enabled | bool | `false` | When true, use a NetworkPolicy to allow ingress to the webhook This is useful on clusters using Calico and/or native k8s network policies in a default-deny setup. | +| plugin.kyverno.networkPolicy.egress | list | `[{"ports":[{"port":6443,"protocol":"TCP"}]}]` | A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. Enables Kubernetes API Server by default | +| plugin.kyverno.networkPolicy.ingress | list | `[]` | A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. | +| plugin.kyverno.resources | object | `{}` | Resource constraints | +| plugin.kyverno.leaderElection.lockName | string | `"kyverno-plugin"` | Lock Name | +| plugin.kyverno.leaderElection.releaseOnCancel | bool | `true` | Released lock when the run context is cancelled. | +| plugin.kyverno.leaderElection.leaseDuration | int | `15` | LeaseDuration is the duration that non-leader candidates will wait to force acquire leadership. | +| plugin.kyverno.leaderElection.renewDeadline | int | `10` | RenewDeadline is the duration that the acting master will retry refreshing leadership before giving up. | +| plugin.kyverno.leaderElection.retryPeriod | int | `2` | RetryPeriod is the duration the LeaderElector clients should wait between tries of actions. | +| plugin.kyverno.podDisruptionBudget.minAvailable | int | `1` | Configures the minimum available pods for kyvernoPlugin disruptions. Cannot be used if `maxUnavailable` is set. | +| plugin.kyverno.podDisruptionBudget.maxUnavailable | string | `nil` | Configures the maximum unavailable pods for kyvernoPlugin disruptions. Cannot be used if `minAvailable` is set. | +| plugin.kyverno.nodeSelector | object | `{}` | Node labels for pod assignment | +| plugin.kyverno.tolerations | list | `[]` | List of node taints to tolerate | +| plugin.kyverno.affinity | object | `{}` | Affinity constraints. | +| plugin.kyverno.topologySpreadConstraints | object | `{}` | Pod Topology Spread Constraints for the kyverno plugin. | +| plugin.kyverno.extraVolumes.volumeMounts | list | `[]` | Deployment volumeMounts | +| plugin.kyverno.extraVolumes.volumes | list | `[]` | Deployment values | +| plugin.kyverno.extraConfig | object | `{}` | Extra configuration options appended to kyverno plugin settings | +| plugin.trivy.enabled | bool | `false` | Enable Trivy Operator Plugin | +| plugin.trivy.image.registry | string | `"ghcr.io"` | Image registry | +| plugin.trivy.image.repository | string | `"kyverno/policy-reporter/trivy-plugin"` | Image repository | +| plugin.trivy.image.pullPolicy | string | `"IfNotPresent"` | Image PullPolicy | +| plugin.trivy.image.tag | string | `"0.4.9"` | Image tag Defaults to `Chart.AppVersion` if omitted | +| plugin.trivy.cli.image.registry | string | `"ghcr.io"` | Image registry | +| plugin.trivy.cli.image.repository | string | `"aquasecurity/trivy"` | Image repository | +| plugin.trivy.cli.image.pullPolicy | string | `"IfNotPresent"` | Image PullPolicy | +| plugin.trivy.cli.image.tag | string | `"0.63.0"` | Image tag Defaults to `Chart.AppVersion` if omitted | +| plugin.trivy.extraArgs | object | `{}` | Additional container args. | +| plugin.trivy.cveawg.disable | bool | `false` | disable external CVEAWG API calls. | +| plugin.trivy.github.disable | bool | `false` | disable GitHub API calls. | +| plugin.trivy.github.token | string | `""` | optional github token for authenticated GitHub API calls. | +| plugin.trivy.dbVolume | object | `{}` | If set the volume for dbVolume is freely configurable below "- name: dbVolume". If no value is set an emptyDir is used. | +| plugin.trivy.tmpVolume | object | `{}` | If set the volume for tmpVolume is freely configurable below "- name: tmpVolume". If no value is set an emptyDir is used. | +| plugin.trivy.replicaCount | int | `1` | Deployment replica count | +| plugin.trivy.priorityClassName | string | `""` | Deployment priorityClassName | +| plugin.trivy.logging.api | bool | `false` | Enables external API request logging | +| plugin.trivy.logging.server | bool | `false` | Enables Server access logging | +| plugin.trivy.logging.encoding | string | `"console"` | log encoding possible encodings are console and json | +| plugin.trivy.logging.logLevel | int | `0` | log level default info | +| plugin.trivy.server.port | int | `8080` | Application port | +| plugin.trivy.policyReporter.skipTLS | bool | `false` | Skip TLS Verification | +| plugin.trivy.policyReporter.certificate | string | `""` | TLS Certificate file path | +| plugin.trivy.policyReporter.secretRef | string | `""` | Secret to read the API configuration from supports `host`, `certificate`, `skipTLS`, `username`, `password` key | +| plugin.trivy.imagePullSecrets | list | `[]` | Image pull secrets for image verification policies, this will define the `--imagePullSecrets` argument | +| plugin.trivy.serviceAccount.create | bool | `true` | Create ServiceAccount | +| plugin.trivy.serviceAccount.automount | bool | `true` | Enable ServiceAccount automount | +| plugin.trivy.serviceAccount.annotations | object | `{}` | Annotations for the ServiceAccount | +| plugin.trivy.serviceAccount.name | string | `""` | The ServiceAccount name | +| plugin.trivy.podAnnotations | object | `{}` | Additional annotations to add to each pod | +| plugin.trivy.podLabels | object | `{}` | Additional labels to add to each pod | +| plugin.trivy.updateStrategy | object | `{}` | Deployment update strategy. Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy | +| plugin.trivy.revisionHistoryLimit | int | `10` | The number of revisions to keep | +| plugin.trivy.podSecurityContext | object | `{"runAsGroup":1234,"runAsUser":1234}` | Security context for the pod | +| plugin.trivy.livenessProbe | object | `{"httpGet":{"path":"/vulnr/v1/policies","port":"http"},"timeoutSeconds":3}` | Deployment livenessProbe for policy-reporter-trivy-plugin | +| plugin.trivy.readinessProbe | object | `{"httpGet":{"path":"/vulnr/v1/policies","port":"http"},"timeoutSeconds":3}` | Deployment readinessProbe for policy-reporter-trivy-plugin | +| plugin.trivy.envVars | list | `[]` | Allow additional env variables to be added | +| plugin.trivy.rbac.enabled | bool | `true` | Create RBAC resources | +| plugin.trivy.securityContext.runAsUser | int | `1234` | | +| plugin.trivy.securityContext.runAsNonRoot | bool | `true` | | +| plugin.trivy.securityContext.privileged | bool | `false` | | +| plugin.trivy.securityContext.allowPrivilegeEscalation | bool | `false` | | +| plugin.trivy.securityContext.readOnlyRootFilesystem | bool | `true` | | +| plugin.trivy.securityContext.capabilities.drop[0] | string | `"ALL"` | | +| plugin.trivy.securityContext.seccompProfile.type | string | `"RuntimeDefault"` | | +| plugin.trivy.service.type | string | `"ClusterIP"` | Service type. | +| plugin.trivy.service.port | int | `8080` | Service port. | +| plugin.trivy.service.annotations | object | `{}` | Service annotations. | +| plugin.trivy.service.labels | object | `{}` | Service labels. | +| plugin.trivy.ingress.enabled | bool | `false` | Create ingress resource. | +| plugin.trivy.ingress.className | string | `""` | Ingress class name. | +| plugin.trivy.ingress.labels | object | `{}` | Ingress labels. | +| plugin.trivy.ingress.annotations | object | `{}` | Ingress annotations. | +| plugin.trivy.ingress.hosts | list | `[]` | List of ingress host configurations. | +| plugin.trivy.ingress.tls | list | `[]` | List of ingress TLS configurations. | +| plugin.trivy.networkPolicy.enabled | bool | `false` | When true, use a NetworkPolicy to allow ingress to the webhook This is useful on clusters using Calico and/or native k8s network policies in a default-deny setup. | +| plugin.trivy.networkPolicy.egress | list | `[{"ports":[{"port":6443,"protocol":"TCP"}]}]` | A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. Enables Kubernetes API Server by default | +| plugin.trivy.networkPolicy.ingress | list | `[]` | A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. | +| plugin.trivy.resources | object | `{}` | Resource constraints | +| plugin.trivy.podDisruptionBudget.minAvailable | int | `1` | Configures the minimum available pods for kyvernoPlugin disruptions. Cannot be used if `maxUnavailable` is set. | +| plugin.trivy.podDisruptionBudget.maxUnavailable | string | `nil` | Configures the maximum unavailable pods for kyvernoPlugin disruptions. Cannot be used if `minAvailable` is set. | +| plugin.trivy.nodeSelector | object | `{}` | Node labels for pod assignment | +| plugin.trivy.tolerations | list | `[]` | List of node taints to tolerate | +| plugin.trivy.affinity | object | `{}` | Affinity constraints. | +| plugin.trivy.topologySpreadConstraints | object | `{}` | Pod Topology Spread Constraints for the trivy plugin. | +| plugin.trivy.extraVolumes.volumeMounts | list | `[]` | Deployment volumeMounts | +| plugin.trivy.extraVolumes.volumes | list | `[]` | Deployment values | +| plugin.trivy.extraConfig | object | `{}` | Extra configuration options appended to trivy plugin settings | +| monitoring.enabled | bool | `false` | Enables the Prometheus Operator integration | +| monitoring.annotations | object | `{}` | Key/value pairs that are attached to all resources. | +| monitoring.serviceMonitor.honorLabels | bool | `false` | HonorLabels chooses the metrics labels on collisions with target labels | +| monitoring.serviceMonitor.namespace | string | `nil` | Allow to override the namespace for serviceMonitor | +| monitoring.serviceMonitor.labels | object | `{}` | Labels to match the serviceMonitorSelector of the Prometheus Resource | +| monitoring.serviceMonitor.relabelings | list | `[]` | ServiceMonitor Relabelings https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig | +| monitoring.serviceMonitor.metricRelabelings | list | `[]` | See serviceMonitor.relabelings | +| monitoring.serviceMonitor.namespaceSelector | optional | `{}` | NamespaceSelector | +| monitoring.serviceMonitor.scrapeTimeout | optional | `nil` | ScrapeTimeout | +| monitoring.serviceMonitor.interval | optional | `nil` | Scrape interval | +| monitoring.grafana.namespace | string | `nil` | Naamespace for configMap of grafana dashboards | +| monitoring.grafana.dashboards.enabled | bool | `true` | Enable the deployment of grafana dashboards | +| monitoring.grafana.dashboards.label | string | `"grafana_dashboard"` | Label to find dashboards using the k8s sidecar | +| monitoring.grafana.dashboards.value | string | `"1"` | Label value to find dashboards using the k8s sidecar | +| monitoring.grafana.dashboards.labelFilter | list | `[]` | List of custom label filter Used to add filter for report label based metric labels defined in custom mode | +| monitoring.grafana.dashboards.multicluster.enabled | bool | `false` | Enable cluster filter in all dashboards | +| monitoring.grafana.dashboards.multicluster.label | string | `"cluster"` | Metric Label which is used to filter clusters | +| monitoring.grafana.dashboards.enable.overview | bool | `true` | Enable the Overview Dashboard | +| monitoring.grafana.dashboards.enable.policyReportDetails | bool | `true` | Enable the PolicyReport Dashboard | +| monitoring.grafana.dashboards.enable.clusterPolicyReportDetails | bool | `true` | Enable the ClusterPolicyReport Dashboard | +| monitoring.grafana.folder.annotation | string | `"grafana_folder"` | Annotation to enable folder storage using the k8s sidecar | +| monitoring.grafana.folder.name | string | `"Policy Reporter"` | Grafana folder in which to store the dashboards | +| monitoring.grafana.datasource.label | string | `"Prometheus"` | Grafana Datasource Label | +| monitoring.grafana.datasource.pluginId | string | `"prometheus"` | Grafana Datasource PluginId | +| monitoring.grafana.datasource.pluginName | string | `"Prometheus"` | Grafana Datasource PluginName | +| monitoring.grafana.grafanaDashboard.enabled | bool | `false` | Create GrafanaDashboard custom resource referencing to the configMap. according to https://grafana-operator.github.io/grafana-operator/docs/examples/dashboard_from_configmap/readme/ | +| monitoring.grafana.grafanaDashboard.folder | string | `"kyverno"` | Dashboard folder | +| monitoring.grafana.grafanaDashboard.allowCrossNamespaceImport | bool | `true` | Allow cross Namespace import | +| monitoring.grafana.grafanaDashboard.matchLabels | object | `{"dashboards":"grafana"}` | Label match selector | +| monitoring.policyReportDetails.firstStatusRow.height | int | `8` | | +| monitoring.policyReportDetails.secondStatusRow.enabled | bool | `true` | | +| monitoring.policyReportDetails.secondStatusRow.height | int | `2` | | +| monitoring.policyReportDetails.statusTimeline.enabled | bool | `true` | | +| monitoring.policyReportDetails.statusTimeline.height | int | `8` | | +| monitoring.policyReportDetails.passTable.enabled | bool | `true` | | +| monitoring.policyReportDetails.passTable.height | int | `8` | | +| monitoring.policyReportDetails.failTable.enabled | bool | `true` | | +| monitoring.policyReportDetails.failTable.height | int | `8` | | +| monitoring.policyReportDetails.warningTable.enabled | bool | `true` | | +| monitoring.policyReportDetails.warningTable.height | int | `4` | | +| monitoring.policyReportDetails.errorTable.enabled | bool | `true` | | +| monitoring.policyReportDetails.errorTable.height | int | `4` | | +| monitoring.clusterPolicyReportDetails.statusRow.height | int | `6` | | +| monitoring.clusterPolicyReportDetails.statusTimeline.enabled | bool | `true` | | +| monitoring.clusterPolicyReportDetails.statusTimeline.height | int | `8` | | +| monitoring.clusterPolicyReportDetails.passTable.enabled | bool | `true` | | +| monitoring.clusterPolicyReportDetails.passTable.height | int | `8` | | +| monitoring.clusterPolicyReportDetails.failTable.enabled | bool | `true` | | +| monitoring.clusterPolicyReportDetails.failTable.height | int | `8` | | +| monitoring.clusterPolicyReportDetails.warningTable.enabled | bool | `true` | | +| monitoring.clusterPolicyReportDetails.warningTable.height | int | `4` | | +| monitoring.clusterPolicyReportDetails.errorTable.enabled | bool | `true` | | +| monitoring.clusterPolicyReportDetails.errorTable.height | int | `4` | | +| monitoring.policyReportOverview.failingSummaryRow.height | int | `8` | | +| monitoring.policyReportOverview.failingTimeline.height | int | `10` | | +| monitoring.policyReportOverview.failingPolicyRuleTable.height | int | `10` | | +| monitoring.policyReportOverview.failingClusterPolicyRuleTable.height | int | `10` | | +| extraManifests | list | `[]` | list of extra manifests | +| extraConfig | object | `{}` | Extra configuration options appended to core policy reporter | + +## Source Code + +* + +## Maintainers + +| Name | Email | Url | +| ---- | ------ | --- | +| Frank Jogeleit | | | +| Ammar Yasser | | | + +---------------------------------------------- +Autogenerated from chart metadata using [helm-docs v1.11.0](https://github.com/norwoodj/helm-docs/releases/v1.11.0) diff --git a/charts/policy-reporter/README.md.gotmpl b/charts/policy-reporter/README.md.gotmpl new file mode 100644 index 0000000000..86c13c7a28 --- /dev/null +++ b/charts/policy-reporter/README.md.gotmpl @@ -0,0 +1,50 @@ +{{ template "chart.header" . }} +{{ template "chart.deprecationWarning" . }} +{{ template "chart.description" . }} + +{{ template "chart.badgesSection" . }} + +## Documentation + +You can find detailed Information and Screens about Features and Configurations in the [Documentation](https://kyverno.github.io/policy-reporter-docs). + +## Installation with Helm v3 + +Installation via Helm Repository + +### Add the Helm repository +```bash +helm repo add policy-reporter https://kyverno.github.io/policy-reporter +helm repo update +``` + +### Basic Installation + +The basic installation provides an Prometheus Metrics Endpoint and different REST APIs, for more details have a look at the [Documentation](https://kyverno.github.io/policy-reporter/guide/02-getting-started). + +```bash +helm install policy-reporter policy-reporter/policy-reporter -n policy-reporter --create-namespace +``` + +## Policy Reporter UI + +You can use the Policy Reporter as standalone Application along with the optional UI SubChart. + +### Installation with Policy Reporter UI and Kyverno Plugin enabled + +```bash +helm install policy-reporter policy-reporter/policy-reporter --set plugin.kyverno.enabled=true --set ui.enabled=true -n policy-reporter --create-namespace +kubectl port-forward service/policy-reporter-ui 8082:8080 -n policy-reporter +``` +Open `http://localhost:8082/` in your browser. + + +{{ template "chart.valuesSection" . }} + +{{ template "chart.sourcesSection" . }} + +{{ template "chart.requirementsSection" . }} + +{{ template "chart.maintainersSection" . }} + +{{ template "helm-docs.versionFooter" . }} diff --git a/charts/policy-reporter/configs/core.tmpl b/charts/policy-reporter/configs/core.tmpl new file mode 100644 index 0000000000..647371e61e --- /dev/null +++ b/charts/policy-reporter/configs/core.tmpl @@ -0,0 +1,203 @@ +crd: + targetConfig: {{ .Values.target.crd }} + +target: + loki: + {{- include "target.loki" .Values.target.loki | nindent 4 }} + {{- if and .Values.target.loki .Values.target.loki.channels }} + channels: + {{- range .Values.target.loki.channels }} + - + {{- include "target.loki" . | nindent 8 }} + {{- end }} + {{- end }} + + elasticsearch: + {{- include "target.elasticsearch" .Values.target.elasticsearch | nindent 4 }} + {{- if and .Values.target.elasticsearch .Values.target.elasticsearch.channels }} + channels: + {{- range .Values.target.elasticsearch.channels }} + - + {{- include "target.elasticsearch" . | nindent 8 }} + {{- end }} + {{- end }} + + slack: + {{- include "target.slack" .Values.target.slack | nindent 4 }} + {{- if and .Values.target.slack .Values.target.slack.channels }} + channels: + {{- range .Values.target.slack.channels }} + - + {{- include "target.slack" . | nindent 8 }} + {{- end }} + {{- end }} + + discord: + {{- include "target.webhook" .Values.target.discord | nindent 4 }} + {{- if and .Values.target.discord .Values.target.discord.channels }} + channels: + {{- range .Values.target.discord.channels }} + - + {{- include "target.webhook" . | nindent 8 }} + {{- end }} + {{- end }} + + teams: + {{- include "target.webhook" .Values.target.teams | nindent 4 }} + {{- if and .Values.target.teams .Values.target.teams.channels }} + channels: + {{- range .Values.target.teams.channels }} + - + {{- include "target.webhook" . | nindent 8 }} + {{- end }} + {{- end }} + + webhook: + {{- include "target.webhook" .Values.target.webhook | nindent 4 }} + {{- if and .Values.target.webhook .Values.target.webhook.channels }} + channels: + {{- range .Values.target.webhook.channels }} + - + {{- include "target.webhook" . | nindent 8 }} + {{- end }} + {{- end }} + + telegram: + {{- include "target.telegram" .Values.target.telegram | nindent 4 }} + {{- if and .Values.target.telegram .Values.target.telegram.channels }} + channels: + {{- range .Values.target.telegram.channels }} + - + {{- include "target.telegram" . | nindent 8 }} + {{- end }} + {{- end }} + + googleChat: + {{- include "target.webhook" .Values.target.googleChat | nindent 4 }} + {{- if and .Values.target.webhook .Values.target.googleChat.channels }} + channels: + {{- range .Values.target.googleChat.channels }} + - + {{- include "target.webhook" . | nindent 8 }} + {{- end }} + {{- end }} + + jira: + {{- include "target.jira" .Values.target.jira | nindent 4 }} + {{- if and .Values.target.jira .Values.target.jira.channels }} + channels: + {{- range .Values.target.jira.channels }} + - + {{- include "target.jira" . | nindent 8 }} + {{- end }} + {{- end }} + + alertManager: + {{- include "target.alertManager" .Values.target.alertManager | nindent 4 }} + {{- if and .Values.target.alertManager .Values.target.alertManager.channels }} + channels: + {{- range .Values.target.alertManager.channels }} + - + {{- include "target.alertManager" . | nindent 8 }} + {{- end }} + {{- end }} + + s3: + {{- include "target.s3" .Values.target.s3 | nindent 4 }} + {{- if and .Values.target.s3 .Values.target.s3.channels }} + channels: + {{- range .Values.target.s3.channels }} + - + {{- include "target.s3" . | nindent 8 }} + {{- end }} + {{- end }} + + kinesis: + {{- include "target.kinesis" .Values.target.kinesis | nindent 4 }} + {{- if and .Values.target.kinesis .Values.target.kinesis.channels }} + channels: + {{- range .Values.target.kinesis.channels }} + - + {{- include "target.kinesis" . | nindent 8 }} + {{- end }} + {{- end }} + + securityHub: + {{- include "target.securityhub" .Values.target.securityHub | nindent 4 }} + {{- if and .Values.target.securityHub .Values.target.securityHub.channels }} + channels: + {{- range .Values.target.securityHub.channels }} + - + {{- include "target.securityhub" . | nindent 8 }} + {{- end }} + {{- end }} + + gcs: + {{- include "target.gcs" .Values.target.gcs | nindent 4 }} + {{- if and .Values.target.gcs .Values.target.gcs.channels }} + channels: + {{- range .Values.target.gcs.channels }} + - + {{- include "target.gcs" . | nindent 8 }} + {{- end }} + {{- end }} + +worker: {{ .Values.worker }} + +{{- with .Values.metrics }} +metrics: + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- with .Values.reportFilter }} +reportFilter: + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- with .Values.sourceFilters }} +sourceFilters: + {{- toYaml . | nindent 2 }} +{{- end }} + +leaderElection: + enabled: {{ gt (int .Values.replicaCount) 1 }} + releaseOnCancel: {{ .Values.leaderElection.releaseOnCancel }} + leaseDuration: {{ .Values.leaderElection.leaseDuration }} + renewDeadline: {{ .Values.leaderElection.renewDeadline }} + retryPeriod: {{ .Values.leaderElection.retryPeriod }} + +{{- with .Values.redis }} +redis: + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- with .Values.sourceConfig }} +sourceConfig: + {{- toYaml . | nindent 2 }} +{{- end }} + +logging: + server: {{ .Values.logging.server }} + encoding: {{ .Values.logging.encoding }} + logLevel: {{ include "policyreporter.logLevel" . }} + +api: + basicAuth: + username: {{ .Values.basicAuth.username }} + password: {{ .Values.basicAuth.password }} + secretRef: {{ .Values.basicAuth.secretRef }} + +database: + type: {{ .Values.database.type }} + database: {{ .Values.database.database }} + username: {{ .Values.database.username }} + password: {{ .Values.database.password }} + host: {{ .Values.database.host }} + enableSSL: {{ .Values.database.enableSSL }} + dsn: {{ .Values.database.dsn }} + secretRef: {{ .Values.database.secretRef }} + mountedSecret: {{ .Values.database.mountedSecret }} + +{{- with .Values.extraConfig }} +{{- toYaml . | nindent 0 }} +{{- end }} diff --git a/charts/policy-reporter/configs/email-reports.tmpl b/charts/policy-reporter/configs/email-reports.tmpl new file mode 100644 index 0000000000..42136f77f4 --- /dev/null +++ b/charts/policy-reporter/configs/email-reports.tmpl @@ -0,0 +1,35 @@ +emailReports: + clusterName: {{ .Values.emailReports.clusterName }} + titlePrefix: {{ .Values.emailReports.titlePrefix }} + {{- with .Values.emailReports.smtp }} + smtp: + {{- toYaml . | nindent 4 }} + {{- end }} + + summary: + {{- with .Values.emailReports.summary.to }} + to: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.emailReports.summary.filter }} + filter: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.emailReports.summary.channels }} + channels: + {{- toYaml . | nindent 6 }} + {{- end }} + + violations: + {{- with .Values.emailReports.violations.to }} + to: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.emailReports.violations.filter }} + filter: + {{- toYaml . | nindent 6 }} + {{- end }} + {{- with .Values.emailReports.violations.channels }} + channels: + {{- toYaml . | nindent 6 }} + {{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/configs/kyverno-plugin.tmpl b/charts/policy-reporter/configs/kyverno-plugin.tmpl new file mode 100644 index 0000000000..46a31d366a --- /dev/null +++ b/charts/policy-reporter/configs/kyverno-plugin.tmpl @@ -0,0 +1,31 @@ +leaderElection: + enabled: {{ gt (int .Values.plugin.kyverno.replicaCount) 1 }} + releaseOnCancel: {{ .Values.plugin.kyverno.leaderElection.releaseOnCancel }} + leaseDuration: {{ .Values.plugin.kyverno.leaderElection.leaseDuration }} + renewDeadline: {{ .Values.plugin.kyverno.leaderElection.renewDeadline }} + retryPeriod: {{ .Values.plugin.kyverno.leaderElection.retryPeriod }} + lockName: {{ .Values.plugin.kyverno.leaderElection.lockName }} + +logging: + api: {{ .Values.plugin.kyverno.logging.api }} + server: {{ .Values.plugin.kyverno.logging.server }} + encoding: {{ .Values.plugin.kyverno.logging.encoding }} + logLevel: {{ .Values.plugin.kyverno.logging.logLevel }} + +server: + basicAuth: + username: {{ .Values.basicAuth.username }} + password: {{ .Values.basicAuth.password }} + secretRef: {{ .Values.basicAuth.secretRef }} + +core: + host: {{ printf "http://%s:%d" (include "policyreporter.fullname" .) (.Values.service.port | int) }} + +{{- with .Values.plugin.kyverno.blockReports }} +blockReports: + {{- toYaml . | nindent 4 }} +{{- end }} + +{{- with .Values.plugin.kyverno.extraConfig }} +{{- toYaml . | nindent 0 }} +{{- end }} diff --git a/charts/policy-reporter/configs/trivy-plugin.tmpl b/charts/policy-reporter/configs/trivy-plugin.tmpl new file mode 100644 index 0000000000..ae757973c0 --- /dev/null +++ b/charts/policy-reporter/configs/trivy-plugin.tmpl @@ -0,0 +1,33 @@ +logging: + api: {{ .Values.plugin.trivy.logging.api }} + server: {{ .Values.plugin.trivy.logging.server }} + encoding: {{ .Values.plugin.trivy.logging.encoding }} + logLevel: {{ .Values.plugin.trivy.logging.logLevel }} + +server: + basicAuth: + username: {{ .Values.basicAuth.username }} + password: {{ .Values.basicAuth.password }} + secretRef: {{ .Values.basicAuth.secretRef }} + +core: + host: {{ printf "http://%s:%d" (include "policyreporter.fullname" .) (.Values.service.port | int) }} + skipTLS: {{ .Values.plugin.trivy.policyReporter.skipTLS }} + certificate: {{ .Values.plugin.trivy.policyReporter.certificate }} + secretRef: {{ .Values.plugin.trivy.policyReporter.secretRef }} + basicAuth: + username: {{ .Values.basicAuth.username }} + password: {{ .Values.basicAuth.password }} + +trivy: + dbDir: /db + api: + disable: {{ .Values.plugin.trivy.cveawg.disable }} + +github: + token: {{ .Values.plugin.trivy.github.token | quote }} + disable: {{ .Values.plugin.trivy.github.disable }} + +{{- with .Values.plugin.trivy.extraConfig }} +{{- toYaml . | nindent 0 }} +{{- end }} diff --git a/charts/policy-reporter/configs/ui.tmpl b/charts/policy-reporter/configs/ui.tmpl new file mode 100644 index 0000000000..36c2297007 --- /dev/null +++ b/charts/policy-reporter/configs/ui.tmpl @@ -0,0 +1,116 @@ +logging: + api: {{ .Values.ui.logging.api }} + server: {{ .Values.ui.logging.server }} + encoding: {{ .Values.ui.logging.encoding }} + logLevel: {{ .Values.ui.logging.logLevel }} + +server: + port: {{ .Values.ui.server.port }} + cors: {{ .Values.ui.server.cors }} + overwriteHost: {{ .Values.ui.server.overwriteHost }} + {{- with .Values.ui.server.sessions }} + sessions: + {{- toYaml . | nindent 4 }} + {{- end }} + +ui: + displayMode: {{ .Values.ui.displayMode }} + banner: {{ .Values.ui.banner }} + logo: + path: {{ .Values.ui.logo.path }} + disabled: {{ .Values.ui.logo.disabled }} + +{{- $default := false -}} +{{- range .Values.ui.clusters }} + {{- if eq .name $.Values.ui.name -}} + {{- $default = true -}} + {{- end -}} +{{- end }} + +clusters: +{{- if not $default }} + - name: {{ .Values.ui.name }} + secretRef: {{ include "ui.fullname" . }}-default-cluster +{{- end }} +{{- with .Values.ui.clusters }} + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- with .Values.ui.customBoards }} +customBoards: + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- with .Values.ui.boards }} +boards: + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- $kyverno := false -}} +{{- range .Values.ui.sources }} + {{- if eq .name "kyverno" -}} + {{- $kyverno = true -}} + {{- end -}} +{{- end }} + +{{- $vpol := false -}} +{{- range .Values.ui.sources }} + {{- if eq .name "KyvernoValidatingPolicy" -}} + {{- $vpol = true -}} + {{- end -}} +{{- end }} + +{{- $trivy := false -}} +{{- range .Values.ui.sources }} + {{- if eq .name "Trivy Vulnerability" -}} + {{- $trivy = true -}} + {{- end -}} +{{- end }} + +sources: +{{- if not $kyverno }} + - name: kyverno + type: result + exceptions: false + excludes: + results: + - warn + - error +{{- end }} + +{{- if not $vpol }} + - name: KyvernoValidatingPolicy + type: result + exceptions: false + excludes: + results: + - warn + - error +{{- end }} + +{{- if and (not $trivy) .Values.plugin.trivy.enabled }} + - name: Trivy Vulnerability + type: severity + exceptions: false + excludes: + results: + - pass + - skip +{{- end }} +{{- with .Values.ui.sources }} + {{- toYaml . | nindent 2 }} +{{- end }} + +{{- with .Values.ui.openIDConnect }} +openIDConnect: + {{- toYaml . | nindent 4 }} +{{- end }} + +{{- with .Values.ui.oauth }} +oauth: + {{- toYaml . | nindent 4 }} +{{- end }} + +{{- with .Values.ui.extraConfig }} +{{- toYaml . | nindent 0 }} +{{- end }} diff --git a/charts/policy-reporter/templates/_helpers.tpl b/charts/policy-reporter/templates/_helpers.tpl new file mode 100644 index 0000000000..f509872d4a --- /dev/null +++ b/charts/policy-reporter/templates/_helpers.tpl @@ -0,0 +1,315 @@ +{{- define "policyreporter.name" -}} +{{- "policy-reporter" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "policyreporter.fullname" -}} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride }} +{{- else if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "policyreporter.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "policyreporter.labels" -}} +{{ include "policyreporter.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/component: reporting +app.kubernetes.io/part-of: policy-reporter +{{- if not .Values.static }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ include "policyreporter.chart" . }} +{{- end }} +{{- with .Values.global.labels }} +{{ toYaml . }} +{{- end -}} +{{- end }} + +{{/* +Pod labels +*/}} +{{- define "policyreporter.podLabels" -}} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +app.kubernetes.io/part-of: policy-reporter +{{- if not .Values.static }} +helm.sh/chart: {{ include "policyreporter.chart" . }} +{{- end }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "policyreporter.selectorLabels" -}} +app.kubernetes.io/name: policy-reporter +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "policyreporter.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "policyreporter.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + +{{/* +Create UI target host based on configuration +*/}} +{{- define "policyreporter.uihost" -}} +{{ if .Values.target.ui.host }} +{{- .Values.target.ui.host }} +{{- else if not .Values.ui.enabled }} +{{- "" }} +{{- else }} +{{- "" }} +{{- end }} +{{- end }} + +{{- define "policyreporter.securityContext" -}} +{{- if semverCompare "<1.19" .Capabilities.KubeVersion.Version }} +{{- toYaml (omit .Values.securityContext "seccompProfile") }} +{{- else }} +{{- toYaml .Values.securityContext }} +{{- end }} +{{- end }} + +{{- define "policyreporter.podDisruptionBudget" -}} +{{- if and .Values.podDisruptionBudget.minAvailable .Values.podDisruptionBudget.maxUnavailable }} +{{- fail "Cannot set both minAvailable and maxUnavailable" -}} +{{- end }} +{{- if not .Values.podDisruptionBudget.maxUnavailable }} +minAvailable: {{ default 1 .Values.podDisruptionBudget.minAvailable }} +{{- end }} +{{- if .Values.podDisruptionBudget.maxUnavailable }} +maxUnavailable: {{ .Values.podDisruptionBudget.maxUnavailable }} +{{- end }} +{{- end }} + +{{/* Get the namespace name. */}} +{{- define "policyreporter.namespace" -}} +{{- if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} +{{- else -}} + {{- .Release.Namespace -}} +{{- end -}} +{{- end -}} + +{{/* Get the namespace name for grafana. */}} +{{- define "grafana.namespace" -}} +{{- if .Values.monitoring.grafana.namespace -}} + {{- .Values.monitoring.grafana.namespace -}} +{{- else -}} + {{- include "policyreporter.namespace" . -}} +{{- end -}} +{{- end -}} + +{{/* Get the namespace name. */}} +{{- define "policyreporter.logLevel" -}} +{{- if .Values.logging.server -}} +-1 +{{- else -}} +{{- .Values.logging.logLevel -}} +{{- end -}} +{{- end -}} + +{{- define "target" -}} +name: {{ .name | quote }} +secretRef: {{ .secretRef | quote }} +mountedSecret: {{ .mountedSecret | quote }} +minimumSeverity: {{ .minimumSeverity | quote }} +skipExistingOnStartup: {{ .skipExistingOnStartup }} +{{- with .customFields }} +customFields: +{{- toYaml . | nindent 2 }} +{{- end }} +{{- with .sources }} +sources: +{{- toYaml . | nindent 2 }} +{{- end }} +{{- with .filter }} +filter: +{{- toYaml . | nindent 2 }} +{{- end }} +{{- end }} + +{{- define "target.loki" -}} +config: + host: {{ .host | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + path: {{ .path | quote }} + {{- with .headers }} + headers: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.elasticsearch" -}} +config: + host: {{ .host | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + username: {{ .username | quote }} + password: {{ .password | quote }} + apiKey: {{ .apiKey | quote }} + index: {{ .index| quote }} + rotation: {{ .rotation | quote }} + typelessApi: {{ .typelessApi | quote }} + {{- with .headers }} + headers: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.slack" -}} +config: + webhook: {{ .webhook | quote }} + channel: {{ .channel | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + {{- with .headers }} + headers: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.webhook" -}} +config: + webhook: {{ .webhook | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + {{- if .keepalive }} + keepalive: + interval: {{ .keepalive.interval | quote }} + {{- if .keepalive.params }} + params: + {{- toYaml .keepalive.params | nindent 6 }} + {{- end }} + {{- end }} + {{- with .headers }} + headers: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.jira" -}} +config: + host: {{ .host | quote }} + username: {{ .username | quote }} + password: {{ .password | quote }} + apiToken: {{ .apiToken | quote }} + apiVersion: {{ .apiVersion | quote }} + summaryTemplate: {{ .summaryTemplate | quote }} + projectKey: {{ .projectKey | quote }} + issueType: {{ .issueType | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + {{- with .labels }} + labels: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .components }} + components: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.alertManager" -}} +config: + host: {{ .host | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + {{- with .headers }} + headers: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.telegram" -}} +config: + chatId: {{ .chatId | quote }} + token: {{ .token | quote }} + webhook: {{ .webhook | quote }} + certificate: {{ .certificate | quote }} + skipTLS: {{ .skipTLS }} + {{- with .headers }} + headers: + {{- toYaml . | nindent 4 }} + {{- end }} +{{ include "target" . }} +{{- end }} + +{{- define "target.s3" -}} +config: + accessKeyId: {{ .accessKeyId }} + secretAccessKey: {{ .secretAccessKey }} + region: {{ .region }} + endpoint: {{ .endpoint }} + bucket: {{ .bucket }} + bucketKeyEnabled: {{ .bucketKeyEnabled }} + kmsKeyId: {{ .kmsKeyId }} + serverSideEncryption: {{ .serverSideEncryption }} + pathStyle: {{ .pathStyle }} + prefix: {{ .prefix }} +{{ include "target" . }} +{{- end }} + +{{- define "target.kinesis" -}} +config: + accessKeyId: {{ .accessKeyId }} + secretAccessKey: {{ .secretAccessKey }} + region: {{ .region }} + endpoint: {{ .endpoint }} + streamName: {{ .streamName }} +{{ include "target" . }} +{{- end }} + +{{- define "target.securityhub" -}} +config: + accessKeyId: {{ .accessKeyId | quote }} + secretAccessKey: {{ .secretAccessKey | quote }} + region: {{ .region }} + endpoint: {{ .endpoint }} + accountId: {{ .accountId | quote }} + productName: {{ .productName }} + companyName: {{ .companyName }} + delayInSeconds: {{ .delayInSeconds }} + synchronize: {{ .synchronize }} +{{ include "target" . }} +{{- end }} + +{{- define "target.gcs" -}} +config: + credentials: {{ .credentials }} + bucket: {{ .bucket }} + prefix: {{ .prefix }} +{{ include "target" . }} +{{- end }} diff --git a/charts/policy-reporter/templates/cluster-secret.yaml b/charts/policy-reporter/templates/cluster-secret.yaml new file mode 100644 index 0000000000..a0264a6b3b --- /dev/null +++ b/charts/policy-reporter/templates/cluster-secret.yaml @@ -0,0 +1,36 @@ +{{- if .Values.ui.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "ui.fullname" . }}-default-cluster + namespace: {{ include "policyreporter.namespace" . }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} +type: Opaque +data: + {{- $username := .Values.basicAuth.username }} + {{- $password := .Values.basicAuth.password }} + {{- $secretRef := .Values.basicAuth.secretRef }} + host: {{ printf "http://%s:%d" (include "policyreporter.fullname" .) (.Values.service.port | int) | b64enc }} + {{- if $username }} + username: {{ $username | b64enc }} + {{- end }} + {{- if $password }} + password: {{ $password | b64enc }} + {{- end }} + {{- if $secretRef }} + secretRef: {{ $secretRef | b64enc }} + {{- end }} + {{- if .Values.plugin.kyverno.enabled }} + {{- $host := printf "http://%s:%d" (include "kyverno-plugin.fullname" .) (.Values.plugin.kyverno.service.port | int) }} + plugin.kyverno: {{ (printf "{\"host\":\"%s\", \"name\":\"kyverno\", \"username\":\"%s\", \"password\":\"%s\"}" $host $username $password) | b64enc }} + {{- end }} + {{- if .Values.plugin.trivy.enabled }} + {{- $host := printf "http://%s:%d/vulnr" (include "trivy-plugin.fullname" .) (.Values.plugin.trivy.service.port | int) }} + plugin.trivy: {{ (printf "{\"host\":\"%s\", \"name\":\"Trivy Vulnerability\", \"username\":\"%s\", \"password\":\"%s\"}" $host $username $password) | b64enc }} + {{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/clusterrole.yaml b/charts/policy-reporter/templates/clusterrole.yaml new file mode 100644 index 0000000000..555b1cfef9 --- /dev/null +++ b/charts/policy-reporter/templates/clusterrole.yaml @@ -0,0 +1,62 @@ +{{- if .Values.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + {{- include "policyreporter.labels" . | nindent 4 }} + name: {{ include "policyreporter.fullname" . }} +rules: +- apiGroups: + - 'openreports.io' + resources: + - reports + - reports/status + - clusterreports + - clusterreports/status + verbs: + - get + - list + - watch +- apiGroups: + - '*' + resources: + - policyreports + - policyreports/status + - clusterpolicyreports + - clusterpolicyreports/status + verbs: + - get + - list + - watch +- apiGroups: + - '' + resources: + - namespaces + verbs: + - list +- apiGroups: + - policyreporter.kyverno.io + resources: + - targetconfigs + verbs: + - get + - list + - watch +- apiGroups: + - '' + resources: + - pods + verbs: + - get +- apiGroups: + - 'batch' + resources: + - jobs + verbs: + - get +{{- end -}} diff --git a/charts/policy-reporter/templates/clusterrolebinding.yaml b/charts/policy-reporter/templates/clusterrolebinding.yaml new file mode 100644 index 0000000000..873a6032a0 --- /dev/null +++ b/charts/policy-reporter/templates/clusterrolebinding.yaml @@ -0,0 +1,20 @@ +{{- if .Values.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "policyreporter.fullname" . }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} +roleRef: + kind: ClusterRole + name: {{ include "policyreporter.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "policyreporter.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end -}} diff --git a/charts/policy-reporter/templates/config-email-reports-secret.yaml b/charts/policy-reporter/templates/config-email-reports-secret.yaml new file mode 100644 index 0000000000..9fd7947fdb --- /dev/null +++ b/charts/policy-reporter/templates/config-email-reports-secret.yaml @@ -0,0 +1,16 @@ +{{- if or .Values.emailReports.summary.enabled .Values.emailReports.violations.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "policyreporter.fullname" . }}-config-email-reports + namespace: {{ include "policyreporter.namespace" . }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} +type: Opaque +data: + config.yaml: {{ tpl (.Files.Get "configs/email-reports.tmpl") . | b64enc }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/config-secret.yaml b/charts/policy-reporter/templates/config-secret.yaml new file mode 100644 index 0000000000..37a979296e --- /dev/null +++ b/charts/policy-reporter/templates/config-secret.yaml @@ -0,0 +1,16 @@ +{{- if not .Values.existingTargetConfig.enabled }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "policyreporter.fullname" . }}-config + namespace: {{ include "policyreporter.namespace" . }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} +type: Opaque +data: + config.yaml: {{ tpl (.Files.Get "configs/core.tmpl") . | b64enc }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/cronjob-summary-report.yaml b/charts/policy-reporter/templates/cronjob-summary-report.yaml new file mode 100644 index 0000000000..cfec66e640 --- /dev/null +++ b/charts/policy-reporter/templates/cronjob-summary-report.yaml @@ -0,0 +1,136 @@ +{{- if .Values.emailReports.summary.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "policyreporter.fullname" . }}-summary-report + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} +spec: + schedule: {{ .Values.emailReports.summary.schedule | quote }} + jobTemplate: + spec: + activeDeadlineSeconds: {{ .Values.emailReports.summary.activeDeadlineSeconds }} + backoffLimit: {{ .Values.emailReports.summary.backoffLimit }} + {{- if gt (.Values.emailReports.summary.ttlSecondsAfterFinished | toString | atoi) 0 }} + ttlSecondsAfterFinished: {{ .Values.emailReports.summary.ttlSecondsAfterFinished }} + {{- end }} + template: + metadata: + labels: + {{- include "policyreporter.selectorLabels" . | nindent 12 }} + {{- include "policyreporter.podLabels" . | nindent 12 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.global.labels }} + {{- toYaml . | nindent 12 }} + {{- end }} + annotations: + checksum/secret: {{ include (print .Template.BasePath "/config-email-reports-secret.yaml") . | sha256sum | quote }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 12 }} + {{- end }} + serviceAccountName: {{ include "policyreporter.serviceAccountName" . }} + automountServiceAccountToken: true + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 12 }} + {{- end }} + restartPolicy: {{ .Values.emailReports.summary.restartPolicy }} + containers: + - name: policy-reporter + image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.securityContext }} + securityContext: {{ include "policyreporter.securityContext" . | nindent 16 }} + {{- end }} + command: + - /app/policyreporter + - send + - summary + args: + - --config=/app/config.yaml + - --template-dir=/app/templates + volumeMounts: + - name: config-file + mountPath: /app/config.yaml + subPath: config.yaml + readOnly: true + {{- with .Values.extraVolumes.volumeMounts }} + {{ toYaml . | nindent 14 | trim }} + {{- end }} + {{- if .Values.emailReports.smtp.secret }} + env: + - name: EMAIL_REPORTS_SMTP_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: host + optional: true + - name: EMAIL_REPORTS_SMTP_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: port + optional: true + - name: EMAIL_REPORTS_SMTP_USERNAME + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: username + optional: true + - name: EMAIL_REPORTS_SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: password + optional: true + - name: EMAIL_REPORTS_SMTP_FROM + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: from + optional: true + - name: EMAIL_REPORTS_SMTP_ENCRYPTION + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: encryption + optional: true + {{- end }} + resources: + {{- toYaml .Values.emailReports.resources | nindent 16 }} + volumes: + - name: config-file + secret: + secretName: {{ include "policyreporter.fullname" . }}-config-email-reports + optional: true + {{- with .Values.extraVolumes.volumes }} + {{ toYaml . | nindent 10 | trim }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 12 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/cronjob-violations-report.yaml b/charts/policy-reporter/templates/cronjob-violations-report.yaml new file mode 100644 index 0000000000..656d0c853b --- /dev/null +++ b/charts/policy-reporter/templates/cronjob-violations-report.yaml @@ -0,0 +1,136 @@ +{{- if .Values.emailReports.violations.enabled }} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: {{ include "policyreporter.fullname" . }}-violations-report + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} +spec: + schedule: {{ .Values.emailReports.violations.schedule | quote }} + jobTemplate: + spec: + activeDeadlineSeconds: {{ .Values.emailReports.violations.activeDeadlineSeconds }} + backoffLimit: {{ .Values.emailReports.violations.backoffLimit }} + {{- if gt (.Values.emailReports.violations.ttlSecondsAfterFinished | toString | atoi) 0 }} + ttlSecondsAfterFinished: {{ .Values.emailReports.violations.ttlSecondsAfterFinished }} + {{- end }} + template: + metadata: + labels: + {{- include "policyreporter.selectorLabels" . | nindent 12 }} + {{- include "policyreporter.podLabels" . | nindent 12 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.global.labels }} + {{- toYaml . | nindent 12 }} + {{- end }} + annotations: + checksum/secret: {{ include (print .Template.BasePath "/config-email-reports-secret.yaml") . | sha256sum | quote }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 12 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 12 }} + {{- end }} + serviceAccountName: {{ include "policyreporter.serviceAccountName" . }} + automountServiceAccountToken: true + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 12 }} + {{- end }} + restartPolicy: {{ .Values.emailReports.violations.restartPolicy }} + containers: + - name: policy-reporter + image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.securityContext }} + securityContext: {{ include "policyreporter.securityContext" . | nindent 16 }} + {{- end }} + command: + - /app/policyreporter + - send + - violations + args: + - --config=/app/config.yaml + - --template-dir=/app/templates + volumeMounts: + - name: config-file + mountPath: /app/config.yaml + subPath: config.yaml + readOnly: true + {{- with .Values.extraVolumes.volumeMounts }} + {{ toYaml . | nindent 14 | trim }} + {{- end }} + {{- if .Values.emailReports.smtp.secret }} + env: + - name: EMAIL_REPORTS_SMTP_HOST + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: host + optional: true + - name: EMAIL_REPORTS_SMTP_PORT + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: port + optional: true + - name: EMAIL_REPORTS_SMTP_USERNAME + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: username + optional: true + - name: EMAIL_REPORTS_SMTP_PASSWORD + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: password + optional: true + - name: EMAIL_REPORTS_SMTP_FROM + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: from + optional: true + - name: EMAIL_REPORTS_SMTP_ENCRYPTION + valueFrom: + secretKeyRef: + name: {{ .Values.emailReports.smtp.secret }} + key: encryption + optional: true + {{- end }} + resources: + {{- toYaml .Values.emailReports.resources | nindent 16 }} + volumes: + - name: config-file + secret: + secretName: {{ include "policyreporter.fullname" . }}-config-email-reports + optional: true + {{- with .Values.extraVolumes.volumes }} + {{ toYaml . | nindent 10 | trim }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 12 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/deployment.yaml b/charts/policy-reporter/templates/deployment.yaml new file mode 100644 index 0000000000..5ff16bf8c9 --- /dev/null +++ b/charts/policy-reporter/templates/deployment.yaml @@ -0,0 +1,150 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "policyreporter.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} +spec: + replicas: {{ .Values.replicaCount }} + revisionHistoryLimit: {{ .Values.revisionHistoryLimit }} + {{- with .Values.plugin.kyverno.updateStrategy }} + strategy: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "policyreporter.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "policyreporter.selectorLabels" . | nindent 8 }} + {{- include "policyreporter.podLabels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.global.labels }} + {{- toYaml . | nindent 8 }} + {{- end }} + annotations: + checksum/secret: {{ include (print .Template.BasePath "/config-secret.yaml") . | sha256sum | quote }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "policyreporter.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.serviceAccount.automount }} + {{- if .Values.podSecurityContext }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + {{- end }} + containers: + - name: policy-reporter + image: "{{ .Values.image.registry }}/{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.securityContext }} + securityContext: {{- include "policyreporter.securityContext" . | nindent 12 }} + {{- end }} + args: + - --port={{ .Values.port.number }} + - --config=/app/config.yaml + - --dbfile=/sqlite/database.db + - --metrics-enabled={{ or .Values.metrics.enabled .Values.monitoring.enabled }} + - --rest-enabled={{ or .Values.rest.enabled .Values.ui.enabled }} + - --profile={{ .Values.profiling.enabled }} + - --lease-name={{ include "policyreporter.fullname" . }} + - --template-dir=/app/templates + ports: + - name: {{ .Values.port.name }} + containerPort: {{ .Values.port.number }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + volumeMounts: + - name: sqlite + mountPath: /sqlite + - name: config-file + mountPath: /app/config.yaml + {{- if and .Values.existingTargetConfig.enabled .Values.existingTargetConfig.subPath }} + subPath: {{ .Values.existingTargetConfig.subPath }} + {{- else }} + subPath: config.yaml + {{- end }} + readOnly: true + - name: tmp + mountPath: /tmp + {{- with .Values.extraVolumes.volumeMounts }} + {{ toYaml . | nindent 10 | trim }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if gt (int .Values.replicaCount) 1 }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- end }} + {{- with .Values.envVars }} + {{- . | toYaml | trim | nindent 10 }} + {{- end }} + volumes: + - name: sqlite + {{- if .Values.sqliteVolume }} + {{- toYaml .Values.sqliteVolume | nindent 8 }} + {{- else }} + emptyDir: {} + {{- end }} + - name: config-file + secret: + {{- if and .Values.existingTargetConfig.enabled .Values.existingTargetConfig.name }} + secretName: {{ .Values.existingTargetConfig.name }} + {{- else }} + secretName: {{ include "policyreporter.fullname" . }}-config + {{- end }} + optional: true + - name: tmp + {{- if .Values.tmpVolume }} + {{- toYaml .Values.tmpVolume | nindent 8 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- with .Values.extraVolumes.volumes }} + {{ toYaml . | nindent 6 | trim }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/policy-reporter/templates/extra-manifests.yaml b/charts/policy-reporter/templates/extra-manifests.yaml new file mode 100644 index 0000000000..9059d7d09f --- /dev/null +++ b/charts/policy-reporter/templates/extra-manifests.yaml @@ -0,0 +1,4 @@ +{{ range .Values.extraManifests }} +--- +{{ tpl . $ }} +{{ end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ingress.yaml b/charts/policy-reporter/templates/ingress.yaml new file mode 100644 index 0000000000..ac16cd5b29 --- /dev/null +++ b/charts/policy-reporter/templates/ingress.yaml @@ -0,0 +1,66 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "policyreporter.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- if .Values.ingress.labels }} + {{- with .Values.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} + {{- if or .Values.annotations .Values.ingress.annotations }} + annotations: + {{- with .Values.ingress.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- toYaml .Values.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/_helpers.tpl b/charts/policy-reporter/templates/monitoring/_helpers.tpl new file mode 100644 index 0000000000..1dfa881315 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/_helpers.tpl @@ -0,0 +1,58 @@ +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "monitoring.fullname" -}} +{{ template "policyreporter.fullname" . }}-monitoring +{{- end }} + +{{- define "monitoring.name" -}} +{{ template "policyreporter.name" . }}-monitoring +{{- end }} + + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "monitoring.chart" -}} +{{ template "policyreporter.chart" . }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "monitoring.labels" -}} +{{ include "monitoring.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/component: monitoring +app.kubernetes.io/part-of: kyverno +{{- if not .Values.static }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ include "monitoring.chart" . }} +{{- end }} +{{- with .Values.global.labels }} +{{ toYaml . }} +{{- end -}} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "monitoring.selectorLabels" -}} +app.kubernetes.io/name: {{ include "monitoring.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* Get the namespace name. */}} +{{- define "monitoring.smNamespace" -}} +{{- if .Values.monitoring.serviceMonitor.namespace -}} +{{- .Values.monitoring.serviceMonitor.namespace -}} +{{- else if .Values.namespaceOverride -}} + {{- .Values.namespaceOverride -}} +{{- else -}} +{{- .Release.Namespace -}} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/auth-secret.yaml b/charts/policy-reporter/templates/monitoring/auth-secret.yaml new file mode 100644 index 0000000000..c9b72db17a --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/auth-secret.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.monitoring.enabled }} +{{- if and .Values.basicAuth.username .Values.basicAuth.password }} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "monitoring.fullname" . }}-auth + namespace: {{ include "monitoring.smNamespace" . }} + {{- if .Values.monitoring.annotations }} + annotations: + {{- toYaml .Values.monitoring.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "monitoring.labels" . | nindent 4 }} +type: Opaque +data: + username: {{ .Values.basicAuth.username | b64enc }} + password: {{ .Values.basicAuth.password | b64enc }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/monitoring/clusterpolicy-details.dashboard.yaml b/charts/policy-reporter/templates/monitoring/clusterpolicy-details.dashboard.yaml new file mode 100644 index 0000000000..81c1f37187 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/clusterpolicy-details.dashboard.yaml @@ -0,0 +1,936 @@ +{{- if and .Values.monitoring.enabled }} +{{ $root := .Values.monitoring }} + +{{- if and $root.grafana.dashboards.enabled $root.grafana.dashboards.enable.clusterPolicyReportDetails }} +{{- $filters := $root.grafana.dashboards.labelFilter }} +{{- if and $root.grafana.dashboards.multicluster.enabled $root.grafana.dashboards.multicluster.label }} +{{- $filters = append $filters $root.grafana.dashboards.multicluster.label }} +{{- end }} + +{{- $nsLabel := "exported_namespace" }} +{{- if $root.serviceMonitor.honorLabels }} +{{- $nsLabel = "namespace" }} +{{- end }} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "monitoring.fullname" . }}-clusterpolicy-details-dashboard + namespace: {{ include "grafana.namespace" . }} + annotations: + {{ $root.grafana.folder.annotation }}: {{ $root.grafana.folder.name }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{ $root.grafana.dashboards.label }}: {{ $root.grafana.dashboards.value | quote }} + {{- include "monitoring.labels" . | nindent 4 }} +data: + cluster-policy-reporter-details-dashboard.json: | + { + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "{{ $root.grafana.datasource.label }}", + "description": "", + "type": "datasource", + "pluginId": "{{ $root.grafana.datasource.pluginId }}", + "pluginName": "{{ $root.grafana.datasource.pluginName }}" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.1.5" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "panel", + "id": "stat", + "name": "Stat", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.statusRow.height }}, + "w": 6, + "x": 0, + "y": 0 + }, + "id": 3, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"pass\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod))", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Pass Status", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.statusRow.height }}, + "w": 6, + "x": 6, + "y": 0 + }, + "id": 4, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"warn\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod))", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Warning Status", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.statusRow.height }}, + "w": 6, + "x": 12, + "y": 0 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"fail\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod))", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Fail Status", + "type": "stat" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.statusRow.height }}, + "w": 6, + "x": 18, + "y": 0 + }, + "id": 6, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "auto", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod))", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Error Status", + "type": "stat" + } +{{- if $root.clusterPolicyReportDetails.statusTimeline.enabled }} + ,{ + "datasource": { + "uid": "${DS_PROMETHEUS}", + "type": "prometheus" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 1, + "fillOpacity": 10, + "gradientMode": "none", + "spanNulls": false, + "insertNulls": false, + "showPoints": "never", + "pointSize": 5, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "axisColorMode": "text", + "axisBorderShow": false, + "scaleDistribution": { + "type": "linear" + }, + "axisCenteredZero": false, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "unit": "none", + "decimals": 0, + "min": 0 + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "reducer": "allIsZero", + "op": "gte", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "tooltip": true, + "viz": false, + "legend": true + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "reducer": "allIsNull", + "op": "gte", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "tooltip": true, + "viz": false, + "legend": true + } + } + ] + } + ] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.statusTimeline.height }}, + "w": 24, + "x": 0, + "y": 6 + }, + "id": 13, + "pluginVersion": "10.4.1", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by (status, pod)) by (status)", + "interval": "", + "legendFormat": "{{`{{ status }}`}}", + "refId": "A", + "datasource": { + "uid": "prometheus", + "type": "prometheus" + } + } + ], + "title": "Status Timeline", + "type": "timeseries", + "options": { + "tooltip": { + "mode": "multi", + "sort": "none" + }, + "legend": { + "showLegend": true, + "displayMode": "table", + "placement": "right", + "calcs": [ + "lastNotNull" + ] + } + }, + "timeFrom": null, + "timeShift": null + } +{{- end }} +{{- if $root.clusterPolicyReportDetails.passTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.passTable.height }}, + "w": 24, + "x": 0, + "y": 15 + }, + "id": 8, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", kind=~\"$kind\", source=~\"$source\", status=\"pass\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod,policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})) by (policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Passed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "status": 7, + "Value": 8 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} +{{- if $root.clusterPolicyReportDetails.failTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.failTable.height }}, + "w": 24, + "x": 0, + "y": 23 + }, + "id": 9, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"fail\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod, policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})) by (policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Failed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "status": 7, + "Value": 8 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} +{{- if $root.clusterPolicyReportDetails.warningTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.warningTable.height }}, + "w": 24, + "x": 0, + "y": 31 + }, + "id": 10, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"warn\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod,policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})) by (policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "status": 7, + "Value": 8 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} +{{- if $root.clusterPolicyReportDetails.errorTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.clusterPolicyReportDetails.errorTable.height }}, + "w": 24, + "x": 0, + "y": 36 + }, + "id": 11, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=\"warn\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod, policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})) by (policy,rule,kind,name,status,severity,category,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Errored Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "severity": 2, + "status": 7, + "Value": 8 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} + ], + "schemaVersion": 26, + "style": "dark", + "tags": [ + "Policy Reporter" + ], + "templating": { + "list": [ + { + "hide": 0, + "label": "Datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "current": {}, + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(cluster_policy_report_result, policy)", + "hide": 0, + "includeAll": true, + "label": "Policy", + "multi": true, + "name": "policy", + "options": [], + "query": "label_values(cluster_policy_report_result, policy)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(cluster_policy_report_result, category)", + "hide": 0, + "includeAll": true, + "label": "Category", + "multi": true, + "name": "category", + "options": [], + "query": "label_values(cluster_policy_report_result, category)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(cluster_policy_report_result, severity)", + "hide": 0, + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "label_values(cluster_policy_report_result, severity)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(cluster_policy_report_result, kind)", + "hide": 0, + "includeAll": true, + "label": "Kind", + "multi": true, + "name": "kind", + "options": [], + "query": "label_values(cluster_policy_report_result, kind)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(cluster_policy_report_result, source)", + "hide": 0, + "includeAll": true, + "label": "Source", + "multi": true, + "name": "source", + "options": [], + "query": "label_values(cluster_policy_report_result, source)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + {{- range $filters }} + ,{ + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(cluster_policy_report_result, {{.}})", + "hide": 0, + "includeAll": true, + "label": "{{ . | title }}", + "multi": true, + "name": "{{.}}", + "options": [], + "query": "label_values(cluster_policy_report_result, {{.}})", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + {{- end }} + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "ClusterPolicyReport Details", + "uid": "iyJszGUMk", + "version": 1 + } +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/clusterpolicy-details.grafanadashboard.yaml b/charts/policy-reporter/templates/monitoring/clusterpolicy-details.grafanadashboard.yaml new file mode 100644 index 0000000000..6e72e69b95 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/clusterpolicy-details.grafanadashboard.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.monitoring.enabled .Values.monitoring.grafana.dashboards.enabled .Values.monitoring.grafana.dashboards.enable.clusterPolicyReportDetails .Values.monitoring.grafana.grafanaDashboard.enabled }} +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + labels: + {{ .Values.monitoring.grafana.dashboards.label }}: {{ .Values.monitoring.grafana.dashboards.value | quote }} + {{- include "monitoring.labels" . | nindent 4 }} + name: {{ include "monitoring.fullname" . }}-clusterpolicy-details-dashboard + namespace: {{ include "grafana.namespace" . }} +spec: + allowCrossNamespaceImport: {{ .Values.monitoring.grafana.grafanaDashboard.allowCrossNamespaceImport }} + folder: {{ .Values.monitoring.grafana.grafanaDashboard.folder }} + instanceSelector: + matchLabels: + {{- toYaml .Values.monitoring.grafana.grafanaDashboard.matchLabels | nindent 6 }} + configMapRef: + name: {{ include "monitoring.fullname" . }}-clusterpolicy-details-dashboard + key: cluster-policy-reporter-details-dashboard.json +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/overview.dashboard.yaml b/charts/policy-reporter/templates/monitoring/overview.dashboard.yaml new file mode 100644 index 0000000000..1be4257435 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/overview.dashboard.yaml @@ -0,0 +1,692 @@ +{{- if and .Values.monitoring.enabled }} +{{ $root := .Values.monitoring }} + +{{- if and $root.grafana.dashboards.enabled $root.grafana.dashboards.enable.overview }} +{{- $filters := $root.grafana.dashboards.labelFilter }} +{{- if and $root.grafana.dashboards.multicluster.enabled $root.grafana.dashboards.multicluster.label }} +{{- $filters = append $filters $root.grafana.dashboards.multicluster.label }} +{{- end }} + +{{- $nsLabel := "exported_namespace" }} +{{- if $root.serviceMonitor.honorLabels }} +{{- $nsLabel = "namespace" }} +{{- end }} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "monitoring.fullname" . }}-overview-dashboard + namespace: {{ include "grafana.namespace" . }} + annotations: + {{ $root.grafana.folder.annotation }}: {{ $root.grafana.folder.name }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{ $root.grafana.dashboards.label }}: {{ $root.grafana.dashboards.value | quote }} + {{- with $root.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- include "monitoring.labels" . | nindent 4 }} +data: + policy-reporter-dashboard.json: | + { + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "{{ $root.grafana.datasource.label }}", + "description": "", + "type": "datasource", + "pluginId": "{{ $root.grafana.datasource.pluginId }}", + "pluginName": "{{ $root.grafana.datasource.pluginName }}" + } + ], + "__requires": [ + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.1.5" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "id": 66, + "links": [], + "panels": [ + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 1 + } + ] + }, + "unit": "none" + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportOverview.failingSummaryRow.height }}, + "w": 15, + "x": 0, + "y": 0 + }, + "id": 4, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=~\"fail|error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by ({{ $nsLabel }}, pod)) by ({{ $nsLabel }})", + "instant": true, + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Failing Policies by Namespace", + "type": "bargauge" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "#EAB839", + "value": 3 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportOverview.failingSummaryRow.height }}, + "w": 9, + "x": 15, + "y": 0 + }, + "id": 5, + "options": { + "colorMode": "value", + "graphMode": "area", + "justifyMode": "center", + "orientation": "vertical", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "textMode": "auto" + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by (status, pod)) by (status)", + "format": "time_series", + "interval": "", + "intervalFactor": 1, + "legendFormat": "{{`{{ status }}`}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Failing ClusterPolicies", + "type": "stat" + }, + { + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 1, + "fillOpacity": 10, + "gradientMode": "none", + "spanNulls": false, + "insertNulls": false, + "showPoints": "never", + "pointSize": 5, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "axisColorMode": "text", + "axisBorderShow": false, + "scaleDistribution": { + "type": "linear" + }, + "axisCenteredZero": false, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "unit": "short", + "decimals": 0, + "min": 0 + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "reducer": "allIsZero", + "op": "gte", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "tooltip": true, + "viz": false, + "legend": true + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "reducer": "allIsNull", + "op": "gte", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "tooltip": true, + "viz": false, + "legend": true + } + } + ] + } + ] + }, + "gridPos": { + "h": {{ $root.policyReportOverview.failingTimeline.height }}, + "w": 24, + "x": 0, + "y": 8 + }, + "id": 11, + "pluginVersion": "10.4.1", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by (policy, pod)) by (policy)", + "interval": "", + "legendFormat": "{{`{{ policy }}`}}", + "refId": "A", + "datasource": { + "uid": "${DS_PROMETHEUS}" + } + }, + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=~\"fail|error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by (policy, pod)) by (policy)", + "interval": "", + "legendFormat": "{{`{{ policy }}`}}", + "refId": "B", + "datasource": { + "uid": "${DS_PROMETHEUS}" + } + } + ], + "title": "Failing Policies Graph", + "type": "timeseries", + "options": { + "tooltip": { + "mode": "multi", + "sort": "none" + }, + "legend": { + "showLegend": true, + "displayMode": "table", + "placement": "right", + "calcs": [ + "lastNotNull" + ] + } + }, + "timeFrom": null, + "timeShift": null + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportOverview.failingPolicyRuleTable.height }}, + "w": 24, + "x": 0, + "y": 18 + }, + "id": 7, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=~\"fail|error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by (pod,{{ $nsLabel }},policy,rule,kind,name,status,category,severity,source{{ range $filters }},{{.}}{{ end }})) by ({{ $nsLabel }},policy,rule,kind,name,status,category,severity,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }}: {{`{{ policy }}`}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Failing PolicyRules", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true + }, + "indexByName": { + "source": 0, + "category": 1, + "severity": 2, + "{{ $nsLabel }}": 3, + "kind": 4, + "name": 5, + "policy": 6, + "rule": 7, + "status": 8, + "Value": 9 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportOverview.failingClusterPolicyRuleTable.height }}, + "w": 24, + "x": 0, + "y": 28 + }, + "id": 9, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(cluster_policy_report_result{policy=~\"$policy\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", status=~\"fail|error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} })by (pod,policy,rule,kind,name,status,category,severity,source{{ range $filters }},{{.}}{{ end }})) by (policy,rule,kind,name,status,category,severity,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "{{`{{ kind }}`}}: {{`{{ name }}`}} - {{`{{ policy }}`}}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Failing ClusterPolicyRules", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "__name__": true, + "endpoint": true, + "instance": true, + "job": true, + "namespace": true, + "pod": true, + "report": true, + "service": true, + "container": true + }, + "indexByName": { + "source": 0, + "category": 1, + "severity": 2, + "kind": 3, + "name": 4, + "policy": 5, + "rule": 6, + "status": 7, + "Value": 8 + }, + "renameByName": {} + } + } + ], + "type": "table" + } + ], + "schemaVersion": 26, + "style": "dark", + "tags": [ + "Policy Reporter" + ], + "templating": { + "list": [ + { + "hide": 0, + "label": "Datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, policy)", + "hide": 0, + "includeAll": true, + "label": "Policy", + "multi": true, + "name": "policy", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, policy)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, category)", + "hide": 0, + "includeAll": true, + "label": "Category", + "multi": true, + "name": "category", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, category)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, severity)", + "hide": 0, + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, severity)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__= \"policy_report_result\", status=~\"fail|error\"}, {{ $nsLabel }})", + "hide": 0, + "includeAll": true, + "label": "Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": "label_values({__name__= \"policy_report_result\", status=~\"fail|error\"}, {{ $nsLabel }})", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, kind)", + "hide": 0, + "includeAll": true, + "label": "Kind", + "multi": true, + "name": "kind", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, kind)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, source)", + "hide": 0, + "includeAll": true, + "label": "Source", + "multi": true, + "name": "source", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, source)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + {{- range $filters }} + ,{ + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, {{.}})", + "hide": 0, + "includeAll": true, + "label": "{{ . | title }}", + "multi": true, + "name": "{{.}}", + "options": [], + "query": "label_values({__name__=~ \"policy_report_result|cluster_policy_report_result\", status=~\"fail|error\"}, {{.}})", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + {{- end }} + ] + }, + "time": { + "from": "now-30m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "PolicyReports", + "version": 1 + } +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/overview.grafanadashboard.yaml b/charts/policy-reporter/templates/monitoring/overview.grafanadashboard.yaml new file mode 100644 index 0000000000..c918ce1f56 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/overview.grafanadashboard.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.monitoring.enabled .Values.monitoring.grafana.dashboards.enabled .Values.monitoring.grafana.dashboards.enable.overview .Values.monitoring.grafana.grafanaDashboard.enabled }} +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + labels: + {{ .Values.monitoring.grafana.dashboards.label }}: {{ .Values.monitoring.grafana.dashboards.value | quote }} + {{- include "monitoring.labels" . | nindent 4 }} + name: {{ include "monitoring.fullname" . }}-overview-dashboard + namespace: {{ include "grafana.namespace" . }} +spec: + allowCrossNamespaceImport: {{ .Values.monitoring.grafana.grafanaDashboard.allowCrossNamespaceImport }} + folder: {{ .Values.monitoring.grafana.grafanaDashboard.folder }} + instanceSelector: + matchLabels: + {{- toYaml .Values.monitoring.grafana.grafanaDashboard.matchLabels | nindent 6 }} + configMapRef: + name: {{ include "monitoring.fullname" . }}-overview-dashboard + key: policy-reporter-dashboard.json +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/policy-details.dashboard.yaml b/charts/policy-reporter/templates/monitoring/policy-details.dashboard.yaml new file mode 100644 index 0000000000..4943650c37 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/policy-details.dashboard.yaml @@ -0,0 +1,975 @@ +{{- if and .Values.monitoring.enabled }} +{{ $root := .Values.monitoring }} + +{{- if and $root.grafana.dashboards.enabled $root.grafana.dashboards.enable.policyReportDetails }} +{{- $filters := $root.grafana.dashboards.labelFilter }} +{{- if and $root.grafana.dashboards.multicluster.enabled $root.grafana.dashboards.multicluster.label }} +{{- $filters = append $filters $root.grafana.dashboards.multicluster.label }} +{{- end }} + +{{- $nsLabel := "exported_namespace" }} +{{- if $root.serviceMonitor.honorLabels }} +{{- $nsLabel = "namespace" }} +{{- end }} + +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "monitoring.fullname" . }}-policy-details-dashboard + namespace: {{ include "grafana.namespace" . }} + annotations: + {{ $root.grafana.folder.annotation }}: {{ $root.grafana.folder.name }} + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + labels: + {{ $root.grafana.dashboards.label }}: {{ $root.grafana.dashboards.value | quote }} + {{- with $root.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- include "monitoring.labels" . | nindent 4 }} +data: + policy-reporter-details-dashboard.json: | + { + "__inputs": [ + { + "name": "DS_PROMETHEUS", + "label": "{{ $root.grafana.datasource.label }}", + "description": "", + "type": "datasource", + "pluginId": "{{ $root.grafana.datasource.pluginId }}", + "pluginName": "{{ $root.grafana.datasource.pluginName }}" + } + ], + "__requires": [ + { + "type": "panel", + "id": "bargauge", + "name": "Bar gauge", + "version": "" + }, + { + "type": "grafana", + "id": "grafana", + "name": "Grafana", + "version": "7.1.5" + }, + { + "type": "panel", + "id": "graph", + "name": "Graph", + "version": "" + }, + { + "type": "panel", + "id": "table", + "name": "Table", + "version": "" + } + ], + "annotations": { + "list": [ + { + "builtIn": 1, + "datasource": "-- Grafana --", + "enable": true, + "hide": true, + "iconColor": "rgba(0, 211, 255, 1)", + "name": "Annotations & Alerts", + "type": "dashboard" + } + ] + }, + "editable": true, + "gnetId": null, + "graphTooltip": 0, + "links": [], + "panels": [ + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.firstStatusRow.height }}, + "w": 12, + "x": 0, + "y": 0 + }, + "id": 3, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"pass\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by ({{ $nsLabel }}, pod)) by ({{ $nsLabel }})", + "instant": true, + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Pass Status", + "type": "bargauge" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "red", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.firstStatusRow.height }}, + "w": 12, + "x": 12, + "y": 0 + }, + "id": 5, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"fail\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by ({{ $nsLabel }}, pod)) by ({{ $nsLabel }})", + "instant": true, + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Fail Status", + "type": "bargauge" + } +{{- if $root.policyReportDetails.secondStatusRow.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "orange", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.secondStatusRow.height }}, + "w": 12, + "x": 0, + "y": 7 + }, + "id": 4, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"warn\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by ({{ $nsLabel }}, pod)) by ({{ $nsLabel }})", + "instant": true, + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Warning Status", + "type": "bargauge" + }, + { + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": {}, + "decimals": 0, + "mappings": [], + "min": 0, + "noValue": "0", + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "dark-red", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.secondStatusRow.height }}, + "w": 12, + "x": 12, + "y": 7 + }, + "id": 6, + "options": { + "displayMode": "gradient", + "orientation": "horizontal", + "reduceOptions": { + "calcs": [ + "last" + ], + "fields": "", + "values": false + }, + "showUnfilled": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by ({{ $nsLabel }}, pod)) by ({{ $nsLabel }})", + "instant": true, + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }}", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Policy Error Status", + "type": "bargauge" + } +{{- end }} +{{- if $root.policyReportDetails.statusTimeline.enabled }} + ,{ + "datasource": { + "uid": "${DS_PROMETHEUS}" + }, + "fieldConfig": { + "defaults": { + "custom": { + "drawStyle": "line", + "lineInterpolation": "linear", + "barAlignment": 0, + "lineWidth": 1, + "fillOpacity": 10, + "gradientMode": "none", + "spanNulls": false, + "insertNulls": false, + "showPoints": "never", + "pointSize": 5, + "stacking": { + "mode": "none", + "group": "A" + }, + "axisPlacement": "auto", + "axisLabel": "", + "axisColorMode": "text", + "axisBorderShow": false, + "scaleDistribution": { + "type": "linear" + }, + "axisCenteredZero": false, + "hideFrom": { + "tooltip": false, + "viz": false, + "legend": false + }, + "thresholdsStyle": { + "mode": "off" + } + }, + "color": { + "mode": "palette-classic" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "value": null, + "color": "green" + }, + { + "value": 80, + "color": "red" + } + ] + }, + "unit": "none", + "decimals": 0, + "min": 0 + }, + "overrides": [ + { + "matcher": { + "id": "byValue", + "options": { + "reducer": "allIsZero", + "op": "gte", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "tooltip": true, + "viz": false, + "legend": true + } + } + ] + }, + { + "matcher": { + "id": "byValue", + "options": { + "reducer": "allIsNull", + "op": "gte", + "value": 0 + } + }, + "properties": [ + { + "id": "custom.hideFrom", + "value": { + "tooltip": true, + "viz": false, + "legend": true + } + } + ] + } + ] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.statusTimeline.height }}, + "w": 24, + "x": 0, + "y": 10 + }, + "id": 13, + "pluginVersion": "10.4.1", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} } > 0) by (status, pod, {{ $nsLabel }})) by (status, {{ $nsLabel }})", + "interval": "", + "legendFormat": "{{ printf `{{%s}}` $nsLabel }} {{`{{ status }}`}}", + "refId": "A", + "datasource": { + "uid": "${DS_PROMETHEUS}" + } + } + ], + "title": "Status Timeline", + "type": "timeseries", + "options": { + "tooltip": { + "mode": "multi", + "sort": "none" + }, + "legend": { + "showLegend": true, + "displayMode": "table", + "placement": "right", + "calcs": [ + "lastNotNull" + ] + } + }, + "timeFrom": null, + "timeShift": null + } +{{- end }} +{{- if $root.policyReportDetails.passTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.passTable.height }}, + "w": 24, + "x": 0, + "y": 19 + }, + "id": 8, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"pass\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Passed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "{{ $nsLabel }}": 3, + "kind": 4, + "name": 5, + "policy": 6, + "rule": 7, + "severity": 2, + "status": 8, + "Value": 9 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} +{{- if $root.policyReportDetails.failTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + }, + { + "color": "red", + "value": 80 + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.failTable.height }}, + "w": 24, + "x": 0, + "y": 27 + }, + "id": 9, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"fail\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Failed Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "{{ $nsLabel }}": 3, + "kind": 4, + "name": 5, + "policy": 6, + "rule": 7, + "severity": 2, + "status": 8, + "Value": 9 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} +{{- if $root.policyReportDetails.warningTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.warningTable.height }}, + "w": 24, + "x": 0, + "y": 35 + }, + "id": 10, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"warn\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }} )", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Warning Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "source": 1, + "category": 2, + "{{ $nsLabel }}": 3, + "kind": 4, + "name": 5, + "policy": 6, + "rule": 7, + "severity": 2, + "status": 8, + "Value": 9 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} +{{- if $root.policyReportDetails.errorTable.enabled }} + ,{ + "datasource": "${DS_PROMETHEUS}", + "fieldConfig": { + "defaults": { + "custom": { + "align": null, + "displayMode": "auto" + }, + "mappings": [], + "thresholds": { + "mode": "absolute", + "steps": [ + { + "color": "green", + "value": null + } + ] + } + }, + "overrides": [] + }, + "gridPos": { + "h": {{ $root.policyReportDetails.errorTable.height }}, + "w": 24, + "x": 0, + "y": 40 + }, + "id": 11, + "options": { + "showHeader": true + }, + "pluginVersion": "7.1.5", + "targets": [ + { + "expr": "max(sum(policy_report_result{policy=~\"$policy\", rule=~\"$rule\", category=~\"$category\", severity=~\"$severity\", source=~\"$source\", kind=~\"$kind\", {{ $nsLabel }}=~\"$namespace\", status=\"error\"{{ range $filters }}, {{.}}=~\"${{.}}\"{{ end }} }) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})) by ({{ $nsLabel }},category,policy,rule,kind,name,severity,status,source{{ range $filters }},{{.}}{{ end }})", + "format": "table", + "instant": true, + "interval": "", + "legendFormat": "", + "refId": "A" + } + ], + "timeFrom": null, + "timeShift": null, + "title": "Errored Resources", + "transformations": [ + { + "id": "organize", + "options": { + "excludeByName": { + "Time": true, + "status": false + }, + "indexByName": { + "Time": 0, + "category": 1, + "{{ $nsLabel }}": 3, + "kind": 4, + "name": 5, + "policy": 6, + "rule": 7, + "severity": 2, + "status": 8, + "Value": 9 + }, + "renameByName": { + "{{ $nsLabel }}": "namespace" + } + } + } + ], + "type": "table" + } +{{- end }} + ], + "schemaVersion": 26, + "style": "dark", + "tags": [ + "Policy Reporter" + ], + "templating": { + "list": [ + { + "hide": 0, + "label": "Datasource", + "name": "DS_PROMETHEUS", + "options": [], + "query": "prometheus", + "refresh": 1, + "regex": "", + "type": "datasource" + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, policy)", + "hide": 0, + "includeAll": true, + "label": "Policy", + "multi": true, + "name": "policy", + "options": [], + "query": "label_values(policy_report_result, policy)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result{policy=~\"$policy\"},rule)", + "hide": 0, + "includeAll": true, + "label": "Rule", + "multi": true, + "name": "rule", + "options": [], + "query": { + "qryType": 1, + "query": "label_values(policy_report_result{policy=~\"$policy\"},rule)", + "refId": "PrometheusVariableQueryEditor-VariableQuery" + }, + "refresh": 1, + "regex": "", + "skipUrlSync": false, + "sort": 0, + "type": "query" + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, category)", + "hide": 0, + "includeAll": true, + "label": "Category", + "multi": true, + "name": "category", + "options": [], + "query": "label_values(policy_report_result, category)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, severity)", + "hide": 0, + "includeAll": true, + "label": "Severity", + "multi": true, + "name": "severity", + "options": [], + "query": "label_values(policy_report_result, severity)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, {{ $nsLabel }})", + "hide": 0, + "includeAll": true, + "label": "Namespace", + "multi": true, + "name": "namespace", + "options": [], + "query": "label_values(policy_report_result, {{ $nsLabel }})", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, kind)", + "hide": 0, + "includeAll": true, + "label": "Kind", + "multi": true, + "name": "kind", + "options": [], + "query": "label_values(policy_report_result, kind)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + }, + { + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, source)", + "hide": 0, + "includeAll": true, + "label": "Source", + "multi": true, + "name": "source", + "options": [], + "query": "label_values(policy_report_result, source)", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + {{- range $filters }} + ,{ + "allValue": ".*", + "datasource": "${DS_PROMETHEUS}", + "definition": "label_values(policy_report_result, {{.}})", + "hide": 0, + "includeAll": true, + "label": "{{ . | title }}", + "multi": true, + "name": "{{.}}", + "options": [], + "query": "label_values(policy_report_result, {{.}})", + "refresh": 2, + "regex": "", + "skipUrlSync": false, + "sort": 5, + "tagValuesQuery": "", + "tags": [], + "tagsQuery": "", + "type": "query", + "useTags": false + } + {{- end }} + ] + }, + "time": { + "from": "now-5m", + "to": "now" + }, + "timepicker": { + "refresh_intervals": [ + "5s", + "10s", + "30s", + "1m", + "5m", + "15m", + "30m", + "1h", + "2h", + "1d" + ] + }, + "timezone": "", + "title": "PolicyReport Details", + "uid": "Tf1skG8Mz", + "version": 1 + } +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/monitoring/policy-details.grafanadashboard.yaml b/charts/policy-reporter/templates/monitoring/policy-details.grafanadashboard.yaml new file mode 100644 index 0000000000..5b4df191c3 --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/policy-details.grafanadashboard.yaml @@ -0,0 +1,19 @@ +{{- if and .Values.monitoring.enabled .Values.monitoring.grafana.dashboards.enabled .Values.monitoring.grafana.dashboards.enable.policyReportDetails .Values.monitoring.grafana.grafanaDashboard.enabled }} +apiVersion: grafana.integreatly.org/v1beta1 +kind: GrafanaDashboard +metadata: + labels: + {{ .Values.monitoring.grafana.dashboards.label }}: {{ .Values.monitoring.grafana.dashboards.value | quote }} + {{- include "monitoring.labels" . | nindent 4 }} + name: {{ include "monitoring.fullname" . }}-policy-details-dashboard + namespace: {{ include "grafana.namespace" . }} +spec: + allowCrossNamespaceImport: {{ .Values.monitoring.grafana.grafanaDashboard.allowCrossNamespaceImport }} + folder: {{ .Values.monitoring.grafana.grafanaDashboard.folder }} + instanceSelector: + matchLabels: + {{- toYaml .Values.monitoring.grafana.grafanaDashboard.matchLabels | nindent 6 }} + configMapRef: + name: {{ include "monitoring.fullname" . }}-policy-details-dashboard + key: policy-reporter-details-dashboard.json +{{- end }} diff --git a/charts/policy-reporter/templates/monitoring/servicemonitor.yaml b/charts/policy-reporter/templates/monitoring/servicemonitor.yaml new file mode 100644 index 0000000000..8f5e3fa89d --- /dev/null +++ b/charts/policy-reporter/templates/monitoring/servicemonitor.yaml @@ -0,0 +1,58 @@ +{{- if and .Values.monitoring.enabled }} +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: {{ include "monitoring.fullname" . }} + namespace: {{ include "monitoring.smNamespace" . }} + {{- if .Values.monitoring.annotations }} + annotations: + {{- toYaml .Values.monitoring.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "monitoring.labels" . | nindent 4 }} + {{- with .Values.monitoring.serviceMonitor.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + selector: + matchLabels: + {{- include "policyreporter.selectorLabels" . | nindent 8 }} + {{- with .Values.monitoring.serviceMonitor.namespaceSelector }} + namespaceSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + endpoints: + - port: http + {{- if and .Values.basicAuth.username .Values.basicAuth.password }} + basicAuth: + password: + name: {{ include "monitoring.fullname" . }}-auth + key: password + username: + name: {{ include "monitoring.fullname" . }}-auth + key: username + {{- else if .Values.basicAuth.secretRef }} + basicAuth: + password: + name: {{ .Values.basicAuth.secretRef }} + key: password + username: + name: {{ .Values.basicAuth.secretRef }} + key: username + {{- end }} + honorLabels: {{ .Values.monitoring.serviceMonitor.honorLabels }} + {{- if .Values.monitoring.serviceMonitor.scrapeTimeout }} + scrapeTimeout: {{ .Values.monitoring.serviceMonitor.scrapeTimeout }} + {{- end }} + {{- if .Values.monitoring.serviceMonitor.interval }} + interval: {{ .Values.monitoring.serviceMonitor.interval }} + {{- end }} + {{- with .Values.monitoring.serviceMonitor.relabelings }} + relabelings: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.monitoring.serviceMonitor.metricRelabelings }} + metricRelabelings: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/networkpolicy.yaml b/charts/policy-reporter/templates/networkpolicy.yaml new file mode 100644 index 0000000000..b1ffdad64b --- /dev/null +++ b/charts/policy-reporter/templates/networkpolicy.yaml @@ -0,0 +1,42 @@ +{{- if .Values.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: {{ include "policyreporter.labels" . | nindent 4 }} + name: {{ include "policyreporter.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} +spec: + podSelector: + matchLabels: {{- include "policyreporter.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + {{- if .Values.ui.enabled }} + - from: + - podSelector: + matchLabels: {{- include "ui.selectorLabels" . | nindent 10 }} + ports: + - protocol: TCP + port: {{ .Values.ui.service.port }} + {{- end }} + {{- if .Values.plugin.trivy.enabled }} + - from: + - podSelector: + matchLabels: {{- include "trivy-plugin.selectorLabels" . | nindent 10 }} + ports: + - protocol: TCP + port: {{ .Values.plugin.trivy.service.port }} + {{- end }} + {{- with .Values.networkPolicy.ingress }} + {{- toYaml . | nindent 2 }} + {{- end }} + {{- with .Values.networkPolicy.egress }} + egress: + {{- toYaml . | nindent 2 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/kyverno/_helpers.tpl b/charts/policy-reporter/templates/plugins/kyverno/_helpers.tpl new file mode 100644 index 0000000000..943de11457 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/_helpers.tpl @@ -0,0 +1,70 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "kyverno-plugin.name" -}} +{{ template "policyreporter.name" . }}-kyverno-plugin +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "kyverno-plugin.fullname" -}} +{{ template "policyreporter.fullname" . }}-kyverno-plugin +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "kyverno-plugin.chart" -}} +{{ template "policyreporter.chart" . }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "kyverno-plugin.labels" -}} +{{ include "kyverno-plugin.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if not .Values.static }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ include "kyverno-plugin.chart" . }} +{{- end -}} +{{- with .Values.global.labels }} +{{ toYaml . }} +{{- end -}} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "kyverno-plugin.selectorLabels" -}} +app.kubernetes.io/name: {{ include "kyverno-plugin.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "kyverno-plugin.serviceAccountName" -}} +{{- if .Values.plugin.kyverno.serviceAccount.create }} +{{- default (include "kyverno-plugin.fullname" .) .Values.plugin.kyverno.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.plugin.kyverno.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "kyverno-plugin.podDisruptionBudget" -}} +{{- if and .Values.plugin.kyverno.podDisruptionBudget.minAvailable .Values.plugin.kyverno.podDisruptionBudget.maxUnavailable }} +{{- fail "Cannot set both" -}} +{{- end }} +{{- if not .Values.plugin.kyverno.podDisruptionBudget.maxUnavailable }} +minAvailable: {{ default 1 .Values.plugin.kyverno.podDisruptionBudget.minAvailable }} +{{- end }} +{{- if .Values.plugin.kyverno.podDisruptionBudget.maxUnavailable }} +maxUnavailable: {{ .Values.plugin.kyverno.podDisruptionBudget.maxUnavailable }} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/kyverno/clusterrole.yaml b/charts/policy-reporter/templates/plugins/kyverno/clusterrole.yaml new file mode 100644 index 0000000000..128b33e089 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/clusterrole.yaml @@ -0,0 +1,45 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if .Values.plugin.kyverno.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + labels: + rbac.authorization.k8s.io/aggregate-to-admin: "true" + {{- include "kyverno-plugin.labels" . | nindent 4 }} + name: {{ include "kyverno-plugin.fullname" . }} +rules: +- apiGroups: + - '*' + resources: + - policies + - policies/status + - clusterpolicies + - clusterpolicies/status + verbs: + - get + - list +{{- if .Values.plugin.kyverno.blockReports.enabled }} +- apiGroups: + - "" + resources: + - events + verbs: + - get + - list + - watch +- apiGroups: + - '*' + resources: + - policyreports + - policyreports/status + - clusterpolicyreports + - clusterpolicyreports/status + verbs: + - get + - list + - create + - update + - delete +{{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/clusterrolebinding.yaml b/charts/policy-reporter/templates/plugins/kyverno/clusterrolebinding.yaml new file mode 100644 index 0000000000..fc1f7c8c30 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/clusterrolebinding.yaml @@ -0,0 +1,18 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if and .Values.plugin.kyverno.serviceAccount.create .Values.plugin.kyverno.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: {{ include "kyverno-plugin.fullname" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} +roleRef: + kind: ClusterRole + name: {{ include "kyverno-plugin.fullname" . }} + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "kyverno-plugin.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/config-secret.yaml b/charts/policy-reporter/templates/plugins/kyverno/config-secret.yaml new file mode 100644 index 0000000000..6fcc3698ea --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/config-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.plugin.kyverno.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "kyverno-plugin.fullname" . }}-config + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} +type: Opaque +data: + config.yaml: {{ tpl (.Files.Get "configs/kyverno-plugin.tmpl") . | b64enc }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/deployment.yaml b/charts/policy-reporter/templates/plugins/kyverno/deployment.yaml new file mode 100644 index 0000000000..8dccea83bf --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/deployment.yaml @@ -0,0 +1,117 @@ +{{- if .Values.plugin.kyverno.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "kyverno-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.plugin.kyverno.replicaCount }} + revisionHistoryLimit: {{ .Values.plugin.kyverno.revisionHistoryLimit }} + {{- with .Values.plugin.kyverno.updateStrategy }} + strategy: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "kyverno-plugin.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/secret: {{ include (print .Template.BasePath "/plugins/kyverno/config-secret.yaml") . | sha256sum | quote }} + {{- with .Values.plugin.kyverno.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 8 }} + {{- with .Values.plugin.kyverno.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.plugin.kyverno.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.plugin.kyverno.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "kyverno-plugin.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.plugin.kyverno.serviceAccount.automount }} + {{- if .Values.plugin.kyverno.podSecurityContext }} + securityContext: + {{- toYaml .Values.plugin.kyverno.podSecurityContext | nindent 8 }} + {{- end }} + containers: + - name: policy-reporter-kyverno-plugin + {{- if .Values.plugin.kyverno.securityContext }} + securityContext: + {{- toYaml .Values.plugin.kyverno.securityContext | nindent 12 }} + {{- end }} + image: "{{ .Values.plugin.kyverno.image.registry }}/{{ .Values.plugin.kyverno.image.repository }}:{{ .Values.plugin.kyverno.image.tag }}" + imagePullPolicy: {{ .Values.plugin.kyverno.image.pullPolicy }} + args: + - run + - --config=/app/config.yaml + - --port={{ .Values.plugin.kyverno.server.port }} + ports: + - name: http + containerPort: {{ .Values.plugin.kyverno.server.port }} + protocol: TCP + livenessProbe: + httpGet: + path: /v1/policies + port: http + readinessProbe: + httpGet: + path: /v1/policies + port: http + resources: + {{- toYaml .Values.plugin.kyverno.resources | nindent 12 }} + volumeMounts: + - name: config-file + mountPath: /app/config.yaml + subPath: config.yaml + readOnly: true + {{- with .Values.plugin.kyverno.extraVolumes.volumeMounts }} + {{ toYaml . | nindent 10 | trim }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- if gt (int .Values.plugin.kyverno.replicaCount) 1 }} + - name: POD_NAME + valueFrom: + fieldRef: + fieldPath: metadata.name + {{- end }} + {{- with .Values.plugin.kyverno.envVars }} + {{- . | toYaml | trim | nindent 10 }} + {{- end }} + volumes: + - name: config-file + secret: + secretName: {{ include "kyverno-plugin.fullname" . }}-config + optional: true + {{- with .Values.plugin.kyverno.extraVolumes.volumes }} + {{ toYaml . | nindent 6 | trim }} + {{- end }} + {{- with .Values.plugin.kyverno.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.plugin.kyverno.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.plugin.kyverno.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.plugin.kyverno.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/kyverno/ingress.yaml b/charts/policy-reporter/templates/plugins/kyverno/ingress.yaml new file mode 100644 index 0000000000..36f7ce05d7 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if .Values.plugin.kyverno.ingress.enabled -}} +{{- $fullName := include "kyverno-plugin.fullname" . -}} +{{- $svcPort := .Values.plugin.kyverno.service.port -}} +{{- if and .Values.plugin.kyverno.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.plugin.kyverno.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.plugin.kyverno.ingress.annotations "kubernetes.io/ingress.class" .Values.plugin.kyverno.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} + {{- with .Values.plugin.kyverno.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.plugin.kyverno.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.plugin.kyverno.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.plugin.kyverno.ingress.className }} + {{- end }} + {{- if .Values.plugin.kyverno.ingress.tls }} + tls: + {{- toYaml .Values.plugin.kyverno.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.plugin.kyverno.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/kyverno/networkpolicy.yaml b/charts/policy-reporter/templates/plugins/kyverno/networkpolicy.yaml new file mode 100644 index 0000000000..f08234fa7a --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/networkpolicy.yaml @@ -0,0 +1,24 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if .Values.plugin.kyverno.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: {{- include "kyverno-plugin.labels" . | nindent 4 }} + name: {{ include "kyverno-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} +spec: + podSelector: + matchLabels: {{- include "kyverno-plugin.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + {{- with .Values.plugin.kyverno.networkPolicy.ingress }} + ingress: + {{- toYaml . | nindent 2 }} + {{- end }} + {{- with .Values.plugin.kyverno.networkPolicy.egress }} + egress: + {{- toYaml . | nindent 2 }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/poddisruptionbudget.yaml b/charts/policy-reporter/templates/plugins/kyverno/poddisruptionbudget.yaml new file mode 100644 index 0000000000..ce439f73bf --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/poddisruptionbudget.yaml @@ -0,0 +1,19 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if (gt (int .Values.plugin.kyverno.replicaCount) 1) }} +{{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }} +apiVersion: policy/v1 +{{- else }} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "kyverno-plugin.fullname" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} +spec: +{{- include "kyverno-plugin.podDisruptionBudget" . | indent 2 }} + selector: + matchLabels: + {{- include "kyverno-plugin.selectorLabels" . | nindent 6 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/role.yaml b/charts/policy-reporter/templates/plugins/kyverno/role.yaml new file mode 100644 index 0000000000..be0b8585a8 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/role.yaml @@ -0,0 +1,22 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if and (and .Values.plugin.kyverno.serviceAccount.create .Values.plugin.kyverno.rbac.enabled) (and .Values.plugin.kyverno.blockReports.enabled (gt (int .Values.plugin.kyverno.replicaCount) 1)) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} + name: {{ include "kyverno-plugin.fullname" . }}-leaderelection + namespace: {{ include "policyreporter.namespace" . }} +rules: +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - get + - patch + - update +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/rolebinding.yaml b/charts/policy-reporter/templates/plugins/kyverno/rolebinding.yaml new file mode 100644 index 0000000000..985816191f --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if and (and .Values.plugin.kyverno.serviceAccount.create .Values.plugin.kyverno.rbac.enabled) (and .Values.plugin.kyverno.blockReports.enabled (gt (int .Values.plugin.kyverno.replicaCount) 1)) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "kyverno-plugin.fullname" . }}-leaderelection + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} +roleRef: + kind: Role + name: {{ include "kyverno-plugin.fullname" . }}-leaderelection + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "kyverno-plugin.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/secret-role.yaml b/charts/policy-reporter/templates/plugins/kyverno/secret-role.yaml new file mode 100644 index 0000000000..41e20ed27b --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/secret-role.yaml @@ -0,0 +1,17 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if and .Values.plugin.kyverno.serviceAccount.create .Values.plugin.kyverno.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} + name: {{ include "kyverno-plugin.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} +rules: +- apiGroups: [''] + resources: + - secrets + verbs: + - get +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/secret-rolebinding.yaml b/charts/policy-reporter/templates/plugins/kyverno/secret-rolebinding.yaml new file mode 100644 index 0000000000..58b09ef474 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/secret-rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if and .Values.plugin.kyverno.serviceAccount.create .Values.plugin.kyverno.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "kyverno-plugin.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} +roleRef: + kind: Role + name: {{ include "kyverno-plugin.fullname" . }}-secret-reader + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "kyverno-plugin.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/kyverno/service.yaml b/charts/policy-reporter/templates/plugins/kyverno/service.yaml new file mode 100644 index 0000000000..8f9229e9f1 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/service.yaml @@ -0,0 +1,25 @@ +{{- if .Values.plugin.kyverno.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "kyverno-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} + {{- with .Values.plugin.kyverno.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.plugin.kyverno.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.plugin.kyverno.service.type }} + ports: + - port: {{ .Values.plugin.kyverno.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "kyverno-plugin.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/kyverno/serviceaccount.yaml b/charts/policy-reporter/templates/plugins/kyverno/serviceaccount.yaml new file mode 100644 index 0000000000..f790bc81ab --- /dev/null +++ b/charts/policy-reporter/templates/plugins/kyverno/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.plugin.kyverno.enabled -}} +{{- if .Values.plugin.kyverno.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "kyverno-plugin.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "kyverno-plugin.labels" . | nindent 4 }} + {{- with .Values.plugin.kyverno.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.plugin.kyverno.serviceAccount.automount }} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/trivy/_helpers.tpl b/charts/policy-reporter/templates/plugins/trivy/_helpers.tpl new file mode 100644 index 0000000000..13bf4d7f6c --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/_helpers.tpl @@ -0,0 +1,70 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "trivy-plugin.name" -}} +{{ template "policyreporter.name" . }}-trivy-plugin +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "trivy-plugin.fullname" -}} +{{ template "policyreporter.fullname" . }}-trivy-plugin +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "trivy-plugin.chart" -}} +{{ template "policyreporter.chart" . }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "trivy-plugin.labels" -}} +{{ include "trivy-plugin.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if not .Values.static }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ include "trivy-plugin.chart" . }} +{{- end }} +{{- with .Values.global.labels }} +{{ toYaml . }} +{{- end -}} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "trivy-plugin.selectorLabels" -}} +app.kubernetes.io/name: {{ include "trivy-plugin.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "trivy-plugin.serviceAccountName" -}} +{{- if .Values.plugin.trivy.serviceAccount.create }} +{{- default (include "trivy-plugin.fullname" .) .Values.plugin.trivy.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.plugin.trivy.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "trivy-plugin.podDisruptionBudget" -}} +{{- if and .Values.plugin.trivy.podDisruptionBudget.minAvailable .Values.plugin.trivy.podDisruptionBudget.maxUnavailable }} +{{- fail "Cannot set both" -}} +{{- end }} +{{- if not .Values.plugin.trivy.podDisruptionBudget.maxUnavailable }} +minAvailable: {{ default 1 .Values.plugin.trivy.podDisruptionBudget.minAvailable }} +{{- end }} +{{- if .Values.plugin.trivy.podDisruptionBudget.maxUnavailable }} +maxUnavailable: {{ .Values.plugin.trivy.podDisruptionBudget.maxUnavailable }} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/trivy/config-secret.yaml b/charts/policy-reporter/templates/plugins/trivy/config-secret.yaml new file mode 100644 index 0000000000..15b86c4a74 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/config-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.plugin.trivy.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "trivy-plugin.fullname" . }}-config + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} +type: Opaque +data: + config.yaml: {{ tpl (.Files.Get "configs/trivy-plugin.tmpl") . | b64enc }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/deployment.yaml b/charts/policy-reporter/templates/plugins/trivy/deployment.yaml new file mode 100644 index 0000000000..033978f8b3 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/deployment.yaml @@ -0,0 +1,149 @@ +{{- if .Values.plugin.trivy.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "trivy-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.plugin.trivy.replicaCount }} + revisionHistoryLimit: {{ .Values.plugin.trivy.revisionHistoryLimit }} + {{- with .Values.plugin.trivy.updateStrategy }} + strategy: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "trivy-plugin.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/secret: {{ include (print .Template.BasePath "/plugins/trivy/config-secret.yaml") . | sha256sum | quote }} + {{- with .Values.plugin.trivy.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "trivy-plugin.labels" . | nindent 8 }} + {{- with .Values.plugin.trivy.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.plugin.trivy.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.plugin.trivy.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "trivy-plugin.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.plugin.trivy.serviceAccount.automount }} + {{- if .Values.plugin.trivy.podSecurityContext }} + securityContext: + {{- toYaml .Values.plugin.trivy.podSecurityContext | nindent 8 }} + {{- end }} + initContainers: + - name: trivy-db + image: "{{ .Values.plugin.trivy.cli.image.registry }}/{{ .Values.plugin.trivy.cli.image.repository }}:{{ .Values.plugin.trivy.cli.image.tag }}" + args: + - --cache-dir + - / + - image + - --download-db-only + {{- range $key, $value := .Values.plugin.trivy.extraArgs }} + {{- if $value }} + - --{{ $key }}={{ $value }} + {{- end }} + {{- end }} + securityContext: + {{- if .Values.plugin.trivy.securityContext }} + {{- toYaml .Values.plugin.trivy.securityContext | nindent 12 }} + {{- end }} + resources: + {{- toYaml .Values.plugin.trivy.resources | nindent 12 }} + env: + {{- with .Values.plugin.trivy.envVars }} + {{- . | toYaml | trim | nindent 10 }} + {{- end }} + volumeMounts: + - name: db + mountPath: /db + - name: tmp + mountPath: /tmp + containers: + - name: policy-reporter-trivy-plugin + {{- if .Values.plugin.trivy.securityContext }} + securityContext: + {{- toYaml .Values.plugin.trivy.securityContext | nindent 12 }} + {{- end }} + image: "{{ .Values.plugin.trivy.image.registry }}/{{ .Values.plugin.trivy.image.repository }}:{{ .Values.plugin.trivy.image.tag }}" + imagePullPolicy: {{ .Values.plugin.trivy.image.pullPolicy }} + args: + - run + - --config=/app/config.yaml + - --port={{ .Values.plugin.trivy.server.port }} + ports: + - name: http + containerPort: {{ .Values.plugin.trivy.server.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.plugin.trivy.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.plugin.trivy.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.plugin.trivy.resources | nindent 12 }} + volumeMounts: + - name: config-file + mountPath: /app/config.yaml + subPath: config.yaml + readOnly: true + - name: db + mountPath: /db + {{- with .Values.plugin.trivy.extraVolumes.volumeMounts }} + {{ toYaml . | nindent 10 | trim }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- with .Values.plugin.trivy.envVars }} + {{- . | toYaml | trim | nindent 10 }} + {{- end }} + volumes: + - name: config-file + secret: + secretName: {{ include "trivy-plugin.fullname" . }}-config + optional: true + - name: db + {{- with .Values.plugin.trivy.dbVolume }} + {{- toYaml . | nindent 8 }} + {{- else }} + emptyDir: {} + {{- end }} + - name: tmp + {{- with .Values.plugin.trivy.tmpVolume }} + {{- toYaml . | nindent 8 }} + {{- else }} + emptyDir: {} + {{- end }} + {{- with .Values.plugin.trivy.extraVolumes.volumes }} + {{ toYaml . | nindent 6 | trim }} + {{- end }} + {{- with .Values.plugin.trivy.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.plugin.trivy.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.plugin.trivy.topologySpreadConstraints }} + topologySpreadConstraints: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.plugin.trivy.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/plugins/trivy/ingress.yaml b/charts/policy-reporter/templates/plugins/trivy/ingress.yaml new file mode 100644 index 0000000000..d7a61acc6c --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.plugin.trivy.enabled -}} +{{- if .Values.plugin.trivy.ingress.enabled -}} +{{- $fullName := include "trivy-plugin.fullname" . -}} +{{- $svcPort := .Values.plugin.trivy.service.port -}} +{{- if and .Values.plugin.trivy.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.plugin.trivy.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.plugin.trivy.ingress.annotations "kubernetes.io/ingress.class" .Values.plugin.trivy.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} + {{- with .Values.plugin.trivy.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.plugin.trivy.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.plugin.trivy.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.plugin.trivy.ingress.className }} + {{- end }} + {{- if .Values.plugin.trivy.ingress.tls }} + tls: + {{- toYaml .Values.plugin.trivy.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.plugin.trivy.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/networkpolicy.yaml b/charts/policy-reporter/templates/plugins/trivy/networkpolicy.yaml new file mode 100644 index 0000000000..011753a9c0 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/networkpolicy.yaml @@ -0,0 +1,31 @@ +{{- if .Values.plugin.trivy.enabled -}} +{{- if .Values.plugin.trivy.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: {{- include "trivy-plugin.labels" . | nindent 4 }} + name: {{ include "trivy-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} +spec: + podSelector: + matchLabels: {{- include "trivy-plugin.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + {{- with .Values.plugin.trivy.networkPolicy.ingress }} + ingress: + {{- toYaml . | nindent 2 }} + {{- end }} + egress: + - to: + - podSelector: + matchLabels: + {{- include "policyreporter.selectorLabels" . | nindent 10 }} + ports: + - protocol: TCP + port: {{ .Values.service.port }} + {{- with .Values.plugin.trivy.networkPolicy.egress }} + {{- toYaml . | nindent 2 }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/poddisruptionbudget.yaml b/charts/policy-reporter/templates/plugins/trivy/poddisruptionbudget.yaml new file mode 100644 index 0000000000..528536604b --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.plugin.trivy.enabled -}} +{{- if (gt (int .Values.plugin.trivy.replicaCount) 1) }} +{{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }} +apiVersion: policy/v1 +{{- else }} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "trivy-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} +spec: +{{- include "trivy-plugin.podDisruptionBudget" . | indent 2 }} + selector: + matchLabels: + {{- include "trivy-plugin.selectorLabels" . | nindent 6 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/secret-role.yaml b/charts/policy-reporter/templates/plugins/trivy/secret-role.yaml new file mode 100644 index 0000000000..bde89f850a --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/secret-role.yaml @@ -0,0 +1,17 @@ +{{- if .Values.plugin.trivy.enabled -}} +{{- if and .Values.plugin.trivy.serviceAccount.create .Values.plugin.trivy.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} + name: {{ include "trivy-plugin.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} +rules: +- apiGroups: [''] + resources: + - secrets + verbs: + - get +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/secret-rolebinding.yaml b/charts/policy-reporter/templates/plugins/trivy/secret-rolebinding.yaml new file mode 100644 index 0000000000..1fd024036c --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/secret-rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.plugin.trivy.enabled -}} +{{- if and .Values.plugin.trivy.serviceAccount.create .Values.plugin.trivy.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "trivy-plugin.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} +roleRef: + kind: Role + name: {{ include "trivy-plugin.fullname" . }}-secret-reader + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "trivy-plugin.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/service.yaml b/charts/policy-reporter/templates/plugins/trivy/service.yaml new file mode 100644 index 0000000000..22e1946233 --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/service.yaml @@ -0,0 +1,25 @@ +{{- if .Values.plugin.trivy.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "trivy-plugin.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} + {{- with .Values.plugin.trivy.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.plugin.trivy.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.plugin.trivy.service.type }} + ports: + - port: {{ .Values.plugin.trivy.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "trivy-plugin.selectorLabels" . | nindent 4 }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/plugins/trivy/serviceaccount.yaml b/charts/policy-reporter/templates/plugins/trivy/serviceaccount.yaml new file mode 100644 index 0000000000..288e02014e --- /dev/null +++ b/charts/policy-reporter/templates/plugins/trivy/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.plugin.trivy.enabled -}} +{{- if .Values.plugin.trivy.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "trivy-plugin.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "trivy-plugin.labels" . | nindent 4 }} + {{- with .Values.plugin.trivy.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.plugin.trivy.serviceAccount.automount }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/poddisruptionbudget.yaml b/charts/policy-reporter/templates/poddisruptionbudget.yaml new file mode 100644 index 0000000000..0d1eb250a6 --- /dev/null +++ b/charts/policy-reporter/templates/poddisruptionbudget.yaml @@ -0,0 +1,22 @@ +{{- if (gt (int .Values.replicaCount) 1) }} +{{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }} +apiVersion: policy/v1 +{{- else }} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ template "policyreporter.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} +spec: +{{- include "policyreporter.podDisruptionBudget" . | indent 2 }} + selector: + matchLabels: + {{- include "policyreporter.selectorLabels" . | nindent 6 }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/policyreporter.kyverno.io_targetconfigs.yaml b/charts/policy-reporter/templates/policyreporter.kyverno.io_targetconfigs.yaml new file mode 100644 index 0000000000..b1b79d12fd --- /dev/null +++ b/charts/policy-reporter/templates/policyreporter.kyverno.io_targetconfigs.yaml @@ -0,0 +1,494 @@ +{{- if .Values.target.crd -}} +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: targetconfigs.policyreporter.kyverno.io +spec: + group: policyreporter.kyverno.io + names: + kind: TargetConfig + listKind: TargetConfigList + plural: targetconfigs + shortNames: + - tcfg + singular: targetconfig + scope: Cluster + versions: + - name: v1alpha1 + schema: + openAPIV3Schema: + description: TargetConfig is the Schema for the targetconfigs API. + properties: + apiVersion: + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources + type: string + kind: + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds + type: string + metadata: + type: object + spec: + description: TargetConfigSpec defines the desired state of TargetConfig. + oneOf: + - required: + - s3 + - required: + - webhook + - required: + - telegram + - required: + - slack + - required: + - elasticSearch + - required: + - gcs + - required: + - loki + - required: + - securityHub + - required: + - kinesis + - required: + - splunk + - required: + - teams + - required: + - jira + - required: + - alertManager + properties: + alertManager: + properties: + certificate: + type: string + headers: + additionalProperties: + type: string + type: object + host: + type: string + skipTLS: + type: boolean + required: + - host + type: object + customFields: + additionalProperties: + type: string + type: object + elasticSearch: + properties: + apiKey: + type: string + certificate: + type: string + headers: + additionalProperties: + type: string + type: object + host: + type: string + index: + type: string + password: + type: string + rotation: + type: string + skipTLS: + type: boolean + typelessApi: + type: boolean + username: + type: string + required: + - host + - index + type: object + filter: + properties: + namespaces: + properties: + exclude: + items: + type: string + type: array + include: + items: + type: string + type: array + selector: + additionalProperties: + type: string + type: object + type: object + policies: + properties: + exclude: + items: + type: string + type: array + include: + items: + type: string + type: array + selector: + additionalProperties: + type: string + type: object + type: object + reportLabels: + properties: + exclude: + items: + type: string + type: array + include: + items: + type: string + type: array + selector: + additionalProperties: + type: string + type: object + type: object + severities: + properties: + exclude: + items: + type: string + type: array + include: + items: + type: string + type: array + selector: + additionalProperties: + type: string + type: object + type: object + sources: + properties: + exclude: + items: + type: string + type: array + include: + items: + type: string + type: array + selector: + additionalProperties: + type: string + type: object + type: object + status: + properties: + exclude: + items: + type: string + type: array + include: + items: + type: string + type: array + selector: + additionalProperties: + type: string + type: object + type: object + type: object + gcs: + properties: + bucket: + type: string + credentials: + type: string + prefix: + type: string + required: + - bucket + - credentials + - prefix + type: object + jira: + properties: + apiToken: + type: string + apiVersion: + type: string + certificate: + type: string + components: + items: + type: string + type: array + host: + type: string + issueType: + type: string + labels: + items: + type: string + type: array + password: + type: string + projectKey: + type: string + skipTLS: + type: boolean + summaryTemplate: + type: string + username: + type: string + required: + - projectKey + type: object + kinesis: + properties: + accessKeyId: + type: string + endpoint: + type: string + region: + type: string + secretAccessKey: + type: string + streamName: + type: string + required: + - accessKeyId + - secretAccessKey + - streamName + type: object + loki: + properties: + certificate: + type: string + headers: + additionalProperties: + type: string + type: object + host: + type: string + password: + type: string + path: + type: string + skipTLS: + type: boolean + username: + type: string + required: + - host + type: object + minimumSeverity: + type: string + mountedSecret: + type: string + name: + type: string + s3: + properties: + accessKeyId: + type: string + bucket: + type: string + bucketKeyEnabled: + type: boolean + endpoint: + type: string + kmsKeyId: + type: string + pathStyle: + type: boolean + prefix: + type: string + region: + type: string + secretAccessKey: + type: string + serverSideEncryption: + type: string + required: + - accessKeyId + - bucket + - secretAccessKey + type: object + secretRef: + type: string + securityHub: + properties: + accessKeyId: + type: string + accountId: + type: string + companyName: + type: string + delayInSeconds: + type: integer + endpoint: + type: string + productName: + type: string + region: + type: string + secretAccessKey: + type: string + synchronize: + type: boolean + required: + - accessKeyId + - accountId + - productName + - secretAccessKey + type: object + skipExistingOnStartup: + default: true + type: boolean + slack: + properties: + certificate: + type: string + channel: + type: string + headers: + additionalProperties: + type: string + type: object + keepalive: + properties: + interval: + type: string + params: + additionalProperties: + type: string + type: object + type: object + skipTLS: + type: boolean + webhook: + type: string + required: + - channel + - webhook + type: object + sources: + items: + type: string + type: array + splunk: + properties: + certificate: + type: string + headers: + additionalProperties: + type: string + type: object + host: + type: string + skipTLS: + type: boolean + token: + type: string + required: + - host + - token + type: object + teams: + properties: + certificate: + type: string + headers: + additionalProperties: + type: string + type: object + keepalive: + properties: + interval: + type: string + params: + additionalProperties: + type: string + type: object + type: object + skipTLS: + type: boolean + webhook: + type: string + required: + - webhook + type: object + telegram: + properties: + certificate: + type: string + chatId: + type: string + headers: + additionalProperties: + type: string + type: object + keepalive: + properties: + interval: + type: string + params: + additionalProperties: + type: string + type: object + type: object + skipTLS: + type: boolean + token: + type: string + webhook: + type: string + required: + - chatId + - token + - webhook + type: object + webhook: + properties: + certificate: + type: string + headers: + additionalProperties: + type: string + type: object + keepalive: + properties: + interval: + type: string + params: + additionalProperties: + type: string + type: object + type: object + skipTLS: + type: boolean + webhook: + type: string + required: + - webhook + type: object + type: object + status: + description: TargetConfigStatus defines the observed state of TargetConfig. + type: object + type: object + served: true + storage: true + subresources: + status: {} +{{- end -}} \ No newline at end of file diff --git a/charts/policy-reporter/templates/role.yaml b/charts/policy-reporter/templates/role.yaml new file mode 100644 index 0000000000..ba46dab3cb --- /dev/null +++ b/charts/policy-reporter/templates/role.yaml @@ -0,0 +1,24 @@ +{{- if and .Values.rbac.enabled (gt (int .Values.replicaCount) 1) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + name: {{ include "policyreporter.fullname" . }}-leaderelection + namespace: {{ include "policyreporter.namespace" . }} +rules: +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - create + - delete + - get + - patch + - update +{{- end -}} diff --git a/charts/policy-reporter/templates/rolebinding.yaml b/charts/policy-reporter/templates/rolebinding.yaml new file mode 100644 index 0000000000..6d2b1e4e50 --- /dev/null +++ b/charts/policy-reporter/templates/rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if and .Values.rbac.enabled (gt (int .Values.replicaCount) 1) -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "policyreporter.fullname" . }}-leaderelection + namespace: {{ include "policyreporter.namespace" . }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} +roleRef: + kind: Role + name: {{ include "policyreporter.fullname" . }}-leaderelection + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "policyreporter.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end -}} diff --git a/charts/policy-reporter/templates/secret-role.yaml b/charts/policy-reporter/templates/secret-role.yaml new file mode 100644 index 0000000000..0aa8a27105 --- /dev/null +++ b/charts/policy-reporter/templates/secret-role.yaml @@ -0,0 +1,21 @@ +{{- if .Values.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + name: {{ include "policyreporter.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} +rules: +- apiGroups: [''] + resources: + - secrets + verbs: + - get + - list + - watch +{{- end -}} diff --git a/charts/policy-reporter/templates/secret-rolebinding.yaml b/charts/policy-reporter/templates/secret-rolebinding.yaml new file mode 100644 index 0000000000..3abbf9bc9d --- /dev/null +++ b/charts/policy-reporter/templates/secret-rolebinding.yaml @@ -0,0 +1,21 @@ +{{- if .Values.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "policyreporter.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} + {{- if .Values.annotations }} + annotations: + {{- toYaml .Values.annotations | nindent 4 }} + {{- end }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} +roleRef: + kind: Role + name: {{ include "policyreporter.fullname" . }}-secret-reader + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "policyreporter.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end -}} diff --git a/charts/policy-reporter/templates/service.yaml b/charts/policy-reporter/templates/service.yaml new file mode 100644 index 0000000000..d29ab2479a --- /dev/null +++ b/charts/policy-reporter/templates/service.yaml @@ -0,0 +1,30 @@ +{{- if .Values.service.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "policyreporter.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- with .Values.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- if or .Values.annotations .Values.service.annotations }} + annotations: + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.service.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: {{ .Values.port.name }} + protocol: TCP + name: http + selector: + {{- include "policyreporter.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/policy-reporter/templates/serviceaccount.yaml b/charts/policy-reporter/templates/serviceaccount.yaml new file mode 100644 index 0000000000..4f7a9aa85d --- /dev/null +++ b/charts/policy-reporter/templates/serviceaccount.yaml @@ -0,0 +1,18 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "policyreporter.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "policyreporter.labels" . | nindent 4 }} + {{- if or .Values.annotations .Values.serviceAccount.annotations }} + annotations: + {{- with .Values.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.serviceAccount.annotations }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/ui/_helpers.tpl b/charts/policy-reporter/templates/ui/_helpers.tpl new file mode 100644 index 0000000000..536e2cde0c --- /dev/null +++ b/charts/policy-reporter/templates/ui/_helpers.tpl @@ -0,0 +1,70 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "ui.name" -}} +{{ template "policyreporter.name" . }}-ui +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "ui.fullname" -}} +{{ template "policyreporter.fullname" . }}-ui +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "ui.chart" -}} +{{ template "policyreporter.chart" . }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "ui.labels" -}} +{{ include "ui.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +{{- if not .Values.static }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +helm.sh/chart: {{ include "ui.chart" . }} +{{- end }} +{{- with .Values.global.labels }} +{{ toYaml . }} +{{- end -}} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "ui.selectorLabels" -}} +app.kubernetes.io/name: {{ include "ui.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "ui.serviceAccountName" -}} +{{- if .Values.ui.serviceAccount.create }} +{{- default (include "ui.fullname" .) .Values.ui.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.ui.serviceAccount.name }} +{{- end }} +{{- end }} + +{{- define "ui.podDisruptionBudget" -}} +{{- if and .Values.ui.podDisruptionBudget.minAvailable .Values.ui.podDisruptionBudget.maxUnavailable }} +{{- fail "Cannot set both" -}} +{{- end }} +{{- if not .Values.ui.podDisruptionBudget.maxUnavailable }} +minAvailable: {{ default 1 .Values.ui.podDisruptionBudget.minAvailable }} +{{- end }} +{{- if .Values.ui.podDisruptionBudget.maxUnavailable }} +maxUnavailable: {{ .Values.ui.podDisruptionBudget.maxUnavailable }} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/ui/config-secret.yaml b/charts/policy-reporter/templates/ui/config-secret.yaml new file mode 100644 index 0000000000..cd46993023 --- /dev/null +++ b/charts/policy-reporter/templates/ui/config-secret.yaml @@ -0,0 +1,12 @@ +{{- if .Values.ui.enabled -}} +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "ui.fullname" . }}-config + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} +type: Opaque +data: + config.yaml: {{ tpl (.Files.Get "configs/ui.tmpl") . | b64enc }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ui/deployment.yaml b/charts/policy-reporter/templates/ui/deployment.yaml new file mode 100644 index 0000000000..dfaf245348 --- /dev/null +++ b/charts/policy-reporter/templates/ui/deployment.yaml @@ -0,0 +1,118 @@ +{{- if .Values.ui.enabled -}} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "ui.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.ui.replicaCount }} + revisionHistoryLimit: {{ .Values.ui.revisionHistoryLimit }} + {{- with .Values.ui.updateStrategy }} + strategy: + {{- toYaml . | nindent 4 }} + {{- end }} + selector: + matchLabels: + {{- include "ui.selectorLabels" . | nindent 6 }} + template: + metadata: + annotations: + checksum/secret: {{ include (print .Template.BasePath "/ui/config-secret.yaml") . | sha256sum | quote }} + checksum/cluster-secret: {{ include (print .Template.BasePath "/cluster-secret.yaml") . | sha256sum | quote }} + {{- with .Values.ui.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "ui.labels" . | nindent 8 }} + {{- with .Values.ui.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.ui.priorityClassName }} + priorityClassName: {{ . }} + {{- end }} + {{- with .Values.ui.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "ui.serviceAccountName" . }} + automountServiceAccountToken: {{ .Values.ui.serviceAccount.automount }} + {{- if .Values.ui.podSecurityContext }} + securityContext: + {{- toYaml .Values.ui.podSecurityContext | nindent 8 }} + {{- end }} + containers: + - name: policy-reporter-ui + {{- if .Values.ui.securityContext }} + securityContext: + {{- toYaml .Values.ui.securityContext | nindent 12 }} + {{- end }} + image: "{{ .Values.ui.image.registry }}/{{ .Values.ui.image.repository }}:{{ .Values.ui.image.tag }}" + imagePullPolicy: {{ .Values.ui.image.pullPolicy }} + args: + - run + - --config=/app/config.yaml + - --port={{ .Values.ui.server.port }} + ports: + - name: http + containerPort: {{ .Values.ui.server.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.ui.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.ui.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.ui.resources | nindent 12 }} + volumeMounts: + - name: config-file + mountPath: /app/config.yaml + subPath: config.yaml + readOnly: true + - name: tmp + mountPath: /tmp + {{- with .Values.ui.extraVolumes.volumeMounts }} + {{ toYaml . | nindent 10 | trim }} + {{- end }} + env: + - name: POD_NAMESPACE + valueFrom: + fieldRef: + fieldPath: metadata.namespace + {{- with .Values.ui.envVars }} + {{- . | toYaml | trim | nindent 10 }} + {{- end }} + {{- if .Values.ui.sidecarContainers }} + {{- range $name, $spec := .Values.ui.sidecarContainers }} + - name: {{ $name }} + {{- if kindIs "string" $spec }} + {{- tpl $spec $ | nindent 10 }} + {{- else }} + {{- toYaml $spec | nindent 10 }} + {{- end }} + {{- end }} + {{- end }} + volumes: + - name: config-file + secret: + secretName: {{ include "ui.fullname" . }}-config + optional: true + - name: tmp + emptyDir: {} + {{- with .Values.ui.extraVolumes.volumes }} + {{ toYaml . | nindent 6 | trim }} + {{- end }} + {{- with .Values.ui.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.ui.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.ui.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} +{{- end }} diff --git a/charts/policy-reporter/templates/ui/ingress.yaml b/charts/policy-reporter/templates/ui/ingress.yaml new file mode 100644 index 0000000000..0df539a94e --- /dev/null +++ b/charts/policy-reporter/templates/ui/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ui.enabled -}} +{{- if .Values.ui.ingress.enabled -}} +{{- $fullName := include "ui.fullname" . -}} +{{- $svcPort := .Values.ui.ingress.port | default .Values.ui.service.port -}} +{{- if and .Values.ui.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ui.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ui.ingress.annotations "kubernetes.io/ingress.class" .Values.ui.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} + {{- with .Values.ui.ingress.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.ui.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ui.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ui.ingress.className }} + {{- end }} + {{- if .Values.ui.ingress.tls }} + tls: + {{- toYaml .Values.ui.ingress.tls | nindent 4 }} + {{- end }} + rules: + {{- range .Values.ui.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ui/networkpolicy.yaml b/charts/policy-reporter/templates/ui/networkpolicy.yaml new file mode 100644 index 0000000000..9278f7822b --- /dev/null +++ b/charts/policy-reporter/templates/ui/networkpolicy.yaml @@ -0,0 +1,53 @@ +{{- if .Values.ui.enabled -}} +{{- if .Values.ui.networkPolicy.enabled }} +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + labels: {{- include "ui.labels" . | nindent 4 }} + name: {{ include "ui.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} +spec: + podSelector: + matchLabels: {{- include "ui.selectorLabels" . | nindent 6 }} + policyTypes: + - Ingress + - Egress + ingress: + - from: + ports: + - protocol: TCP + port: {{ .Values.ui.service.port }} + {{- with .Values.ui.networkPolicy.ingress }} + {{- toYaml . | nindent 2 }} + {{- end }} + egress: + - to: + - podSelector: + matchLabels: + {{- include "policyreporter.selectorLabels" . | nindent 10 }} + ports: + - protocol: TCP + port: {{ .Values.service.port }} + {{- if or .Values.plugin.kyverno.enabled }} + - to: + - podSelector: + matchLabels: + {{- include "kyverno-plugin.selectorLabels" . | nindent 10 }} + ports: + - protocol: TCP + port: {{ .Values.plugin.kyverno.service.port }} + {{- end }} + {{- if or .Values.plugin.trivy.enabled }} + - to: + - podSelector: + matchLabels: + {{- include "trivy-plugin.selectorLabels" . | nindent 10 }} + ports: + - protocol: TCP + port: {{ .Values.plugin.trivy.service.port }} + {{- end }} + {{- with .Values.networkPolicy.egress }} + {{- toYaml . | nindent 2 }} + {{- end }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ui/poddisruptionbudget.yaml b/charts/policy-reporter/templates/ui/poddisruptionbudget.yaml new file mode 100644 index 0000000000..55d733627f --- /dev/null +++ b/charts/policy-reporter/templates/ui/poddisruptionbudget.yaml @@ -0,0 +1,20 @@ +{{- if .Values.ui.enabled -}} +{{- if (gt (int .Values.ui.replicaCount) 1) }} +{{- if .Capabilities.APIVersions.Has "policy/v1/PodDisruptionBudget" }} +apiVersion: policy/v1 +{{- else }} +apiVersion: policy/v1beta1 +{{- end }} +kind: PodDisruptionBudget +metadata: + name: {{ include "ui.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} +spec: +{{- include "ui.podDisruptionBudget" . | indent 2 }} + selector: + matchLabels: + {{- include "ui.selectorLabels" . | nindent 6 }} +{{- end }} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ui/secret-role.yaml b/charts/policy-reporter/templates/ui/secret-role.yaml new file mode 100644 index 0000000000..faf398212b --- /dev/null +++ b/charts/policy-reporter/templates/ui/secret-role.yaml @@ -0,0 +1,17 @@ +{{- if .Values.ui.enabled -}} +{{- if and .Values.ui.serviceAccount.create .Values.ui.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + {{- include "ui.labels" . | nindent 4 }} + name: {{ include "ui.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} +rules: +- apiGroups: [''] + resources: + - secrets + verbs: + - get +{{- end -}} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ui/secret-rolebinding.yaml b/charts/policy-reporter/templates/ui/secret-rolebinding.yaml new file mode 100644 index 0000000000..3e5ba6d5c8 --- /dev/null +++ b/charts/policy-reporter/templates/ui/secret-rolebinding.yaml @@ -0,0 +1,19 @@ +{{- if .Values.ui.enabled -}} +{{- if and .Values.ui.serviceAccount.create .Values.rbac.enabled -}} +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: {{ include "ui.fullname" . }}-secret-reader + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} +roleRef: + kind: Role + name: {{ include "ui.fullname" . }}-secret-reader + apiGroup: rbac.authorization.k8s.io +subjects: +- kind: "ServiceAccount" + name: {{ include "ui.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} +{{- end -}} +{{- end }} \ No newline at end of file diff --git a/charts/policy-reporter/templates/ui/service.yaml b/charts/policy-reporter/templates/ui/service.yaml new file mode 100644 index 0000000000..006a86ed7f --- /dev/null +++ b/charts/policy-reporter/templates/ui/service.yaml @@ -0,0 +1,28 @@ +{{- if .Values.ui.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ui.fullname" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} + {{- with .Values.ui.service.labels }} + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.ui.service.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + type: {{ .Values.ui.service.type }} + ports: + - port: {{ .Values.ui.service.port }} + targetPort: http + protocol: TCP + name: http + {{- if .Values.ui.service.additionalPorts }} + {{- toYaml .Values.ui.service.additionalPorts | nindent 4 }} + {{- end }} + selector: + {{- include "ui.selectorLabels" . | nindent 4 }} +{{- end }} diff --git a/charts/policy-reporter/templates/ui/serviceaccount.yaml b/charts/policy-reporter/templates/ui/serviceaccount.yaml new file mode 100644 index 0000000000..2cb124202f --- /dev/null +++ b/charts/policy-reporter/templates/ui/serviceaccount.yaml @@ -0,0 +1,16 @@ +{{- if .Values.ui.enabled -}} +{{- if .Values.ui.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "ui.serviceAccountName" . }} + namespace: {{ include "policyreporter.namespace" . }} + labels: + {{- include "ui.labels" . | nindent 4 }} + {{- with .Values.ui.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.ui.serviceAccount.automount }} +{{- end }} +{{- end }} diff --git a/charts/policy-reporter/values.yaml b/charts/policy-reporter/values.yaml new file mode 100644 index 0000000000..6ca92ae4d2 --- /dev/null +++ b/charts/policy-reporter/values.yaml @@ -0,0 +1,1856 @@ +# -- Override the chart name used for all resources +nameOverride: "" + +# -- Overwrite the fullname of all resources +fullnameOverride: "policy-reporter" + +# -- Overwrite the namespace of all resources +namespaceOverride: "" + +image: + # -- (string) Image registry + registry: ghcr.io + # -- (string) Image repository + repository: kyverno/policy-reporter + # -- (string) Image pullPolicy + pullPolicy: IfNotPresent + # -- (string) Image tag + tag: ~ + +# -- Image pullSecrets +imagePullSecrets: [] + +# -- Deployment priorityClassName +priorityClassName: "" + +# -- Deployment replica count +replicaCount: 1 + +# -- The number of revisions to keep +revisionHistoryLimit: 10 + +# -- Deployment strategy +updateStrategy: {} + # rollingUpdate: + # maxSurge: 25% + # maxUnavailable: 25% + # type: RollingUpdate + +# -- Container port +port: + name: http + number: 8080 + +# -- Key/value pairs that are attached to all resources. +annotations: {} + +rbac: + # -- Create RBAC resources + enabled: true + +serviceAccount: + # -- Create ServiceAccount + create: true + # -- Enable ServiceAccount automount + automount: true + # -- Annotations for the ServiceAccount + annotations: {} + # -- The ServiceAccount name + name: "" + +service: + # -- Create Service + enabled: true + # -- Service type + type: ClusterIP + # -- Service port + port: 8080 + # -- Service annotations + annotations: {} + # -- Service labels + labels: {} + +# -- Security context for the pod +podSecurityContext: + fsGroup: 1234 + +securityContext: + runAsUser: 1234 + runAsNonRoot: true + privileged: false + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + +# -- Additional annotations to add to each pod +podAnnotations: {} + +# -- Additional labels to add to each pod +podLabels: {} + +# -- Resource constraints +resources: {} + # limits: + # memory: 100Mi + # cpu: 10m + # requests: + # memory: 75Mi + # cpu: 5m + +networkPolicy: + # -- Create NetworkPolicy + enabled: false + # -- Egress rule to allow Kubernetes API Server access + egress: + - to: + ports: + - protocol: TCP + port: 6443 + ingress: [] + +ingress: + # -- Create Ingress + # This ingress exposes the policy-reporter core app. + enabled: false + # -- Ingress className + className: "" + # -- Labels for the Ingress + labels: {} + # -- Annotations for the Ingress + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # -- Ingress host list + hosts: + # - host: chart-example.local + # paths: [] + # -- Ingress tls list + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + +logging: + # -- Enables server access logging + server: false + # -- Log encoding + # possible encodings are console and json + encoding: console + # -- Log level + # default info + logLevel: 0 + +rest: + # -- Enables the REST API + enabled: false + +metrics: + # -- Enables Prometheus Metrics + enabled: false + # -- Metric Mode allows to customize labels + # Allowed values: detailed, simple, custom + mode: detailed + # -- List of used labels in custom mode + # Supported fields are: ["namespace", "rule", "policy", "report" // Report name, "kind" // resource kind, "name" // resource name, "status", "severity", "category", "source"] + customLabels: [] + # -- Filter results to reduce cardinality + filter: {} +# sources: +# exclude: ["Trivy CIS Kube Bench"] +# status: +# exclude: ["pass", "skip"] + +profiling: + # -- Enable profiling with pprof + enabled: false + +# -- Amount of queue workers for Report resource processing +worker: 5 + +# -- Filter Report resources to process +reportFilter: {} + # # -- Filter reports based on an namespace allow- or disallow list, wildcards are supported + # namespaces: + # include: [] + # exclude: [] + # # -- Disable the processing of cluster scoped Reports + # disableClusterReports: false + +# -- Customize source specific logic like result ID generation +sourceConfig: [] +# - selector: +# source: kyverno +# customId: +# enabled: true +# fields: ["resource", "policy", "rule", "category", "result", "message"] + +# Source based Report filter +sourceFilters: + - selector: + # -- select Report by source + source: kyverno + # -- Filter out Reports of controlled Pods and Jobs, only works for Reports with scope resource + uncontrolledOnly: true + # -- Filter out cluster scoped Reports + disableClusterReports: false + # -- Filter out Reports based on the scope resource kind + kinds: + exclude: [ReplicaSet] + - selector: + # -- select Report by source + source: KyvernoValidatingPolicy + # -- Filter out Reports of controlled Pods and Jobs, only works for Reports with scope resource + uncontrolledOnly: true + # -- Filter out cluster scoped Reports + disableClusterReports: false + # -- Filter out Reports based on the scope resource kind + kinds: + exclude: [ReplicaSet] + +global: + # -- additional labels added on each resource + labels: {} + +# basicAuth for APIs and metrics +basicAuth: + # -- HTTP BasicAuth username + username: "" + # -- HTTP BasicAuth password + password: "" + # -- (optional) Secret reference to get username and/or password from + secretRef: "" + +emailReports: + # -- (optional) - Displayed in the email report if configured + clusterName: "" + # -- Title prefix in the email subject + titlePrefix: "Report" + # -- Resource constraints for the created CronJobs + resources: {} + smtp: + # -- (optional) Secret reference to provide the complete or partial SMTP configuration + secret: "" + # -- SMTP Server Host + host: "" + # -- SMTP Server Port + port: 465 + # -- SMTP Username + username: "" + # -- SMTP Password + password: "" + # -- Displayed from email address + from: "" + # -- SMTP Encryption + # Default is none, supports ssl/tls and starttls + encryption: "" + # -- Skip SMTP TLS verification + skipTLS: false + # -- SMTP Server Certificate file path + certificate: "" + + summary: + # -- Enable Summary E-Mail reports + enabled: false + # -- CronJob schedule + schedule: "0 8 * * *" + # -- CronJob activeDeadlineSeconds + activeDeadlineSeconds: 300 + # -- CronJob backoffLimit + backoffLimit: 3 + # -- CronJob ttlSecondsAfterFinished + ttlSecondsAfterFinished: 0 + # -- CronJob restartPolicy + restartPolicy: Never + # -- List of receiver email addresses + to: [] + # -- (optional) Report filter + filter: {} + # # remove ClusterPolicyResults from Reports + # disableClusterReports: false + # namespaces: + # include: [] + # exclude: [] + # sources: + # include: [] + # exclude: [] + # -- (optional) Channels can be used to to send only a subset of namespaces / sources to dedicated email addresses + channels: [] + # - to: ['team-a@company.org'] + # filter: + # disableClusterReports: true + # namespaces: + # include: ['team-a-*'] + # sources: + # include: ['Kyverno'] + + violations: + # -- Enable Violation Summary E-Mail reports + enabled: false + # -- CronJob schedule + schedule: "0 8 * * *" + # -- CronJob activeDeadlineSeconds + activeDeadlineSeconds: 300 + # -- CronJob backoffLimit + backoffLimit: 3 + # -- CronJob ttlSecondsAfterFinished + ttlSecondsAfterFinished: 0 + # -- CronJob restartPolicy + restartPolicy: Never + # -- List of receiver email addresses + to: [] + # -- (optional) Report filter + filter: {} + # disableClusterReports: false # remove ClusterPolicyResults from Reports + # namespaces: + # include: [] + # exclude: [] + # sources: + # include: [] + # exclude: [] + # -- (optional) Channels can be used to to send only a subset of namespaces / sources to dedicated email addresses + channels: [] + # - to: ['team-a@company.org'] + # filter: + # disableClusterReports: true + # namespaces: + # include: ['team-a-*'] + # sources: + # include: ['Kyverno'] + +existingTargetConfig: + # -- Use an already existing configuration + enabled: false + # -- Name of the secret with the config + name: "" + # -- SubPath within the secret (defaults to config.yaml) + subPath: "" + +target: + # -- enable and install TargetConfig CRD + crd: false + loki: + # -- Host Address + host: "" + # -- Loki API, defaults to "/loki/api/v1/push" + path: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Additional HTTP Headers + headers: {} + # -- HTTP BasicAuth username + username: "" + # -- HTTP BasicAuth password + password: "" + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} +# namespaces: +# include: ["develop"] +# priorities: +# exclude: ["debug", "info", "error"] +# labels: +# include: ["app", "owner:team-a", "monitoring:*"] + # -- List of channels to route results to different configurations + channels: [] +# - host: "http://loki.loki-stack:3100" +# sources: [] +# customLabels: {} +# filter: +# namespaces: +# include: ["develop"] +# priorities: +# exclude: ["debug", "info", "error"] +# reportLabels: +# . include: ["app", "owner:team-b"] + + elasticsearch: + # -- Host address + host: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Elasticsearch index (default: policy-reporter) + index: "policy-reporter" + # -- Elasticsearch index rotation and index suffix + # Possible values: daily, monthly, annually, none (default: daily) + rotation: "daily" + # -- Enables Elasticsearch typless API + # https://www.elastic.co/blog/moving-from-types-to-typeless-apis-in-elasticsearch-7-0 keeping as false for retrocompatibility. + typelessApi: false + # -- HTTP BasicAuth username + username: "" + # -- HTTP BasicAuth password + password: "" + # -- Elasticsearch API Key for api key authentication + apiKey: "" + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + slack: + # -- Webhook Address + webhook: "" + # -- Slack Channel + channel: "" + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] +# - webhook: "https://slack.webhook1" +# channel: "" +# filter: +# namespaces: +# include: ["develop"] +# priorities: +# exclude: ["debug", "info", "error"] +# policies: +# include: ["require-run-as-nonroot"] +# reportLabels: +# . include: ["app", "owner:team-b"] +# - webhook: "https://slack.webhook2" +# minimumSeverity: "warning" +# filter: +# namespaces: +# include: ["team-a-*"] + + discord: + # -- Webhook Address + webhook: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + teams: + # -- Webhook Address + webhook: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + webhook: + # -- Webhook Address + webhook: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Keepalive configuration + keepalive: + # -- Duration string like "30s" for heartbeat interval, '0' - disabled + interval: "0" + # -- Additional parameters to include in heartbeat payload + params: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + telegram: + # -- Telegram bot token + token: "" + # -- Telegram chat id + chatId: "" + # -- (optional) Telegram proxy host + host: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + googleChat: + # -- Webhook Address + webhook: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + jira: + # -- JIRA server URL + host: "" + # -- JIRA username + username: "" + # -- JIRA password (use password or apiToken, not both) + password: "" + # -- JIRA API token (use password or apiToken, not both) + apiToken: "" + # -- JIRA static labels + apiVersion: "v3" + # -- JIRA project key + projectKey: "" + # -- JIRA issue type (default: "Bug") + issueType: "" + # -- JIRA component names list + components: [] + # -- JIRA static labels + labels: [] + # -- JIRA summary go template, available values: result, customfield + # default: "{{ if result.ResourceString }}{{ result.ResourceString }}: {{ end }}Policy Violation: {{ result.Policy }}" + summaryTemplate: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + alertManager: + # -- host address + host: "" + # -- Server Certificate file path + # Can be added under extraVolumes + certificate: "" + # -- Skip TLS verification + skipTLS: false + # -- Additional HTTP Headers + headers: {} + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing PolicyReportResults on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + # Authentication via PodIdentity or WebIdentity are also supported + s3: + # -- (optional) S3 Access key + accessKeyId: "" + # -- (optional) S3 SecretAccess key + secretAccessKey: "" + # -- (optional) S3 Storage region + region: "" + # -- (optional) S3 Storage endpoint + endpoint: "" + # -- (required) S3 Storage bucket name + bucket: "" + # -- S3 Storage to use an S3 Bucket Key for object encryption with SSE-KMS + bucketKeyEnabled: false + # -- S3 Storage KMS Key ID for object encryption with SSE-KMS + kmsKeyId: "" + # -- S3 Storage server-side encryption algorithm used when storing this object in Amazon S3, AES256, aws:kms + serverSideEncryption: "" + # -- S3 Storage, force path style configuration + pathStyle: false + # -- Used prefix, keys will have format: s3:////YYYY-MM-DD/YYYY-MM-DDTHH:mm:ss.s+01:00.json + prefix: "" + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + # Authentication via PodIdentity or WebIdentity are also supported + kinesis: + # -- (optional) Access key + accessKeyId: "" + # -- (optional) SecretAccess key + secretAccessKey: "" + # -- (optional) Region + region: "" + # -- (optional) Endpoint + endpoint: "" + # -- (required) StreamName + streamName: "" + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + # Authentication via PodIdentity or WebIdentity are also supported + securityHub: + # -- (optional) Access key + accessKeyId: "" + # -- (optional) SecretAccess key + secretAccessKey: "" + # -- (optional) Region + region: "" + # -- (optional) Endpoint + endpoint: "" + # -- (required) AccountId + accountId: "" + # -- (optional) Used product name, defaults to "Polilcy Reporter" + productName: "" + # -- (optional) Used company name, defaults to "Kyverno" + companyName: "" + # -- Enable cleanup listener for SecurityHub + synchronize: true + # -- Delay between AWS GetFindings API calls, to avoid hitting the API RequestLimit + delayInSeconds: 2 + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + + # Authentication via PodIdentity is also supported + gcs: + # -- (optional) GCS (Google Cloud Storage) Service Account Credentials + credentials: "" + # -- (required) GCS Bucket + bucket: "" + # -- Read configuration from an already existing Secret + secretRef: "" + # -- Mounted secret path by Secrets Controller, secret should be in json format + mountedSecret: "" + # -- Minimum severity: "" < info < low < medium < high < critical + minimumSeverity: "" + # -- List of sources which should send + sources: [] + # -- Skip already existing report results on startup + skipExistingOnStartup: true + # -- Added as additional labels + customFields: {} + # -- Filter Results which should send to this target + # Wildcars for namespaces and policies are supported, you can either define exclude or include values + # Filters are available for all targets except the UI + filter: {} + # -- List of channels to route results to different configurations + channels: [] + +# LeaderElection configuration for HA mode +# will be enabled when replicaCount > 1 +leaderElection: + releaseOnCancel: true + leaseDuration: 15 + renewDeadline: 10 + retryPeriod: 2 + +redis: + # -- Enables Redis as external result cache, uses in memory cache by default + enabled: false + # -- Redis host + address: "" + # -- Redis database + database: 0 + # -- Redis key prefix + prefix: "policy-reporter" + # -- (optional) Username + username: "" + # -- (optional) Password + password: "" + +database: + # -- Use an external Database, supported: mysql, postgres, mariadb + type: "" + # -- Database + database: "" + # -- Username + username: "" + # -- Password + password: "" + # -- Host Address + host: "" + # -- Enables SSL + 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: "" + # -- Read configuration from an existing Secret + # supported fields: username, password, host, dsn, database + secretRef: "" + # Read configuration from a mounted Secret, 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. + # Cannot be used if `maxUnavailable` is set. + minAvailable: 1 + # -- Configures the maximum unavailable pods for policy-reporter disruptions. + # Cannot be used if `minAvailable` is set. + maxUnavailable: + +# -- Node labels for pod assignment +# ref: https://kubernetes.io/docs/user-guide/node-selection/ +nodeSelector: {} + +# -- Tolerations for pod assignment +# ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/ +tolerations: [] + +# -- Anti-affinity to disallow deploying client and master nodes on the same worker node +affinity: {} + +# -- Topology Spread Constraints to better spread pods +topologySpreadConstraints: [] + +# -- Deployment livenessProbe for policy-reporter +livenessProbe: + httpGet: + path: /ready + port: http + +# -- Deployment readinessProbe for policy-reporter +readinessProbe: + httpGet: + path: /healthz + port: http + +extraVolumes: + # -- Deployment volumeMounts + volumeMounts: [] + + # -- Deployment values + volumes: [] + +# -- If set the volume for sqlite is freely configurable below "- name: sqlite". If no value is set an emptyDir is used. +sqliteVolume: {} + # emptyDir: + # sizeLimit: 10Mi + +# -- Allow additional env variables to be added +envVars: [] + +# -- Allow custom configuration of the /tmp volume +tmpVolume: {} + +ui: + # -- (bool) Enable Policy Reporter UI + enabled: false + image: + # -- (string) Image registry + registry: ghcr.io + # -- (string) Image repository + repository: kyverno/policy-reporter-ui + # -- (string) Image PullPolicy + pullPolicy: IfNotPresent + # -- (string) Image tag + tag: "2.4.1" + + # -- Deployment replica count + replicaCount: 1 + + # -- Deployment priorityClassName + priorityClassName: "" + + logging: + # -- Enables external api request logging + api: false + # -- Enables server access logging + server: false + # -- Log encoding + # possible encodings are console and json + encoding: console + # -- Log level + # default info + logLevel: 0 + + server: + # -- Application port + port: 8080 + # -- Enabled CORS header + cors: true + # -- Overwrites Request Host with Proxy Host and adds `X-Forwarded-Host` and `X-Origin-Host` headers + overwriteHost: true + # -- session configuration + sessions: + storage: filesystem + tempDir: /tmp + + openIDConnect: + # -- Enable openID Connect authentication + enabled: false + # -- OpenID Connect Discovery URL + discoveryUrl: "" + # -- OpenID Connect Callback URL + callbackUrl: "" + # -- OpenID Connect ClientID + clientId: "" + # -- OpenID Connect ClientSecret + clientSecret: "" + # -- Optional Group Claim to map user groups to the profile + # groups can be used to define access control for clusters, boards and custom boards. + groupClaim: "" + # -- OpenID Connect allowed Scopes + scopes: [] + # -- Skip TLS Verification + skipTLS: false + # -- TLS Certificate file path + certificate: "" + # -- Secret to rea + # -- Provide OpenID Connect configuration via Secret + # supported keys: `discoveryUrl`, `clientId`, `clientSecret`, `certificate`, `skipTLS` + secretRef: "" + + oauth: + # -- Enable openID Connect authentication + enabled: false + # -- OAuth2 Provider + # supported: amazon, gitlab, github, apple, google, yandex, azuread + provider: "" + # -- OpenID Connect Callback URL + callbackUrl: "" + # -- OpenID Connect ClientID + clientId: "" + # -- OpenID Connect ClientSecret + clientSecret: "" + # -- OpenID Connect allowed Scopes + scopes: [] + # -- Provide OpenID Connect configuration via Secret + # supported keys: `provider`, `clientId`, `clientSecret` + secretRef: "" + + # -- optional banner text + banner: "" + + logo: + # -- custom logo path + path: "" + # -- disable logo entirely + disabled: false + + # -- DisplayMode dark/light/colorblind/colorblinddark + # uses the OS configured preferred color scheme as default + displayMode: "" + + # -- Configure access control for all default boards. + boards: {} + # accessControl: + # groups: [] + # emails: [] + + # -- Additional customizable dashboards + customBoards: [] + # - name: Team A + # namespaces: + # # -- list of displayed namespaces + # list: [] + # # -- selector for displayed namespaces + # selector: + # team: team-a # equal + # workload: * # label exists + # infra: !* # label does not exist + # env: dev,test # label value is one of [dev, test] + # sources: + # # -- list of displayed sources + # list: [] + # clusterScope: + # # -- display cluster scoped resources and results + # enabled: false + # display: "" + # filter: + # include: + # results: [] + # severities: [] + # clusterKinds: [] + # namespaceKinds: [] + + # -- source specific configurations + sources: [] + # -- kyverno specific UI configurations + # - name: kyverno + # -- show results per category, other option: severity + # type: result + # -- enabled action button to generate PolicyExceptions from the UI + # exceptions: false + # -- exclude results or (cluster)kinds per source + # excludes: + # results: + # - warn + # - error + + ## -- Default Cluster name + name: Default + + # -- Connected Policy Reporter APIs + clusters: [] + # - name: default + # host: http://policy-reporter:8080 + # secretRef: "" + # skipTLS: false + # certificate: "" + # plugins: + # - name: kyverno + # host: http://policy-reporter-kyverno-plugin:8080 + + # -- Image pull secrets for image verification policies, this will define the `--imagePullSecrets` argument + imagePullSecrets: [] + # regcred: + # registry: foo.example.com + # username: foobar + # password: secret + + serviceAccount: + # -- Create ServiceAccount + create: true + # -- Enable ServiceAccount automount + automount: true + # -- Annotations for the ServiceAccount + annotations: {} + # -- The ServiceAccount name + name: "" + + + # -- Add sidecar containers to the UI deployment + # sidecarContainers: + # oauth-proxy: + # image: quay.io/oauth2-proxy/oauth2-proxy:v7.6.0 + # args: + # - --upstream=http://127.0.0.1:8080 + # - --http-address=0.0.0.0:8081 + # - ... + # ports: + # - containerPort: 8081 + # name: oauth-proxy + # protocol: TCP + # resources: {} + sidecarContainers: {} + + # -- Additional annotations to add to each pod + podAnnotations: {} + + # -- Additional labels to add to each pod + podLabels: {} + + # -- Deployment update strategy. + # Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + updateStrategy: {} + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 40% + # type: RollingUpdate + + # -- The number of revisions to keep + revisionHistoryLimit: 10 + + # -- Security context for the pod + podSecurityContext: + runAsUser: 1234 + runAsGroup: 1234 + + # -- Allow additional env variables to be added + envVars: [] + + rbac: + # -- Create RBAC resources + enabled: true + + securityContext: + runAsUser: 1234 + runAsNonRoot: true + privileged: false + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + + # -- Deployment livenessProbe for policy-reporter-ui + livenessProbe: + httpGet: + path: /healthz + port: http + + # -- Deployment readinessProbe for policy-reporter-ui + readinessProbe: + httpGet: + path: /healthz + port: http + + service: + # -- Service type. + type: ClusterIP + # -- Service port. + port: 8080 + # -- Service annotations. + annotations: {} + # -- Service labels. + labels: {} + # -- Additional service ports for e.g. Sidecars # - name: authenticated + # additionalPorts: + # - name: authenticated + # port: 8081 + # targetPort: 8081 + additionalPorts: [] + + ingress: + # -- Create ingress resource. + enabled: false + # -- Redirect ingress to an additional defined port on the service + port: null + # -- Ingress class name. + className: "" + # -- Ingress labels. + labels: {} + # -- Ingress annotations. + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # -- List of ingress host configurations. + hosts: [] + # - host: chart-example.local + # paths: + # - path: / + # pathType: ImplementationSpecific + # -- List of ingress TLS configurations. + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + networkPolicy: + # -- When true, use a NetworkPolicy to allow ingress to the webhook + # This is useful on clusters using Calico and/or native k8s network policies in a default-deny setup. + enabled: false + # -- A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. + # Enables Kubernetes API Server by default + egress: + - ports: + - protocol: TCP + port: 6443 + # -- A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. + ingress: [] + + # -- Resource constraints + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + # enabled if replicaCount > 1 + podDisruptionBudget: + # -- Configures the minimum available pods for kyvernoPlugin disruptions. + # Cannot be used if `maxUnavailable` is set. + minAvailable: 1 + # -- Configures the maximum unavailable pods for kyvernoPlugin disruptions. + # Cannot be used if `minAvailable` is set. + maxUnavailable: + + # -- Node labels for pod assignment + nodeSelector: {} + + # -- List of node taints to tolerate + tolerations: [] + + # -- Affinity constraints. + affinity: {} + + extraVolumes: + # -- Deployment volumeMounts + volumeMounts: [] + + # -- Deployment values + volumes: [] + + # -- Extra configuration options appended to UI settings + extraConfig: {} + +plugin: + kyverno: + # -- (bool) Enable Kyverno Plugin + enabled: false + image: + # -- (string) Image registry + registry: ghcr.io + # -- (string) Image repository + repository: kyverno/policy-reporter/kyverno-plugin + # -- (string) Image PullPolicy + pullPolicy: IfNotPresent + # -- (string) Image tag + tag: "0.5.0" + + # -- Deployment replica count + replicaCount: 1 + + # -- Deployment priorityClassName + priorityClassName: "" + + logging: + # -- Enables external API request logging + api: false + # -- Enables Server access logging + server: false + # -- log encoding + # possible encodings are console and json + encoding: console + # -- log level + # default info + logLevel: 0 + + server: + # -- Application port + port: 8080 + + blockReports: + # -- Enables he BlockReport feature + enabled: false + # -- Watches for Kyverno Events in the configured namespace + # leave blank to watch in all namespaces + eventNamespace: default + # -- Used value for the source field in the created (Cluster)PolicyReports + source: Kyverno Event + results: + # -- Max items per PolicyReport resource + maxPerReport: 200 + # -- Keep only the latest of duplicated events + keepOnlyLatest: false + policyReport: + # -- Labels for all created (Cluster)PolicyReports + labels: [] + # -- Annotations for all created (Cluster)PolicyReports + annotations: [] + + # -- Image pull secrets for image verification policies, this will define the `--imagePullSecrets` argument + imagePullSecrets: [] + # regcred: + # registry: foo.example.com + # username: foobar + # password: secret + + serviceAccount: + # -- Create ServiceAccount + create: true + # -- Enable ServiceAccount automount + automount: true + # -- Annotations for the ServiceAccount + annotations: {} + # -- The ServiceAccount name + name: "" + + # -- Additional annotations to add to each pod + podAnnotations: {} + + # -- Additional labels to add to each pod + podLabels: {} + + # -- Deployment update strategy. + # Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + updateStrategy: {} + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 40% + # type: RollingUpdate + + # -- The number of revisions to keep + revisionHistoryLimit: 10 + + # -- Security context for the pod + podSecurityContext: + runAsUser: 1234 + runAsGroup: 1234 + + # -- Allow additional env variables to be added + envVars: [] + + rbac: + # -- Create RBAC resources + enabled: true + + securityContext: + runAsUser: 1234 + runAsNonRoot: true + privileged: false + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + + service: + # -- Service type. + type: ClusterIP + # -- Service port. + port: 8080 + # -- Service annotations. + annotations: {} + # -- Service labels. + labels: {} + + ingress: + # -- Create ingress resource. + enabled: false + # -- Ingress class name. + className: "" + # -- Ingress labels. + labels: {} + # -- Ingress annotations. + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # -- List of ingress host configurations. + hosts: [] + # - host: chart-example.local + # paths: + # - path: / + # pathType: ImplementationSpecific + # -- List of ingress TLS configurations. + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + networkPolicy: + # -- When true, use a NetworkPolicy to allow ingress to the webhook + # This is useful on clusters using Calico and/or native k8s network policies in a default-deny setup. + enabled: false + # -- A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. + # Enables Kubernetes API Server by default + egress: + - ports: + - protocol: TCP + port: 6443 + # -- A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. + ingress: [] + + # -- Resource constraints + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + # required for HA mode + # if "blockReports" is disabled, leaderElection is also disabled automatically + # will be enabled when replicaCount > 1 + leaderElection: + # -- Lock Name + lockName: kyverno-plugin + # -- Released lock when the run context is cancelled. + releaseOnCancel: true + # -- LeaseDuration is the duration that non-leader candidates will wait to force acquire leadership. + leaseDuration: 15 + # -- RenewDeadline is the duration that the acting master will retry refreshing leadership before giving up. + renewDeadline: 10 + # -- RetryPeriod is the duration the LeaderElector clients should wait between tries of actions. + retryPeriod: 2 + + # enabled if replicaCount > 1 + podDisruptionBudget: + # -- Configures the minimum available pods for kyvernoPlugin disruptions. + # Cannot be used if `maxUnavailable` is set. + minAvailable: 1 + # -- Configures the maximum unavailable pods for kyvernoPlugin disruptions. + # Cannot be used if `minAvailable` is set. + maxUnavailable: + + # -- Node labels for pod assignment + nodeSelector: {} + + # -- List of node taints to tolerate + tolerations: [] + + # -- Affinity constraints. + affinity: {} + + # -- Pod Topology Spread Constraints for the kyverno plugin. + topologySpreadConstraints: {} + + extraVolumes: + # -- Deployment volumeMounts + volumeMounts: [] + + # -- Deployment values + volumes: [] + + # -- Extra configuration options appended to kyverno plugin settings + extraConfig: {} + + trivy: + # -- (bool) Enable Trivy Operator Plugin + enabled: false + image: + # -- (string) Image registry + registry: ghcr.io + # -- (string) Image repository + repository: kyverno/policy-reporter/trivy-plugin + # -- (string) Image PullPolicy + pullPolicy: IfNotPresent + # -- (string) Image tag + # Defaults to `Chart.AppVersion` if omitted + tag: "0.4.9" + + cli: + image: + # -- (string) Image registry + registry: ghcr.io + # -- (string) Image repository + repository: aquasecurity/trivy + # -- (string) Image PullPolicy + pullPolicy: IfNotPresent + # -- (string) Image tag + # Defaults to `Chart.AppVersion` if omitted + tag: "0.63.0" + + # -- Additional container args. + extraArgs: {} + + cveawg: + # -- (bool) disable external CVEAWG API calls. + disable: false + + github: + # -- (bool) disable GitHub API calls. + disable: false + # -- (string) optional github token for authenticated GitHub API calls. + token: "" + + # -- If set the volume for dbVolume is freely configurable below "- name: dbVolume". If no value is set an emptyDir is used. + dbVolume: {} + # emptyDir: + # sizeLimit: 10Mi + + # -- If set the volume for tmpVolume is freely configurable below "- name: tmpVolume". If no value is set an emptyDir is used. + tmpVolume: {} + # emptyDir: + # sizeLimit: 10Mi + + # -- Deployment replica count + replicaCount: 1 + + # -- Deployment priorityClassName + priorityClassName: "" + + logging: + # -- Enables external API request logging + api: false + # -- Enables Server access logging + server: false + # -- log encoding + # possible encodings are console and json + encoding: console + # -- log level + # default info + logLevel: 0 + + server: + # -- Application port + port: 8080 + + policyReporter: + # -- Skip TLS Verification + skipTLS: false + # -- TLS Certificate file path + certificate: "" + # -- Secret to read the API configuration from + # supports `host`, `certificate`, `skipTLS`, `username`, `password` key + secretRef: "" + + # -- Image pull secrets for image verification policies, this will define the `--imagePullSecrets` argument + imagePullSecrets: [] + # regcred: + # registry: foo.example.com + # username: foobar + # password: secret + + serviceAccount: + # -- Create ServiceAccount + create: true + # -- Enable ServiceAccount automount + automount: true + # -- Annotations for the ServiceAccount + annotations: {} + # -- The ServiceAccount name + name: "" + + # -- Additional annotations to add to each pod + podAnnotations: {} + + # -- Additional labels to add to each pod + podLabels: {} + + # -- Deployment update strategy. + # Ref: https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#strategy + updateStrategy: {} + # rollingUpdate: + # maxSurge: 1 + # maxUnavailable: 40% + # type: RollingUpdate + + # -- The number of revisions to keep + revisionHistoryLimit: 10 + + # -- Security context for the pod + podSecurityContext: + runAsUser: 1234 + runAsGroup: 1234 + + # -- Deployment livenessProbe for policy-reporter-trivy-plugin + livenessProbe: + timeoutSeconds: 3 + httpGet: + path: /vulnr/v1/policies + port: http + + # -- Deployment readinessProbe for policy-reporter-trivy-plugin + readinessProbe: + timeoutSeconds: 3 + httpGet: + path: /vulnr/v1/policies + port: http + + # -- Allow additional env variables to be added + envVars: [] + + rbac: + # -- Create RBAC resources + enabled: true + + securityContext: + runAsUser: 1234 + runAsNonRoot: true + privileged: false + allowPrivilegeEscalation: false + readOnlyRootFilesystem: true + capabilities: + drop: + - ALL + seccompProfile: + type: RuntimeDefault + + service: + # -- Service type. + type: ClusterIP + # -- Service port. + port: 8080 + # -- Service annotations. + annotations: {} + # -- Service labels. + labels: {} + + ingress: + # -- Create ingress resource. + enabled: false + # -- Ingress class name. + className: "" + # -- Ingress labels. + labels: {} + # -- Ingress annotations. + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + # -- List of ingress host configurations. + hosts: [] + # - host: chart-example.local + # paths: + # - path: / + # pathType: ImplementationSpecific + # -- List of ingress TLS configurations. + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local + + networkPolicy: + # -- When true, use a NetworkPolicy to allow ingress to the webhook + # This is useful on clusters using Calico and/or native k8s network policies in a default-deny setup. + enabled: false + # -- A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. + # Enables Kubernetes API Server by default + egress: + - ports: + - protocol: TCP + port: 6443 + # -- A list of valid from selectors according to https://kubernetes.io/docs/concepts/services-networking/network-policies. + ingress: [] + + # -- Resource constraints + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + # enabled if replicaCount > 1 + podDisruptionBudget: + # -- Configures the minimum available pods for kyvernoPlugin disruptions. + # Cannot be used if `maxUnavailable` is set. + minAvailable: 1 + # -- Configures the maximum unavailable pods for kyvernoPlugin disruptions. + # Cannot be used if `minAvailable` is set. + maxUnavailable: + + # -- Node labels for pod assignment + nodeSelector: {} + + # -- List of node taints to tolerate + tolerations: [] + + # -- Affinity constraints. + affinity: {} + + # -- Pod Topology Spread Constraints for the trivy plugin. + topologySpreadConstraints: {} + + extraVolumes: + # -- Deployment volumeMounts + volumeMounts: [] + + # -- Deployment values + volumes: [] + + # -- Extra configuration options appended to trivy plugin settings + extraConfig: {} + +monitoring: + # -- Enables the Prometheus Operator integration + enabled: false + + # -- Key/value pairs that are attached to all resources. + annotations: {} + + serviceMonitor: + # -- HonorLabels chooses the metrics labels on collisions with target labels + honorLabels: false + # -- Allow to override the namespace for serviceMonitor + namespace: + # -- Labels to match the serviceMonitorSelector of the Prometheus Resource + labels: {} + # -- ServiceMonitor Relabelings + # https://github.com/prometheus-operator/prometheus-operator/blob/main/Documentation/api.md#relabelconfig + relabelings: [] + # -- See serviceMonitor.relabelings + metricRelabelings: [] + # -- (optional) NamespaceSelector + namespaceSelector: {} + # -- (optional) ScrapeTimeout + scrapeTimeout: + # -- (optional) Scrape interval + interval: + + grafana: + # -- Naamespace for configMap of grafana dashboards + namespace: + dashboards: + # -- Enable the deployment of grafana dashboards + enabled: true + # -- Label to find dashboards using the k8s sidecar + label: grafana_dashboard + # -- Label value to find dashboards using the k8s sidecar + value: "1" + # -- List of custom label filter + # Used to add filter for report label based metric labels defined in custom mode + labelFilter: [] + multicluster: + # -- Enable cluster filter in all dashboards + enabled: false + # -- Metric Label which is used to filter clusters + label: cluster + enable: + # -- Enable the Overview Dashboard + overview: true + # -- Enable the PolicyReport Dashboard + policyReportDetails: true + # -- Enable the ClusterPolicyReport Dashboard + clusterPolicyReportDetails: true + folder: + # -- Annotation to enable folder storage using the k8s sidecar + annotation: grafana_folder + # -- Grafana folder in which to store the dashboards + name: Policy Reporter + datasource: + # -- Grafana Datasource Label + label: Prometheus + # -- Grafana Datasource PluginId + pluginId: prometheus + # -- Grafana Datasource PluginName + pluginName: Prometheus + + grafanaDashboard: + # -- Create GrafanaDashboard custom resource referencing to the configMap. + # according to https://grafana-operator.github.io/grafana-operator/docs/examples/dashboard_from_configmap/readme/ + enabled: false + # -- Dashboard folder + folder: kyverno + # -- Allow cross Namespace import + allowCrossNamespaceImport: true + # -- Label match selector + matchLabels: + dashboards: "grafana" + + # Customize the Grafana PolicyReport Dashboard + policyReportDetails: + firstStatusRow: + height: 8 + secondStatusRow: + enabled: true + height: 2 + statusTimeline: + enabled: true + height: 8 + passTable: + enabled: true + height: 8 + failTable: + enabled: true + height: 8 + warningTable: + enabled: true + height: 4 + errorTable: + enabled: true + height: 4 + + # Customize the Grafana ClusterPolicyReport Dashboard + clusterPolicyReportDetails: + statusRow: + height: 6 + statusTimeline: + enabled: true + height: 8 + passTable: + enabled: true + height: 8 + failTable: + enabled: true + height: 8 + warningTable: + enabled: true + height: 4 + errorTable: + enabled: true + height: 4 + + # Customize the Grafana Overview Dashboard + policyReportOverview: + failingSummaryRow: + height: 8 + failingTimeline: + height: 10 + failingPolicyRuleTable: + height: 10 + failingClusterPolicyRuleTable: + height: 10 + +# -- list of extra manifests +extraManifests: [] + +# -- Extra configuration options appended to core policy reporter +extraConfig: {} diff --git a/core.yaml b/core.yaml index 831683118b..86602344eb 100644 --- a/core.yaml +++ b/core.yaml @@ -116,6 +116,10 @@ k8s: app: velero disablePolicyChecks: true disableIstioInjection: true + - name: policy-reporter + app: policy-reporter + disablePolicyChecks: true + disableIstioInjection: true adminApps: - name: alertmanager diff --git a/helmfile.d/helmfile-01.init.yaml.gotmpl b/helmfile.d/helmfile-01.init.yaml.gotmpl index 1c9ecdac85..3fe7b17f71 100644 --- a/helmfile.d/helmfile-01.init.yaml.gotmpl +++ b/helmfile.d/helmfile-01.init.yaml.gotmpl @@ -22,6 +22,10 @@ releases: labels: pkg: kyverno <<: *raw + - name: policy-reporter + installed: {{ $a | get "policy-reporter.enabled" }} + namespace: policy-reporter + <<: *default - name: sealed-secrets installed: {{ $a | get "sealed-secrets.enabled" }} namespace: sealed-secrets diff --git a/helmfile.d/snippets/defaults.yaml b/helmfile.d/snippets/defaults.yaml index feb291b94b..3a4d7929cf 100644 --- a/helmfile.d/snippets/defaults.yaml +++ b/helmfile.d/snippets/defaults.yaml @@ -595,7 +595,7 @@ environments: kubeflow-pipelines: enabled: false persistence: - mysql: + mysql: size: 20Gi resources: cacheDeployer: @@ -734,6 +734,16 @@ environments: cpu: "1" memory: 512Mi _rawValues: {} + policy-reporter: + enabled: false + resources: + requests: + cpu: 100m + memory: 128Mi + limits: + cpu: "1" + memory: 512Mi + _rawValues: {} tekton: resources: dashboard: diff --git a/tests/fixtures/env/apps/policy-reporter.yaml b/tests/fixtures/env/apps/policy-reporter.yaml new file mode 100644 index 0000000000..51aea3ad10 --- /dev/null +++ b/tests/fixtures/env/apps/policy-reporter.yaml @@ -0,0 +1,7 @@ +kind: AplApp +metadata: + name: policy-reporter + labels: {} +spec: + enabled: false + _rawValues: {} diff --git a/values-schema.yaml b/values-schema.yaml index ed0c1a5b69..a6b0f64029 100644 --- a/values-schema.yaml +++ b/values-schema.yaml @@ -2124,7 +2124,16 @@ properties: $ref: '#/definitions/resources' reportsController: $ref: '#/definitions/resources' - + policy-reporter: + additionalProperties: false + properties: + enabled: + type: boolean + default: false + _rawValues: + $ref: '#/definitions/rawValues' + resources: + $ref: '#/definitions/resources' kiali: additionalProperties: false properties: diff --git a/values/grafana-dashboards/grafana-dashboards.gotmpl b/values/grafana-dashboards/grafana-dashboards.gotmpl index 1c4c261e80..f493ff6d3a 100644 --- a/values/grafana-dashboards/grafana-dashboards.gotmpl +++ b/values/grafana-dashboards/grafana-dashboards.gotmpl @@ -1,8 +1,12 @@ {{- $v := .Values }} +{{- $pr := index $v.apps "policy-reporter" }} folders: - k8s-admin - istio-admin - cloudnative-pg + {{- if (and $v.apps.kyverno.enabled $pr.enabled)}} + - policy-reporter + {{- end }} {{- if $v.apps.falco.enabled }} - falco {{- end }} diff --git a/values/kyverno/kyverno-raw.gotmpl b/values/kyverno/kyverno-raw.gotmpl index c22ef4c3cc..36e8684817 100644 --- a/values/kyverno/kyverno-raw.gotmpl +++ b/values/kyverno/kyverno-raw.gotmpl @@ -61,4 +61,62 @@ resources: {{ $key }}: {{ $val }} {{- end }} {{- end }} -app.kubernetes.io/instance: loki +{{- if $v.otomi.linodeLkeImageRepository }} +{{- if not $v.otomi.nodeSelector }} +resources: +{{- end }} + - apiVersion: kyverno.io/v1 + kind: ClusterPolicy + metadata: + name: orcs-compliance-cluster + annotations: + policies.kyverno.io/title: ORCS Registry Compliance (Cluster-wide) + policies.kyverno.io/category: supply-chain-security + policies.kyverno.io/severity: high + policies.kyverno.io/subject: Pod + policies.kyverno.io/description: >- + Enforces OCI Registry Cache Service (ORCS) compliance across all namespaces + by ensuring all container images are pulled through the designated ORCS registry + for supply chain security and vulnerability management. + pod-policies.kyverno.io/autogen-controllers: "none" + spec: + validationFailureAction: Audit + background: true + failurePolicy: Fail + rules: + - name: validate-orcs-registry-cluster + match: + any: + - resources: + kinds: + - Pod + exclude: + any: + # Exclude team namespaces (they have their own ORCS policies) + - resources: + namespaces: + - "team-*" + - "kube-system" + skipBackgroundRequests: false + validate: + foreach: + - list: request.object.spec.[containers, initContainers, ephemeralContainers][] + deny: + conditions: + all: + # Require images to come from ORCS registry + - key: "{{`{{ element.image }}`}}" + operator: NotEquals + value: "{{ $v.otomi.linodeLkeImageRepository }}/*" + # Allow specific exemptions for critical system components + - key: "{{`{{ element.image }}`}}" + operator: AnyNotIn + value: + - "docker.io/istio/proxyv2*" + - "ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-*" + - "k8s.gcr.io/*" + - "registry.k8s.io/*" + - "quay.io/kyverno/*" + # System components that may not be available via ORCS + +{{- end }} diff --git a/values/policy-reporter/policy-reporter.gotmpl b/values/policy-reporter/policy-reporter.gotmpl new file mode 100644 index 0000000000..d980ffb0d0 --- /dev/null +++ b/values/policy-reporter/policy-reporter.gotmpl @@ -0,0 +1,28 @@ +{{ $v := .Values }} + +{{- if $v.otomi.linodeLkeImageRepository }} +image: + registry: "{{ $v.otomi.linodeLkeImageRepository }}/ghcr" +ui: + image: + registry: "{{ $v.otomi.linodeLkeImageRepository }}/ghcr" +plugin: + kyverno: + image: + registry: "{{ $v.otomi.linodeLkeImageRepository }}/ghcr" +{{- end }} +metrics: + enabled: true +monitoring: + enabled: true + serviceMonitor: + labels: + release: prometheus-operator + prometheus: system +sourceFilters: + - selector: + source: KyvernoValidatingPolicy + uncontrolledOnly: false + disableClusterReports: false + kinds: + exclude: [ReplicaSet] diff --git a/values/prometheus-operator/prometheus-operator.gotmpl b/values/prometheus-operator/prometheus-operator.gotmpl index 538dafab23..72506d14f6 100644 --- a/values/prometheus-operator/prometheus-operator.gotmpl +++ b/values/prometheus-operator/prometheus-operator.gotmpl @@ -5,6 +5,7 @@ {{- $a := $apps | get "alertmanager" }} {{- $g := $apps | get "grafana" }} {{- $p := $apps | get "prometheus" }} +{{- $pr := index $v.apps "policy-reporter" }} {{- $hasKeycloak := $k.enabled }} {{- $domain := ($v.cluster | get "domainSuffix" nil) }} @@ -193,6 +194,10 @@ additionalPrometheusRules: - name: keycloak-db-backup {{- readFile "rules/keycloak-db-backup.yaml" | nindent 4 }} {{- end }} + {{- if (and $pr.enabled $v.otomi.linodeLkeImageRepository) }} + - name: orcs-compliance + {{- readFile "rules/orcs-compliance.yaml" | nindent 4 }} + {{- end }} alertmanager: enabled: {{ $a.enabled }} alertmanagerSpec: diff --git a/values/prometheus-operator/rules/orcs-compliance.yaml b/values/prometheus-operator/rules/orcs-compliance.yaml new file mode 100644 index 0000000000..6bcb30d315 --- /dev/null +++ b/values/prometheus-operator/rules/orcs-compliance.yaml @@ -0,0 +1,129 @@ +groups: + - name: orcs-compliance + rules: + - alert: ORCSPolicyViolationHigh + annotations: + description: > + High rate of ORCS compliance policy violations detected. + {{ $value }} policy violations in the last 5 minutes across + namespace {{ $labels.namespace }}. This indicates containers + are being deployed that don't comply with ORCS registry requirements. + summary: '[ORCS Compliance] High violation rate detected' + runbook_url: 'https://docs.example.com/runbooks/orcs-compliance' + expr: | + ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="fail"}[5m]) > 5 + ) or ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance-mutate", result="fail"}[5m]) > 5 + ) + for: 2m + labels: + severity: warning + component: orcs-compliance + team: platform + + - alert: ORCSPolicyViolationCritical + annotations: + description: > + Critical rate of ORCS compliance policy violations detected. + {{ $value }} policy violations in the last 10 minutes across + namespace {{ $labels.namespace }}. This may indicate a systematic + bypass of ORCS compliance or misconfigured deployment pipelines. + Immediate attention required. + summary: '[ORCS Compliance] Critical violation rate - immediate action required' + runbook_url: 'https://docs.example.com/runbooks/orcs-compliance-critical' + expr: | + ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="fail"}[10m]) > 20 + ) or ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance-mutate", result="fail"}[10m]) > 20 + ) + for: 1m + labels: + severity: critical + component: orcs-compliance + team: platform + + - alert: ORCSComplianceDown + annotations: + description: > + ORCS compliance policy has not reported any results for the past 30 minutes. + This could indicate that the Kyverno policy engine is not functioning + properly or policies are not being applied. Supply chain security + monitoring is compromised. + summary: '[ORCS Compliance] Policy monitoring down' + runbook_url: 'https://docs.example.com/runbooks/orcs-compliance-down' + expr: | + absent(kyverno_policy_results_total{policy_name=~"orcs-compliance.*"}) == 1 + for: 30m + labels: + severity: critical + component: orcs-compliance + team: platform + + - alert: ORCSNonCompliantNamespace + annotations: + description: > + Namespace {{ $labels.namespace }} has consistently high ORCS policy violations. + {{ $value }}% of deployments in this namespace are non-compliant with + ORCS registry requirements over the past hour. This namespace may need + policy exemption review or deployment pipeline fixes. + summary: '[ORCS Compliance] Namespace {{ $labels.namespace }} consistently non-compliant' + runbook_url: 'https://docs.example.com/runbooks/orcs-namespace-compliance' + expr: | + ( + ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="fail"}[1h]) + / + ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="fail"}[1h]) + + + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="pass"}[1h]) + ) + ) * 100 > 80 + ) + and + ( + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="fail"}[1h]) > 10 + ) + for: 15m + labels: + severity: warning + component: orcs-compliance + team: platform + + - alert: ORCSPolicyExecutionLatencyHigh + annotations: + description: > + ORCS compliance policy execution latency is high. + Average execution time: {{ $value }}s. This may impact + deployment performance and indicates potential policy + optimization needs. + summary: '[ORCS Compliance] High policy execution latency' + runbook_url: 'https://docs.example.com/runbooks/orcs-latency' + expr: | + histogram_quantile(0.95, + increase(kyverno_policy_execution_duration_seconds_bucket{policy_name=~"orcs-compliance.*"}[5m]) + ) > 2 + for: 10m + labels: + severity: warning + component: orcs-compliance + team: platform + + - alert: ORCSExemptionOveruse + annotations: + description: > + High number of ORCS policy exemptions being triggered. + {{ $value }} exemptions in the last hour may indicate + overly broad exemption rules or potential policy bypass attempts. + Review exemption configuration and usage patterns. + summary: '[ORCS Compliance] High exemption usage detected' + runbook_url: 'https://docs.example.com/runbooks/orcs-exemptions' + expr: | + increase(kyverno_policy_results_total{policy_name="orcs-compliance", result="skip"}[1h]) > 100 + for: 5m + labels: + severity: info + component: orcs-compliance + team: platform \ No newline at end of file