iT邦幫忙

2026 iThome 鐵人賽

DAY 7
1
Kubernetes

資安這條路:從攻擊者視角看 Kubernetes系列 第 7

Day 7|防禦持久化:Audit Log + RBAC 監控 + 映像簽章

  • 分享至 

  • xImage
  •  

資安這條路:從攻擊者視角看 Kubernetes

ATT&CK TA0003 的防禦面——偵測並阻止攻擊者在叢集中留下後門。

防禦總覽

攻擊 防禦措施 層級
S09 RBAC 竄改 Audit Log + RBAC 限制 Audit / RBAC
S10 後門 SA Audit Log + SA 盤點 Audit / Ops
S11 Sidecar 注入 Webhook 審計 + Kyverno Admission
S12 映像植入 Cosign 簽章 + Kyverno 驗簽 Supply Chain

持久化攻擊的共通特點是隱蔽——攻擊者希望後門能存活越久越好。因此偵測手段必須具備兩個能力:

  1. 即時偵測:在後門建立的瞬間發出告警(Audit Log + Falco k8s_audit)
  2. 定期盤點:找出已經存在但未被告警的後門(SA 審計 + RBAC 掃描)

前置準備

所有指令都在 koad 專案目錄下執行。如果還沒 clone,請先參考 Day 1 的 Step 0。

開始前請確認以下環境就緒。

1. 確認 Falco 與 Kyverno 運行中

# 主機終端
kubectl get pods -n falco
kubectl get pods -n kyverno

兩者都應為 Running 狀態。

2. 確認攻擊場景 Pod 存在

# 主機終端
kubectl get pods -n koad -l 'koad-scenario in (S09,S10,S11,S12)'

Day 6 的持久化攻擊場景需要存在,才能驗證 Audit Log 是否捕捉到這些操作。

3. 確認 Audit Log 路徑

# 主機終端
minikube ssh -- ls -la /var/log/kubernetes/audit/

如果目錄不存在或為空,需要先配置 API Server 的 Audit Policy(本日內容會教你怎麼做)。

學習目標

完成本日實作後,你將能夠:

  • 撰寫 K8s Audit Policy(四級記錄策略)
  • jq 從 Audit Log 中分析 RBAC 異動事件
  • 建立 SA 定期盤點腳本,偵測後門帳號
  • 用 Cosign 簽署映像、用 Kyverno 驗簽
  • 理解三層偵測架構(Audit Log + Admission + Runtime)的互補關係

Kubernetes Audit Log:偵測 RBAC 異動

為什麼需要 Audit Log

Falco 的 syscall 規則能偵測到容器內的異常行為(shell 啟動、kubectl 執行),但 RBAC 竄改、SA 建立、Webhook 配置 這些動作發生在 API Server 層面,syscall 看不到。

K8s Audit Log 記錄了所有經過 API Server 的請求,是偵測 Persistence 攻擊的關鍵資料源。

Audit Log 管線架構

API Server

Audit 四級設定

層級 記錄內容 儲存成本 適用場景
None 不記錄 不重要的 API 呼叫(如 /healthz)
Metadata 請求的 metadata(誰、何時、做了什麼) 大部分讀取操作
Request Metadata + 請求 body 寫入操作
RequestResponse Metadata + 請求 body + 回應 body 高風險操作(RBAC 變更)

Audit Event 結構詳解

一個完整的 Audit Event JSON:

