Documentation / policy-reporter
Policy Reporter
Installs Policy Reporter, an in-cluster view of the policy reports Kyverno writes: every policy’s results for the resources in the cluster, by namespace, policy and severity, including the results of the Compliance and Assurance Convoy’s policies.
The chart installs Policy Reporter’s own Helm chart, unchanged, under the name
reporter, with settings for a cluster on your own premises:
- every image from the Mamluk registry, pinned by digest;
- the UI and the Kyverno plugin, which adds each policy’s detail to the UI;
- nothing sent outside the cluster: every notification target, email reports and the Trivy plugin are refused;
- the UI read through
kubectl port-forward, and published only behind sign-in through your own identity provider; - NetworkPolicies that allow each Pod only what it uses;
- every Pod meeting the
restrictedPod Security Standard.
Prerequisites
- Kubernetes 1.33 or later, and the Bahriya Tersane
kyvernochart. - A namespace of its own, conventionally
policy-reporter. - A pull secret for
1x.axnamed1x-axin that namespace, created from an image token as described in the access documentation.
Installation
helm install policy-reporter tersane/policy-reporter \
--namespace policy-reporter --create-namespace \
--version <chart version>
Open the UI, read-only:
kubectl --namespace policy-reporter port-forward service/policy-reporter-ui 8080:8080
then http://localhost:8080/. Whoever may create pods/portforward in the
namespace may read it.
What it shows, and what it does not
Policy Reporter reads the policy reports in both of Kyverno’s formats
(wgpolicyk8s.io and openreports.io), so it shows the result of every
Kyverno policy, the Convoy’s included.
It does not show trivy-operator’s results. trivy-operator does not write policy reports, and showing them would need a further component that converts them, and calls to services outside the cluster. The Compliance and Assurance Convoy’s report presents trivy-operator’s results with each failing object and how to fix it.
It is a view, not evidence. It keeps results in a SQLite file on a volume that lasts as long as its Pod, reads them again from the reports when it restarts, and shows what Kyverno reports now. The Convoy’s dated, signed report is the evidence for a regime.
Publishing the UI
The UI has no access control of its own. The chart therefore refuses an Ingress for it until people sign in through OpenID Connect:
- Create a client for this UI alone at your identity provider: a
confidential client, with the redirect URI
https://<host>/callback. Do not reuse the client that signs people in to the cluster itself (on a Bahriya Kubernetes Engine cluster,bahriya-kubernetes-login): it has settings of its own that this UI does not need, and a change made for one would break the other. - Put its details in a Secret in the release’s namespace, with the keys
discoveryUrl(the issuer’s/.well-known/openid-configuration),clientIdandclientSecret. -
Set the values:
reporter: ui: openIDConnect: enabled: true secretRef: policy-reporter-oidc callbackUrl: https://reports.example.com/callback groupClaim: groups ingress: enabled: true className: <your ingress class> hosts: - host: reports.example.com paths: [{path: /, pathType: Prefix}] networkPolicy: allowFrom: - namespaceSelector: {matchLabels: {kubernetes.io/metadata.name: <your ingress controller's namespace>}} identityProviderCIDRs: [192.0.2.10/32]
identityProviderCIDRs names the addresses the UI may reach to sign people
in, on port 443; an identity provider inside the cluster is named by its Pods’
addresses. groupClaim names the token claim that lists a person’s groups,
which Policy Reporter’s access settings can use.
reporter.ui.openIDConnect.pkce is off. Turn it on only if your client
requires PKCE; the UI then sends a code challenge with each sign-in. The
client secret is never a value, and the identity provider’s certificate is
always verified: clientSecret and skipTLS are refused.
Network
| Pod | Reached by | Reaches |
|---|---|---|
| Core | the UI | DNS, the Kubernetes API server |
| Kyverno plugin | the UI, the core | DNS, the Kubernetes API server |
| UI | networkPolicy.allowFrom |
DNS, the Kubernetes API server (it reads its Secrets there when it starts), the core, the plugin; with sign-in, identityProviderCIDRs |
The API server’s addresses are read from the kubernetes EndpointSlices in
default when the chart is installed or upgraded. After adding a
control-plane node, upgrade the chart, or the Pods cannot reach its API
server. Where the chart cannot read them, for example when a GitOps tool
renders it, give them in apiServer.cidrs.
What the chart refuses
| Setting | Why |
|---|---|
Any reporter.target.* destination, channel or secret, reporter.target.crd, reporter.existingTargetConfig |
Each would send results outside the cluster |
reporter.emailReports |
The same |
reporter.plugin.trivy |
It calls outside APIs |
reporter.ui.oauth |
Sign-in through a public provider; use OpenID Connect with your own |
An Ingress or HTTPRoute for the UI without openIDConnect |
The UI has no access control of its own |
An Ingress or HTTPRoute for the core, reporter.rest |
The core’s API is read by the UI inside the cluster |
Parameters
| Parameter | Description | Default |
|---|---|---|
reporter.image, reporter.ui.image, reporter.plugin.kyverno.image |
The images, from 1x.ax by digest | pinned |
reporter.imagePullSecrets, reporter.ui.imagePullSecrets, reporter.plugin.kyverno.imagePullSecrets |
Pull secrets | [{name: 1x-ax}] |
reporter.ui.enabled |
The UI | true |
reporter.plugin.kyverno.enabled |
Each policy’s detail in the UI | true |
reporter.ui.openIDConnect.* |
Sign-in; see above | off |
reporter.ui.ingress.* |
Publishing the UI, with sign-in | off |
networkPolicy.allowFrom |
Peers that may reach the UI | [] |
networkPolicy.identityProviderCIDRs |
The identity provider’s addresses, with sign-in | [] |
apiServer.cidrs, apiServer.port |
The API server’s addresses, where the chart cannot read them | [], 6443 |
reporter.* resources and security contexts |
Set for Pod Security restricted |
see values.yaml |