Skip to content

Commit 2c269bd

Browse files
authored
Merge pull request #209 from Obmondo/docs/security-exporter-readmes
docs(kubeaid-security-exporter): add chart README, refresh the agent one
2 parents f3e41ea + ab93f02 commit 2c269bd

2 files changed

Lines changed: 81 additions & 9 deletions

File tree

argocd-helm-charts/kubeaid-agent/README.md

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ on the `kubeaid` Argo CD project, stored in the `argocd-project-role-kubeaid-age
1818
- `argocd-project-role-kubeaid-agent` Secret in the `argocd` namespace, holding the Argo CD auth token under the
1919
`token` key (created automatically by `kubeaid-cli`). Name overridable via
2020
`appConfig.argocd.authTokenSecretName`.
21-
- kube-prometheus, if `serviceMonitor` / `prometheusRule` stay enabled (both default to `true`).
21+
- `kubeaid-security-exporter` in the cluster, if `appConfig.securityPosture.enabled` stays `true`. The agent
22+
forwards that exporter's snapshots; it collects no posture data itself.
23+
- kube-prometheus, if `serviceMonitor` stays enabled (defaults to `true`).
2224

2325
## Key values / KubeAid-specific configuration
2426

@@ -30,20 +32,19 @@ on the `kubeaid` Argo CD project, stored in the `argocd-project-role-kubeaid-age
3032
| `appConfig.obmondoAPI.url` | `https://api.obmondo.com/api` | Obmondo API endpoint (mTLS). |
3133
| `appConfig.kubeaidUpdate.enabled` | `false` | Opt-in: schedule the service-window Argo CD sync cron job. |
3234
| `appConfig.kubeaidUpdate.checkInterval` | `15m` | Poll cadence for an active KubeAid update service window. |
33-
| `appConfig.securityPosture.enabled` | `true` | Collect vulnerabilities (trivy-operator reports), least-privilege findings, network-policy and runtime-detection posture, and submit them to the Obmondo API. Also gates the matching RBAC and the PrometheusRule. |
34-
| `appConfig.securityPosture.interval` | `12h` | Full posture collection cadence (Trivy refreshes reports every 24h). |
35+
| `appConfig.securityPosture.enabled` | `true` | Poll `kubeaid-security-exporter` and forward its snapshots to the Obmondo API. The agent collects nothing itself. |
36+
| `appConfig.securityPosture.exporterURL` | `http://kubeaid-security-exporter` | In-cluster URL of the exporter. A bare Service name resolves in the agent's own namespace; qualify it if the two charts deploy to different namespaces. |
37+
| `appConfig.securityPosture.pollInterval` | `1h` | Poll cadence. The submit is skipped when `collectedAt` has not advanced, so end-to-end freshness is bounded by the exporter's collection interval, not by this. |
3538
| `obmondoAPITLSSecretName` | `obmondo-clientcert` | Secret with the mTLS keypair. |
3639
| `extraSecretReaderNamespaces` | `[]` | Extra namespaces where a secrets-read Role/RoleBinding is created for the agent. |
37-
| `prometheusRule.upgradableThreshold` | `20` | `ImageOutdatedAndVulnerable` fires when more images than this have both a fixable Critical/High CVE and a newer tag (for `upgradableFor`, default 24h). |
3840

3941
## Operational notes
4042

4143
- RBAC is least-privilege by construction: a purpose-built ClusterRole grants exactly the verbs the agent's code
42-
calls (no `watch`, no blanket `view`). Secrets access stays on namespaced Roles. The security-posture rules
43-
(trivy-operator, Cilium/Tetragon, KubeArmor resources) are gated by the same `securityPosture.enabled` flag the
44-
agent reads, so RBAC and behaviour cannot disagree.
45-
- `securityPosture.enabled: true` is safe on clusters without a scanner — the collector detects missing APIs via
46-
discovery and does nothing. Set it to `false` only where vulnerability detail must not leave the cluster.
44+
calls (no `watch`, no blanket `view`). Secrets access stays on namespaced Roles. The agent holds no CRD access
45+
at all — reading Trivy, Cilium, Tetragon and KubeArmor resources belongs to `kubeaid-security-exporter`.
46+
- `securityPosture.enabled: true` is safe where the exporter is not installed — the poll fails, a metric records
47+
it, and nothing is submitted. Set it to `false` only where vulnerability detail must not leave the cluster.
4748
- Runs unprivileged: non-root, all capabilities dropped, `RuntimeDefault` seccomp.
4849