{
  "kind": "Event",
  "apiVersion": "audit.k8s.io/v1",
  "level": "RequestResponse",
  "auditID": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "stage": "ResponseComplete",
  "requestURI": "/apis/rbac.authorization.k8s.io/v1/clusterrolebindings",
  "verb": "create",
  "user": {
    "username": "system:serviceaccount:koad:overprivileged-sa",
    "uid": "12345",
    "groups": ["system:serviceaccounts", "system:serviceaccounts:koad"]
  },
  "sourceIPs": ["10.244.0.15"],
  "userAgent": "kubectl/v1.30.0",
  "objectRef": {
    "resource": "clusterrolebindings",
    "name": "koad-attacker-admin",
    "apiGroup": "rbac.authorization.k8s.io",
    "apiVersion": "v1"
  },
  "responseStatus": {
    "metadata": {},
    "code": 201
  },
  "requestObject": {
    "metadata": { "name": "koad-attacker-admin" },
    "subjects": [{"kind": "ServiceAccount", "name": "attacker-sa", "namespace": "koad"}],
    "roleRef": {"kind": "ClusterRole", "name": "cluster-admin"}
  },
  "requestReceivedTimestamp": "2026-08-19T15:00:00.000000Z",
  "stageTimestamp": "2026-08-19T15:00:00.050000Z"
}

關鍵欄位說明:

欄位 用途 S09 範例值
user.username 操作者身份 system:serviceaccount:koad:overprivileged-sa
verb 操作類型 create
objectRef.resource 操作的資源 clusterrolebindings
requestObject.roleRef.name 綁定的角色 cluster-admin
responseStatus.code 結果 201(建立成功)
sourceIPs 來源 IP 10.244.0.15(Pod IP)

KOAD Audit Policy

KOAD 的審計策略針對每個攻擊場景設計了對應規則:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  # S09, S10:RBAC 變更 → 最高層級記錄
  - level: RequestResponse
    resources:
      - group: "rbac.authorization.k8s.io"
        resources:
          - clusterroles
          - clusterrolebindings
          - roles
          - rolebindings
    verbs: ["create", "update", "patch", "delete"]

  # S10:ServiceAccount 操作
  - level: RequestResponse
    resources:
      - group: ""
        resources: ["serviceaccounts"]
    verbs: ["create", "update", "patch", "delete"]

  # S03, S25, S26:Secret 存取
  - level: Metadata
    resources:
      - group: ""
        resources: ["secrets"]

  # S11:Webhook 配置變更
  - level: RequestResponse
    resources:
      - group: "admissionregistration.k8s.io"
        resources:
          - mutatingwebhookconfigurations
          - validatingwebhookconfigurations
    verbs: ["create", "update", "patch", "delete"]

  # S04, S05:Pod exec/attach
  - level: RequestResponse
    resources:
      - group: ""
        resources: ["pods/exec", "pods/attach"]

  # S07, S33:CronJob 變更
  - level: RequestResponse
    resources:
      - group: "batch"
        resources: ["cronjobs", "jobs"]
    verbs: ["create", "update", "patch", "delete"]

  # 高頻低風險端點不記錄
  - level: None
    nonResourceURLs: ["/healthz*", "/readyz*", "/livez*"]

  # 預設:其餘記錄 Metadata
  - level: Metadata
    omitStages: ["RequestReceived"]

啟用 Audit Log

在 API Server 的啟動參數中加入:

# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
    - command:
        - kube-apiserver
        - --audit-policy-file=/etc/kubernetes/audit/audit-policy.yaml
        - --audit-log-path=/var/log/kubernetes/audit.log
        - --audit-log-maxage=30         # 保留 30 天
        - --audit-log-maxbackup=10      # 最多 10 個備份檔
        - --audit-log-maxsize=100       # 每個檔案 100MB
      volumeMounts:
        - name: audit-policy
          mountPath: /etc/kubernetes/audit
          readOnly: true
        - name: audit-log
          mountPath: /var/log/kubernetes
  volumes:
    - name: audit-policy
      hostPath:
        path: /etc/kubernetes/audit
    - name: audit-log
      hostPath:
        path: /var/log/kubernetes

Fluent Bit 日誌轉發配置

將 Audit Log 送到 Elasticsearch:

# fluent-bit.conf
[INPUT]
    Name    tail
    Tag     kube.audit
    Path    /var/log/kubernetes/audit.log
    Parser  json

[FILTER]
    Name    grep
    Match   kube.audit
    Regex   verb (create|update|patch|delete)

