Kubernetes API Audit¶
AKKO ships a production-ready audit policy that records every meaningful action on the Kubernetes API server — who did what, when, and to which resource. Logs flow to logs layer via log shipper and are queryable from Dashboards ("Audit Trail" dashboard).
This guide explains how to activate the policy on each supported cluster type. Activation requires API-server flag changes, which is a one-time operation per cluster.
What gets recorded¶
| Event class | Level | Why |
|---|---|---|
| Writes (create/update/patch/delete) on workloads, RBAC, ingress, CRDs | RequestResponse |
Full diff visible — investigates "who changed this" |
| Pod exec / attach / port-forward | RequestResponse |
Detects shell access and tunnels |
| Read on Secrets, ConfigMaps, ServiceAccount tokens | Metadata |
Catches credential exfiltration attempts |
| Authentication (TokenReview, SubjectAccessReview) | Metadata |
RBAC-decision audit |
| Read on everything else (kubectl get/list) | Metadata |
Lightweight exploration trail |
system:nodes reads (kubelet polling) |
None |
Filtered — 90% of API noise |
/healthz, /metrics, /openapi/* |
None |
Filtered — health probes |
Policy file: helm/k8s-audit/audit-policy.yaml
k3s (Netcup, edge, single-node)¶
# 1. Copy the policy to k3s config dir
sudo cp helm/k8s-audit/audit-policy.yaml /etc/rancher/k3s/audit-policy.yaml
# 2. Append API-server flags to k3s config
sudo tee -a /etc/rancher/k3s/config.yaml <<'EOF'
kube-apiserver-arg:
- audit-policy-file=/etc/rancher/k3s/audit-policy.yaml
- audit-log-path=/var/log/k3s-audit.log
- audit-log-maxage=30
- audit-log-maxbackup=10
- audit-log-maxsize=100
EOF
# 3. Restart k3s to pick up the new flags
sudo systemctl restart k3s
# 4. Verify
sudo tail -f /var/log/k3s-audit.log | jq .
log shipper (deployed by AKKO) auto-scrapes /var/log/k3s-audit.log on the host
node and ships entries to logs layer under the job="k3s-audit" label.
EKS (AWS)¶
EKS audit logging is a CloudWatch flag — no policy file needed (EKS uses the upstream default policy, broadly equivalent to ours).
aws eks update-cluster-config \
--region eu-west-1 \
--name akko-prod \
--logging '{"clusterLogging":[{"types":["audit","authenticator","controllerManager"],"enabled":true}]}'
Logs land in the CloudWatch log group /aws/eks/akko-prod/cluster.
Use the AWS for Fluent Bit DaemonSet (or the AKKO-provided logs layer shipper)
to forward them to logs layer if you want a single pane in Dashboards.
GKE (Google Cloud)¶
gcloud container clusters update akko-prod \
--region europe-west1 \
--logging=SYSTEM,WORKLOAD,API_SERVER
Logs land in Cloud Logging. Filter:
To pipe them to logs layer, deploy the logs layer Cloud Logging sink (separate Helm chart) or use Pub/Sub → log shipper.
AKS (Azure)¶
az monitor diagnostic-settings create \
--name akko-audit \
--resource $(az aks show -g <rg> -n akko-prod --query id -o tsv) \
--logs '[{"category":"kube-audit","enabled":true},{"category":"kube-audit-admin","enabled":true}]' \
--workspace <log-analytics-workspace-id>
Logs land in the Log Analytics workspace. Query language is KQL — see
the AzureDiagnostics table.
OpenShift¶
OpenShift writes audit logs by default to
/var/log/kube-apiserver/audit.log on every master node. To override the
profile with the AKKO baseline:
apiVersion: config.openshift.io/v1
kind: APIServer
metadata:
name: cluster
spec:
audit:
profile: WriteRequestBodies # or Default / AllRequestBodies
For full custom rules, mount the AKKO audit-policy.yaml via a
MachineConfig and reference it through customRules.
Querying audit events¶
Once logs reach logs layer, the Audit Trail Dashboard provides ready-made panels:
- Top users by API calls (last 1h)
- Resource creations / deletions (timeline)
- Privileged operations (
pods/exec, RoleBinding changes) - Sensitive reads (Secret access by user)
Raw LogQL examples:
# Every Secret read in the last hour
{job="k3s-audit"} | json | objectRef_resource = "secrets" | verb = "get"
# Every RoleBinding change today
{job="k3s-audit"} | json | objectRef_resource = "rolebindings" | verb =~ "create|update|patch|delete"
# Top 10 users by write volume
sum by (user_username) (count_over_time(
{job="k3s-audit"} | json | verb =~ "create|update|patch|delete" [1h]
))
Rotation & retention¶
The k3s flags above rotate every 100 MB and keep 10 backups for 30 days on disk. logs layer applies a separate retention (default 30 days, 90 days on Netcup — see logs layer configuration). Set the disk retention shorter than logs layer to avoid duplication.
Compliance mapping¶
| Standard | Requirement | Covered |
|---|---|---|
| SOC 2 CC6.1 | Logical access logging | ✅ All write events recorded with user identity |
| ISO 27001 A.12.4.1 | Event logging | ✅ Authentication + authorization decisions |
| GDPR Art. 32 | Integrity & accountability | ✅ Tamper-evident JSON log shipped to logs layer |
| HDS | Hosting healthcare data — access logs | ✅ Sensitive resource reads at Metadata level |
For air-gapped deployments, see Air-Gapped Deployment for how to ship audit logs to an internal logs layer without internet egress.