4950
## Docs links
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# kubeaid-security-exporter
2+
3+
Deploys the [KubeAid Security Exporter](https://gitea.obmondo.com/EnableIT/kubeaid-security-exporter) — a
4+
Kubernetes-native exporter that reads a cluster's security posture and reports it as Prometheus metrics and
5+
a JSON API. It only ever reads: no Kubernetes object is created, mutated, or deleted.
6+
7+
What it collects, where the relevant operator is installed:
8+
9+
- **Vulnerabilities and least-privilege findings** from Trivy Operator's report CRs — full CVE detail
10+
(CVSS score, installed and fixed version, advisory link), rather than the lossy Prometheus projection.
11+
- **Upgrade availability**, by joining those findings against version-checker on canonical image
12+
references resolved in Go. Rebuilding image references in PromQL fails silently.
13+
- **Network enforcement** from Cilium — whether policy is actually realised on an app's pods, which is a
14+
different question from whether the app ships a policy.
15+
- **Runtime detection posture** from Tetragon and KubeArmor — which engines are armed, and whether they
16+
observe or enforce.
17+
18+
None of those are required. Each source is detected through API discovery, and an absent operator is
19+
reported as absent rather than as a failure or as a clean result.
20+
21+
## Relationship to kubeaid-agent
22+
23+
The exporter collects; it never talks to the Obmondo API. `kubeaid-agent` GETs `/api/v1/security-posture`
24+
from this Service and forwards the snapshot, so reporting posture off-cluster is the agent's concern and
25+
cluster read access is this chart's. That split is why the agent holds no CRD access at all.
26+
27+
Deploying this chart without the agent is fine — the metrics and the JSON API work standalone.
28+
29+
## Prerequisites
30+
31+
- **trivy-operator**, for vulnerability and least-privilege data. Without it the exporter reports no
32+
findings, and says so rather than reporting a clean cluster.
33+
- **version-checker**, for upgrade availability. Without it findings still ship, with upgrade availability
34+
unknown rather than "up to date".
35+
- kube-prometheus, if `serviceMonitor` / `prometheusRule` stay enabled (both default to `true`).
36+
37+
Cilium, Tetragon and KubeArmor are read when present and skipped when not.
38+
39+
## Key values
40+
41+
| Value | Default | Meaning |
42+
|---|---|---|
43+
| `exporter.interval` | `12h` | Collection cadence. Trivy refreshes its reports on a 24h TTL, so polling faster re-reads identical data. |
44+
| `exporter.port` | `8080` | Serves `/healthz`, `/readyz`, `/metrics` and `/api/v1/security-posture`. |
45+
| `prometheusRule.upgradableThreshold` | `20` | `ImageOutdatedAndVulnerable` fires above this many images having both a fixable Critical/High CVE and a newer tag available. |
46+
| `prometheusRule.upgradableFor` | `24h` | How long the count must hold before the alert fires. |
47+
48+
## Alerting
49+
50+
One alert, `ImageOutdatedAndVulnerable`. It is a count, so it fires once per cluster rather than once per
51+
image, and the threshold is deliberately high — every real cluster carries a few of these at any moment, so
52+
a low threshold fires everywhere on day one and gets ignored. The signal worth acting on is a pile of easy
53+
upgrades, not the existence of one.
54+
55+
Collection status is exported as `security_exporter_collection` (1 ok, 0 failed, -1 not installed) but is
56+
deliberately not alerted on: a collection failure is a debugging signal, not something worth paging for.
57+
58+
## Operational notes
59+
60+
- RBAC is least-privilege by construction — a purpose-built ClusterRole granting exactly the verbs the code
61+
calls, with no `watch` anywhere since the exporter builds no informers. Every rule is consumed through a
62+
dynamic client, so none of those resource names appear in Go source; removing a rule fails silently and
63+
renders the cluster as clean rather than erroring.
64+
- Runs unprivileged: non-root, read-only root filesystem, all capabilities dropped, `RuntimeDefault` seccomp.
65+
- A collection pass holds every VulnerabilityReport in memory at once, so the memory ceiling scales with
66+
image count rather than with request rate.
67+
68+
## Docs links
69+
70+
- Chart source: `templates/` and [values.yaml](./values.yaml) in this directory (documented inline).
71+
- Obmondo: <https://obmondo.com>

0 commit comments

Comments
 (0)