[OUTPUT]
    Name    es
    Match   kube.audit
    Host    elasticsearch.logging.svc
    Port    9200
    Index   k8s-audit
    Type    _doc

用 Audit Log 偵測各場景

S09:偵測 ClusterRoleBinding 建立

$ cat /var/log/kubernetes/audit.log | \
    jq 'select(.verb=="create" and
        .objectRef.resource=="clusterrolebindings") |
        {time: .requestReceivedTimestamp,
         user: .user.username,
         binding: .objectRef.name,
         role: .requestObject.roleRef.name}'
{
  "time": "2026-08-19T15:00:00Z",
  "user": "system:serviceaccount:koad:overprivileged-sa",
  "binding": "koad-attacker-admin",
  "role": "cluster-admin"
}

S10:偵測 kube-system 中 SA 建立

$ cat /var/log/kubernetes/audit.log | \
    jq 'select(.verb=="create" and
        .objectRef.resource=="serviceaccounts" and
        .objectRef.namespace=="kube-system") |
        {time: .requestReceivedTimestamp,
         user: .user.username,
         sa: .objectRef.name}'

S11:偵測 Webhook 配置變更

$ cat /var/log/kubernetes/audit.log | \
    jq 'select(.objectRef.resource | 
        test("webhookconfigurations")) |
        {time: .requestReceivedTimestamp,
         verb: .verb,
         user: .user.username,
         webhook: .objectRef.name}'

偵測異常 RBAC 的規則

# 找出所有綁定到 cluster-admin 的 binding
$ kubectl get clusterrolebindings -o json | \
    jq '.items[] |
        select(.roleRef.name == "cluster-admin") |
        {name: .metadata.name,
         subjects: [.subjects[]? | "\(.kind)/\(.namespace)/\(.name)"],
         created: .metadata.creationTimestamp}'

正常 cluster-admin 綁定(K8s 內建):

  • cluster-adminsystem:masters group
  • minikube-rbacminikube-user

異常綁定(攻擊者建立):

  • koad-attacker-adminServiceAccount/koad/attacker-sa
  • system-controller-bindingServiceAccount/kube-system/system-controller

防禦 S10:ServiceAccount 盤點

定期審計腳本

#!/bin/bash
# audit-sa.sh — 列出所有非預設的 ServiceAccount 及其權限

echo "=== 非預設 ServiceAccount ==="
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
  for sa in $(kubectl get sa -n "$ns" -o jsonpath='{.items[*].metadata.name}'); do
    if [ "$sa" != "default" ]; then
      echo ""
      echo "[$ns] $sa"
      kubectl auth can-i --list \
        --as="system:serviceaccount:$ns:$sa" 2>/dev/null | \
        grep -v "^Resources" | head -5
    fi
  done
done

偵測 kube-system 中的異常 SA

# kube-system 預設的 SA 清單(K8s 1.30)
EXPECTED_SAS="attachdetach-controller calico-kube-controllers calico-node
certificate-controller clusterrole-aggregation-controller coredns
cronjob-controller daemon-set-controller default deployment-controller
disruption-controller endpoint-controller endpointslice-controller
ephemeral-volume-controller expand-controller generic-garbage-collector
horizontal-pod-autoscaler job-controller namespace-controller
node-controller persistent-volume-binder pod-garbage-collector
pv-protection-controller pvc-protection-controller replicaset-controller
replication-controller resourcequota-controller root-ca-cert-publisher
service-account-controller service-controller statefulset-controller
storage-provisioner token-cleaner ttl-after-finished-controller
ttl-controller"

# 找出不在預期清單中的 SA
for sa in $(kubectl get sa -n kube-system -o jsonpath='{.items[*].metadata.name}'); do
  if ! echo "$EXPECTED_SAS" | grep -wq "$sa"; then
    echo "SUSPICIOUS: $sa"
    # 進一步檢查權限
    echo "  Permissions:"
    kubectl auth can-i --list \
      --as="system:serviceaccount:kube-system:$sa" 2>/dev/null | \
      grep -E "^\*|cluster-admin" | head -3
  fi
