Skip to main content
Version: 3.14-dev

Audit Trails Setup

The krci-audit add-on records an append-only audit trail of admission changes to the Kubernetes resources managed by KubeRocketCI β€” who created, updated, or deleted an object, and when. It is self-contained and never blocks platform operations: if auditing is unavailable, the change still proceeds.

Architecture​

krci-audit is composed of three parts and a read API:

  • Capture β€” a ValidatingWebhookConfiguration (the native Kubernetes admission-control mechanism, backed by kube-audit-rest) receives the AdmissionReview for each matching change. Its failurePolicy is Ignore with a short timeout, so platform mutations are never blocked.
  • Ship β€” a Vector sidecar tails the capture log, keeps only the events selected by the store filter, and writes them to PostgreSQL.
  • Store β€” a dedicated PostgreSQL database holds the events in a monthly-partitioned, append-only table. Writes use a least-privilege role that cannot update or delete existing records.
  • Read API β€” a separate, read-only service exposes initiator lookup (who created a resource) and an audit-events query. It connects to PostgreSQL as a SELECT-only role, so the read path can never modify the trail.

Data flows one way:

A Kubernetes resource change triggers the capture webhook, which Vector ships to PostgreSQL; the read API then serves that stored data to consumers.

Installation​

krci-audit is delivered as a KubeRocketCI add-on. It is disabled by default.

Prerequisites: cert-manager (bundled with KubeRocketCI) issues the webhook's serving certificate. For pgo database mode you also need the Crunchydata PostgreSQL operator; to deliver credentials through the External Secrets Operator, install that add-on first.

  1. Provide the database credentials Secret. The chart never generates credentials β€” it only reads a Secret you supply, in every database mode. Create it in the krci-audit namespace (or populate it with the External Secrets Operator):

    kubectl -n krci-audit create secret generic krci-audit-db-access \
    --from-literal=db-owner-username=krci-audit \
    --from-literal=db-owner-password="$(openssl rand -base64 24)" \
    --from-literal=writer-password="$(openssl rand -base64 24)" \
    --from-literal=reader-password="$(openssl rand -base64 24)"

    The db-owner-* keys are required for simple mode; writer-password is always required; reader-password is required when the read API is enabled.

  2. Enable the add-on in clusters/core/apps/values.yaml:

    krci-audit:
    enable: true
  3. Sync the add-on in Argo CD. The chart applies the schema migration, provisions PostgreSQL (for simple/pgo modes), and starts the capture and read API workloads.

Configuration​

The add-on wrapper overrides only db.mode; the full configuration surface lives in the component chart's values.yaml. The most common settings:

SettingDefaultPurpose
capture.rulesv2.edp.epam.com/*, tekton.dev/pipelinerunsWhich admissions the API server sends to the webhook.
capture.filterKubeRocketCI groups + Tekton PipelineRunsWhich received events are actually stored (change any time with helm upgrade, no rebuild).
capture.namespaces[] (all)Restrict auditing to named namespaces.
capture.levelmetadataObject body captured: metadata (bounds size and PII) or full.
db.modesimple (add-on)PostgreSQL provisioning: external (bring your own), pgo (Crunchydata operator), or simple (in-cluster Postgres for dev/small installs).
retention.months12Months of history to keep (see Retention).

Retention​

A scheduled CronJob (nightly at 02:00 by default) drops audit history older than retention.months. Retention is month-granular: expired data is removed a whole monthly partition at a time, so the smallest effective window is about one month β€” sub-monthly windows (for example, three weeks) are not supported. The job only drops whole partitions and never deletes individual rows, preserving append-only integrity.

Access control​

The read API is exposed only inside the cluster (a ClusterIP Service, no Ingress); consumers reach it by in-cluster DNS. It connects to the database as a SELECT-only role, so it cannot alter the trail. Network exposure is the interim access boundary; API authentication and authorization are planned.

Querying the audit trail​

The read API is reachable in-cluster at <release>-api.<namespace>:8080. To query it from your workstation, port-forward the Service:

kubectl -n krci-audit port-forward svc/krci-audit-api 18080:8080

Look up who created a resource (initiator lookup) by kind, namespace, and name:

curl "http://localhost:18080/api/v1/audit/initiator?kind=PipelineRun&namespace=krci&name=build-test-go-app-main-8a2c"
{
"actor": "system:serviceaccount:krci:krci-admin",
"operation": "CREATE",
"found": true,
"timestamp": "2026-07-07T12:41:00Z"
}

Query the recorded events (filterable by kind, operation, actor, and paginated):

curl "http://localhost:18080/api/v1/audit/events?kind=PipelineRun&operation=UPDATE&limit=20"

Compliance usage​

The audit trail provides evidence for compliance frameworks such as SOC 2, ISO 27001, GDPR, and PCI DSS: an immutable, time-stamped record of who changed which resources. Auditors retrieve evidence through the read API β€” initiator lookup ("who created this resource") and the filterable audit-events query β€” without direct database access.