Audit Logging #
Setiap aksi terhadap Kubernetes API — buat Pod, baca Secret, hapus Deployment — bisa dicatat dalam audit log. Ini adalah rekaman jejak yang memungkinkan kamu menjawab pertanyaan kritis saat insiden: siapa yang akses Secret database jam 3 pagi? Kapan Deployment ini diubah? Apakah ada akses tidak normal yang mendahului serangan? Tanpa audit log, investigasi insiden berjalan hampir buta.
Cara Kerja Audit Logging #
Audit logging dikonfigurasi di API Server. Setiap request ke API Server dicatat dalam beberapa tahap:
Stages dalam audit log:
RequestReceived — saat request diterima API Server, sebelum diproses
ResponseStarted — saat header response mulai dikirim (untuk long-running requests)
ResponseComplete — saat response selesai dikirim
Panic — saat API Server mengalami panic saat memproses request
Audit Policy #
Audit policy menentukan request mana yang dicatat dan seberapa detail:
# /etc/kubernetes/audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Jangan catat request ke endpoint yang tidak informatif
- level: None
users: ["system:kube-proxy"]
verbs: ["watch"]
resources:
- group: ""
resources: ["endpoints", "services", "services/status"]
- level: None
userGroups: ["system:nodes"]
verbs: ["get"]
resources:
- group: ""
resources: ["nodes", "nodes/status"]
# Catat semua akses ke Secret dengan detail request
- level: Metadata # catat metadata saja, bukan isi Secret
resources:
- group: ""
resources: ["secrets", "configmaps"]
# Tidak mencatat nilai Secret (untuk keamanan)
# Tapi mencatat siapa, kapan, dari mana
# Catat perubahan ke Deployment, StatefulSet, DaemonSet
- level: RequestResponse # catat request dan response body
verbs: ["create", "update", "patch", "delete"]
resources:
- group: "apps"
resources: ["deployments", "statefulsets", "daemonsets"]
- group: ""
resources: ["pods"]
# Catat semua akses dari user manusia (bukan system components)
- level: Request
userGroups: ["system:authenticated"]
omitStages: ["RequestReceived"]
# Default: catat metadata untuk semua request yang tersisa
- level: Metadata
omitStages: ["RequestReceived"]
Level Audit #
None:
→ Jangan catat sama sekali
→ Untuk request yang sangat frekuen dan tidak informatif
Metadata:
→ Catat metadata request: user, waktu, resource, verb
→ Tidak catat isi request atau response body
→ Baik untuk Secret (aman) dan request volume tinggi
Request:
→ Catat metadata + request body
→ Tidak catat response body
→ Baik untuk operasi create/update/delete
RequestResponse:
→ Catat metadata + request body + response body
→ Paling lengkap tapi paling banyak storage
→ Gunakan untuk aksi yang butuh audit penuh (delete, critical changes)
Mengaktifkan Audit Logging di API Server #
# kube-apiserver manifest (untuk cluster self-managed)
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- --audit-policy-file=/etc/kubernetes/audit-policy.yaml
- --audit-log-path=/var/log/kubernetes/audit.log
- --audit-log-maxage=30 # simpan 30 hari
- --audit-log-maxbackup=10 # simpan 10 file backup
- --audit-log-maxsize=100 # max 100MB per file
# Atau kirim ke webhook (lebih baik untuk produksi):
- --audit-webhook-config-file=/etc/kubernetes/audit-webhook.yaml
- --audit-webhook-batch-max-size=400
- --audit-webhook-batch-max-wait=30s
volumeMounts:
- mountPath: /etc/kubernetes/audit-policy.yaml
name: audit-policy
readOnly: true
- mountPath: /var/log/kubernetes
name: audit-log
Format Audit Log #
Setiap entry audit log adalah JSON:
{
"kind": "Event",
"apiVersion": "audit.k8s.io/v1",
"level": "Metadata",
"auditID": "a4d2b0c3-...",
"stage": "ResponseComplete",
"requestURI": "/api/v1/namespaces/production/secrets/db-credentials",
"verb": "get",
"user": {
"username": "[email protected]",
"groups": ["engineering", "system:authenticated"]
},
"sourceIPs": ["203.0.113.42"],
"userAgent": "kubectl/v1.28.0",
"objectRef": {
"resource": "secrets",
"namespace": "production",
"name": "db-credentials",
"apiVersion": "v1"
},
"responseStatus": {
"code": 200
},
"requestReceivedTimestamp": "2024-01-15T03:27:14.123456Z",
"stageTimestamp": "2024-01-15T03:27:14.156789Z"
}
Query dan Investigasi Audit Log #
# Cari semua akses ke Secret tertentu
grep '"name":"db-credentials"' /var/log/kubernetes/audit.log | \
jq '{time: .requestReceivedTimestamp, user: .user.username, verb: .verb, source: .sourceIPs}'
# Cari akses diluar jam kerja (contoh: setelah jam 20:00 atau sebelum 08:00)
grep '"stage":"ResponseComplete"' /var/log/kubernetes/audit.log | \
jq 'select(.requestReceivedTimestamp | test("T(20|21|22|23|00|01|02|03|04|05|06|07):"))' | \
jq '{time: .requestReceivedTimestamp, user: .user.username, action: .verb, resource: .objectRef.resource}'
# Cari operasi delete di production
grep '"verb":"delete"' /var/log/kubernetes/audit.log | \
grep '"namespace":"production"' | \
jq '{time: .requestReceivedTimestamp, user: .user.username, resource: .objectRef.resource, name: .objectRef.name}'
# Lihat semua aksi dari user tertentu
grep '"username":"[email protected]"' /var/log/kubernetes/audit.log | \
jq '{time: .requestReceivedTimestamp, verb: .verb, resource: .objectRef.resource, name: .objectRef.name}'
Integrasi dengan SIEM #
Untuk produksi, jangan simpan audit log di file lokal — kirim ke sistem yang bisa dianalisis:
# audit-webhook.yaml — kirim ke log aggregation (Elasticsearch, Splunk, dll)
apiVersion: v1
kind: Config
clusters:
- name: audit-backend
cluster:
server: https://elasticsearch.monitoring:9200/_bulk
certificate-authority: /etc/ssl/certs/ca.crt
users:
- name: audit-user
user:
token: <elasticsearch-token>
contexts:
- name: audit-context
context:
cluster: audit-backend
user: audit-user
current-context: audit-context
Untuk cloud managed Kubernetes, audit log biasanya tersedia di platform log management:
# GKE: lihat di Cloud Logging
gcloud logging read 'resource.type="k8s_cluster" AND logName=~"cloudaudit"' \
--project=my-project --limit=100
# EKS: aktifkan control plane logging ke CloudWatch
aws eks update-cluster-config --name my-cluster \
--logging '{"clusterLogging":[{"types":["api","audit","authenticator"],"enabled":true}]}'
Deteksi Anomali: Sinyal yang Perlu Dipantau #
Aksi mencurigakan yang harus di-alert:
1. Akses Secret di luar jam kerja atau dari IP tidak dikenal
→ Mungkin credential breach
2. kubectl exec ke Pod production
→ Siapa yang masuk ke container dan kenapa?
→ Verb: create, Resource: pods/exec
3. Buat ClusterRoleBinding dengan cluster-admin
→ Privilege escalation attempt
4. List semua Secret di namespace
→ Verb: list, Resource: secrets
5. Hapus resource secara massal
→ deletecollection verb
6. Akses dari ServiceAccount yang biasanya tidak manusia
→ system:serviceaccount:namespace:name dari source IP eksternal
7. API error rate yang tinggi dari satu user/service
→ Mungkin brute force atau misconfigured automation
Ringkasan #
- Audit policy dengan level yang tepat per resource — Secret cukup level Metadata (jangan log isinya); Deployment changes perlu RequestResponse; request frekuen dari system component bisa None.
- Kirim ke SIEM, bukan file lokal — file lokal tidak bisa di-query dengan efisien dan bisa hilang jika node bermasalah; gunakan Elasticsearch, Splunk, atau platform cloud logging.
- Alert untuk aksi kritis — akses Secret di luar jam kerja,
kubectl execke production, buat ClusterRoleBinding baru, danlist secretsadalah sinyal yang harus memicu alert.- Cloud managed Kubernetes sudah sediakan infrastruktur — GKE ke Cloud Logging, EKS ke CloudWatch; aktifkan dan konfigurasikan retention policy yang sesuai compliance.
- Audit log untuk investigasi pasca-insiden — “siapa yang deploy ini?”, “kapan Secret ini diakses?”, “dari mana traffic ini berasal?” semua bisa dijawab dari audit log.
- Jangan log response body Secret — level Metadata untuk Secret sudah cukup untuk audit trail tanpa mengekspos nilai sensitif ke log infrastructure.
← Sebelumnya: Supply Chain Security Berikutnya: Cluster Hardening →