done

輸出:

SUSPICIOUS: system-controller    ← S10 的後門 SA
  Permissions:
  *.*         []    []    [*]    ← cluster-admin!

自動化 SA 審計(CronJob)

將審計腳本包裝成 K8s CronJob,定期執行並發送告警:

apiVersion: batch/v1
kind: CronJob
metadata:
  name: sa-audit
  namespace: security
spec:
  schedule: "0 */6 * * *"     # 每 6 小時執行
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: sa-auditor
          containers:
            - name: auditor
              image: bitnami/kubectl:1.30
              command: ["/bin/bash", "-c"]
              args:
                - |
                  EXPECTED=35  # kube-system 預期的 SA 數量
                  ACTUAL=$(kubectl get sa -n kube-system --no-headers | wc -l)
                  if [ "$ACTUAL" -gt "$EXPECTED" ]; then
                    echo "ALERT: kube-system SA count changed: expected=$EXPECTED actual=$ACTUAL"
                    # 送告警到 Slack webhook
                    curl -X POST "$SLACK_WEBHOOK" \
                      -d "{\"text\": \"SA count anomaly in kube-system: $ACTUAL (expected: $EXPECTED)\"}"
                  fi
          restartPolicy: OnFailure

Falco k8s_audit 規則

- rule: K8s SA Created in kube-system
  desc: Detect creation of ServiceAccount in kube-system namespace
  condition: >
    ka.verb = "create" and
    ka.target.resource = "serviceaccounts" and
    ka.target.namespace = "kube-system" and
    not ka.user.name in (kube_system_sa_creators)
  output: >
    ServiceAccount created in kube-system
    (user=%ka.user.name sa=%ka.target.name ns=%ka.target.namespace)
  priority: WARNING
  source: k8s_audit
  tags: [k8s, persistence, T1136]

防禦 S11:Webhook 審計

列出所有 Webhook

# Mutating Webhooks
$ kubectl get mutatingwebhookconfigurations -o custom-columns=\
NAME:.metadata.name,\
WEBHOOKS:.webhooks[*].name,\
SERVICE:.webhooks[*].clientConfig.service.name

# Validating Webhooks
$ kubectl get validatingwebhookconfigurations -o custom-columns=\
NAME:.metadata.name,\
WEBHOOKS:.webhooks[*].name,\
SERVICE:.webhooks[*].clientConfig.service.name

已知合法 Webhook(以 KOAD 環境為例)

Webhook 來源 用途
kyverno-policy-mutating-webhook Kyverno 策略 Mutation
kyverno-resource-mutating-webhook Kyverno 資源 Mutation
kyverno-policy-validating-webhook Kyverno 策略 Validation
kyverno-resource-validating-webhook Kyverno 資源 Validation

任何不在這個清單中的 Webhook 都需要調查。

Kyverno 策略:監控 Webhook 變更

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: audit-webhook-changes
spec:
  validationFailureAction: Audit
  rules:
    - name: log-webhook-creation
      match:
        any:
          - resources:
              kinds:
                - MutatingWebhookConfiguration
                - ValidatingWebhookConfiguration
      validate:
        message: "Webhook configuration change detected — review required"
        deny: {}

防禦 S12:Cosign 映像簽章 + Kyverno 驗簽

Cosign 簽章流程

# 1. 產生金鑰對
$ cosign generate-key-pair
Enter password for private key:
Private key written to cosign.key
Public key written to cosign.pub

# 2. 簽署映像
$ cosign sign --key cosign.key myregistry.io/myapp:v1.0

# 3. 驗證簽章
$ cosign verify --key cosign.pub myregistry.io/myapp:v1.0

Keyless Signing(Sigstore / Fulcio)

Cosign 2.0+ 支援 Keyless Signing——不需要管理金鑰,透過 OIDC 身份驗證自動簽章:

# Keyless signing(會開啟瀏覽器進行 OIDC 登入)
$ cosign sign myregistry.io/myapp:v1.0
# 自動使用 Fulcio CA 簽發短期證書
# 簽章記錄上傳到 Rekor 透明日誌

# Keyless verify
$ cosign verify myregistry.io/myapp:v1.0 \
    --certificate-identity=ci@company.com \
    --certificate-oidc-issuer=https://accounts.google.com

Sigstore 三大元件:

元件 功能 類比
Fulcio 短期證書簽發(基於 OIDC 身份) Let's Encrypt
Rekor 簽章透明日誌(不可篡改) Certificate Transparency
Cosign 客戶端簽章/驗證工具 GPG

完整 CI/CD 簽章流程(GitHub Actions)

name: Build, Sign, Deploy
on:
  push:
    branches: [main]

jobs:
  build-and-sign:
    runs-on: ubuntu-latest
    permissions:
      id-token: write       # 需要 OIDC token for keyless signing
      contents: read
      packages: write
    steps:
      - uses: actions/checkout@v4

      - name: Build and push image
        run: |
          docker build -t ghcr.io/${{ github.repository }}:${{ github.sha }} .
          docker push ghcr.io/${{ github.repository }}:${{ github.sha }}

      - name: Install Cosign
        uses: sigstore/cosign-installer@v3

      - name: Sign image (keyless)
        run: |
          cosign sign ghcr.io/${{ github.repository }}:${{ github.sha }}
        env:
          COSIGN_EXPERIMENTAL: 1

      - name: Verify signature
        run: |
          cosign verify ghcr.io/${{ github.repository }}:${{ github.sha }} \
            --certificate-identity-regexp=".*@company.com" \
            --certificate-oidc-issuer="https://token.actions.githubusercontent.com"

Kyverno 驗簽策略

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: verify-image-signature
spec:
  validationFailureAction: Enforce    # 阻擋未簽章映像
  rules:
    - name: verify-cosign
      match:
        any:
          - resources:
              kinds: ["Pod"]
      verifyImages:
        - imageReferences:
            - "myregistry.io/*"
          attestors:
            - entries:
                - keys:
                    publicKeys: |-
                      -----BEGIN PUBLIC KEY-----
                      MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
                      -----END PUBLIC KEY-----

啟用後,任何來自 myregistry.io 但沒有有效 Cosign 簽章的映像都會被拒絕部署。

映像安全的完整流程

開發者 build 映像


OPA Gatekeeper vs Kyverno 比較

兩大 K8s 策略引擎,選哪個用來防禦持久化?

特性 OPA Gatekeeper Kyverno
策略語言 Rego(專用語言) YAML(K8s 原生)
學習曲線 陡峭(需學 Rego) 平緩(YAML 即策略)
映像驗簽 需要額外整合 原生支援 verifyImages
Mutation 支援 支援(更直觀)
生態系統 大(CNCF 畢業) 成長中(CNCF 孵化)
除錯 困難(Rego trace) 容易(PolicyReport)
CKS 考試 不考 可能出現

Rego vs YAML 策略範例(阻擋 privileged pod):

Gatekeeper (Rego):

package k8sblockprivileged

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  container.securityContext.privileged == true
  msg := sprintf("Privileged container: %v", [container.name])
}

Kyverno (YAML):

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: block-privileged
spec:
  validationFailureAction: Enforce
  rules:
    - name: deny-privileged
      match:
        any:
          - resources:
              kinds: ["Pod"]
      validate:
        message: "Privileged containers are not allowed"
        pattern:
          spec:
            containers:
              - securityContext:
                  privileged: "!true"

KOAD 選擇 Kyverno 的原因:

  1. YAML 原生——不需要學新語言
  2. 原生支援 verifyImages——Cosign 整合開箱即用
  3. PolicyReport——審計模式下自動產生違規報告
  4. 社群活躍——CNCF 孵化專案,版本迭代快

防禦成熟度模型

將持久化防禦分為三個層級,團隊可以逐步提升:

Level 1:手動審計(最低標準)

防禦措施 頻率 工具
RBAC 盤點 每週 kubectl get clusterrolebindings + 人工比對
SA 審計 每週 audit-sa.sh 腳本
Webhook 檢查 每月 kubectl get mutatingwebhookconfigurations
映像掃描 部署前 trivy image 手動執行

Level 2:自動偵測(建議標準)

防禦措施 頻率 工具
Audit Log 告警 即時 Falco k8s_audit + 告警規則
SA 數量監控 每 6 小時 CronJob + Slack 告警
Webhook 變更偵測 即時 Kyverno Audit 策略
映像簽章驗證 部署時 Kyverno verifyImages(Audit 模式)

Level 3:自動阻擋 + 修復(目標標準)

防禦措施 頻率 工具
RBAC 異動自動回滾 即時 Falco Talon(Day 26)
未知 SA 自動刪除 即時 Kyverno + 自動修復
未簽章映像自動阻擋 部署時 Kyverno verifyImages(Enforce 模式)
Webhook 白名單強制 部署時 Kyverno Enforce + 白名單

Level 1 → Level 2 → Level 3

KOAD 的定位: KOAD 靶場覆蓋 Level 1-2 的完整實作,並示範 Level 3 的關鍵技術(Falco Talon 自動回應、Kyverno Enforce 模式)。


防禦架構:多層偵測

API Server

  • Audit Log:偵測 S09 RBAC 竄改、S10 後門 SA、S03 Secret 存取
  • Admission Control:阻擋 S12 未簽章映像、監控 S11 Webhook 變更
  • Runtime(Falco):偵測 S04 Shell、S05 kubectl、S26 Token 讀取

三層各有專長,組合起來才能覆蓋 Persistence 戰術的所有技術。


CKS 考點對照

考點 本日內容 權重
Audit Log 配置 四級設定 + 策略檔案撰寫 Monitoring/Runtime 20%
RBAC 審計 ClusterRoleBinding 盤點與監控 Cluster Hardening 15%
映像簽章 Cosign + Kyverno verifyImages Supply Chain 20%
Webhook 安全 審計 MutatingWebhookConfiguration Supply Chain 20%

CKS 考試中,Audit Log 的配置是高頻考題。你需要能夠:

  1. 撰寫 Audit Policy YAML(指定哪些資源用哪個級別記錄)
  2. 配置 API Server 啟用 Audit(掛載 volume、加啟動參數)
  3. 從 Audit Log 中用 jq 分析特定事件
  4. 設定適當的保留策略(maxage/maxbackup/maxsize)

KOAD 防禦驗證

# 驗證 Audit Policy 是否覆蓋關鍵資源
$ grep -A3 "level: RequestResponse" defense/audit/audit-policy.yaml | \
    grep "resources:" | sort -u
        resources: ["clusterroles", "clusterrolebindings", ...]
        resources: ["pods"]
        resources: ["cronjobs", "jobs"]
        resources: ["serviceaccounts"]
        resources: ["mutatingwebhookconfigurations", ...]
        resources: ["pods/exec", "pods/attach"]

# 驗證 Kyverno 策略狀態
$ kubectl get cpol
NAME                             READY
koad-block-privileged            True
koad-block-hostpath              True
koad-require-trusted-registry    True    ← 映像白名單
koad-disable-automount-sa        True
...

清理與重設

如果你需要還原環境:

# 主機終端 — 移除測試用的 RBAC 物件
kubectl delete clusterrolebinding backdoor-admin 2>/dev/null
kubectl delete serviceaccount backdoor-sa -n kube-system 2>/dev/null

# 還原 Kyverno 策略到 Audit 模式
kubectl get clusterpolicies -o name | xargs -I{} \
  kubectl patch {} --type merge -p '{"spec":{"validationFailureAction":"Audit"}}'

Audit Log 不需要清理——它是唯讀的歷史記錄。


Troubleshooting

問題 原因 解法
Audit Log 檔案不存在 API Server 未啟用 Audit 或 volume 掛載失敗 檢查 /etc/kubernetes/manifests/kube-apiserver.yaml--audit-policy-file--audit-log-path 參數及 volume 掛載
jq 解析 Audit Log 出現 parse error 日誌檔中有不完整的 JSON 行(寫入中途被截斷) 改用 cat audit.log | grep "^{" | jq ... 過濾非 JSON 行
Cosign generate-key-pair 失敗:permission denied 寫入 cosign.key 的目錄沒有寫入權限 切換到有寫入權限的目錄(如 $HOME)再執行
Kyverno verifyImages 策略 Enforce 後所有 Pod 都被拒絕 publicKeys 配置錯誤或映像確實未簽章 先改回 validationFailureAction: Audit,用 kubectl get policyreport -A 檢查違規細節
SA 審計腳本 kubectl auth can-i --list --as=... 回傳空結果 --as 語法錯誤或目前使用者無 impersonation 權限 格式必須是 --as=system:serviceaccount:<ns>:<sa>,且使用者需要 impersonate 動詞權限

真實環境 vs KOAD 靶場

面向 KOAD 靶場 真實生產環境
Admission Controller 通常未啟用 OPA/Kyverno 生產環境通常有 Admission Controller 阻擋異常 Pod Spec
Image Policy 無 image 簽章驗證 可能有 Cosign/Notary 驗證,阻擋未簽章 image
Audit Log 預設未開啟或未收集 生產環境通常有 Audit Log 送到 SIEM

KOAD 中防禦機制需要手動部署。真實環境中,這些防禦通常已經部分存在,挑戰在於確認覆蓋率和正確性。


本日小結

你完成了什麼

  • [x] 理解 K8s Audit Log 四級設定(None / Metadata / Request / RequestResponse)
  • [x] 撰寫 Audit Policy 覆蓋 RBAC、SA、Webhook 等關鍵資源
  • [x] 用 jq 分析 Audit Log 中的 RBAC 異動事件
  • [x] 建立 SA 定期盤點機制
  • [x] 理解 Cosign 映像簽章 + Kyverno 驗簽流程
  • [x] 掌握三層偵測架構的互補關係

完成度自我檢查

  • [ ] 能解釋 K8s Audit Log 四級設定(None / Metadata / Request / RequestResponse)的差異
  • [ ] 能撰寫 Audit Policy 覆蓋 RBAC、SA、Webhook 等關鍵資源
  • [ ] 能用 jq 從 Audit Log 中過濾出 ClusterRoleBinding 建立事件
  • [ ] 已建立 SA 定期盤點機制(手動或 CronJob 自動化)
  • [ ] 能用 Cosign 簽署映像並用 Kyverno 驗簽策略阻擋未簽署映像
  • [ ] 能說明 Audit Log + Admission Control + Runtime 三層偵測的互補關係

關鍵帶走

  1. Audit Log:K8s 原生的審計機制,配合 Fluent Bit 轉發到 SIEM,即時偵測 RBAC 竄改和 SA 建立
  2. SA 盤點:定期比對 kube-system 中的 SA 是否有異常,自動化 CronJob 告警
  3. Webhook 審計:監控 MutatingWebhookConfiguration 變更,建立 Webhook 白名單
  4. 映像簽章:Cosign(含 Keyless)+ Kyverno 從供應鏈層面阻擋後門映像

核心觀念:持久化攻擊發生在 API 物件層面,偵測也必須在 API 層面進行。 Falco 的 syscall 規則擅長偵測 Runtime 行為,但 RBAC 變更和 Webhook 配置需要 Audit Log。這兩套系統互補,缺一不可。

下一步

明天 Day 8 進入 TA0004 Privilege Escalation 的重頭戲——容器逃逸第一式:Privileged 容器 mount device。



上一篇
Day 6|五種持久化:RBAC 竄改 + 後門 SA + Sidecar 注入 + 映像植入
系列文
資安這條路:從攻擊者視角看 Kubernetes7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言