Chuyển đến nội dung chính

第7課: SecurityContext、Capabilities 與 ServiceAccounts

SecurityContext 的 Pod 層級和 Container 層級設定: runAsUser、runAsNonRoot、 readOnlyRootFilesystem。Linux capabilities。ServiceAccount 建立與綁定。

SecurityContext — Pod 層級 vs Container 層級、Linux capabilities

1. SecurityContext

SecurityContext 定義 Pod 或 Container 的權限和存取控制。

apiVersion: v1
kind: Pod
spec:
  securityContext:            # Pod 層級: 套用於所有容器
    runAsUser: 1000           # 容器執行 UID
    runAsGroup: 3000          # 主要 GID
    fsGroup: 2000             # 掛載 volume 的 GID
    runAsNonRoot: true        # 禁止以 root 執行

  containers:
  - name: app
    image: myapp
    securityContext:          # Container 層級: 覆蓋 Pod 層級
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true   # 將根檔案系統設為唯讀
      capabilities:
        add: ["NET_BIND_SERVICE"]    # 新增 capability
        drop: ["ALL"]               # 先 drop 全部,再新增需要的
設定項目層級效果
runAsUserPod/Container以指定 UID 執行程序
runAsNonRootPod/ContainerUID = 0(root)時拒絕執行
readOnlyRootFilesystemContainer將根檔案系統設為唯讀掛載
allowPrivilegeEscalationContainer阻擋權限提升(如 sudo)
privilegedContainer以特權模式執行(等同 host 上的 root)
fsGroupPodVolume 檔案的 GID(用於共享 volume 存取)

考試重點: Container 層級的 securityContext 會覆蓋 Pod 層級的設定。Pod 設定 runAsUser: 1000,Container 設定 runAsUser: 2000,該容器會以 UID 2000 執行。常考模式: kubectl exec pod -- id 或 whoami 確認使用者。

2. Linux Capabilities

Capabilities 允許在不給予完整 root 權限的情況下授予特定權限。

# 常見範例:
NET_BIND_SERVICE  — 綁定 1024 以下的埠號(如 port 80)
NET_ADMIN         — 網路管理(ifconfig 等)
SYS_TIME          — 修改系統時鐘
CHOWN             — 變更檔案所有者
SETUID/SETGID     — 變更使用者/群組 ID

securityContext:
  capabilities:
    drop: ["ALL"]             # 最佳實踐: 先 drop 全部
    add: ["NET_BIND_SERVICE"] # 只加回需要的

3. ServiceAccounts

Pod 使用 ServiceAccount 向 Kubernetes API 進行身份驗證。

# 建立 ServiceAccount
kubectl create serviceaccount my-sa

# 綁定 Role
kubectl create rolebinding my-binding \
  --role=pod-reader \
  --serviceaccount=default:my-sa

# 在 Pod 中指定 SA
spec:
  serviceAccountName: my-sa     # 使用指定的 SA
  automountServiceAccountToken: false  # 停用 SA token 自動掛載

# 預設行為: default SA 的 token 會掛載到 /var/run/secrets/kubernetes.io/serviceaccount/
# 容器可使用該 token 呼叫 K8s API
概念說明
預設 SA每個 Namespace 都有內建的 default SA(最小權限)
Token 掛載除非停用,token 會自動掛載到 Pod
automountServiceAccountToken: false停用 token 掛載(安全最佳實踐)

4. readOnlyRootFilesystem + emptyDir

# readOnlyRootFilesystem: true 時,應用無法寫入根檔案系統。
# 但應用可能需要寫入暫存檔案 → 使用 emptyDir volume:

spec:
  containers:
  - name: app
    image: myapp
    securityContext:
      readOnlyRootFilesystem: true
    volumeMounts:
    - name: tmp
      mountPath: /tmp        # 暫存檔案寫入此處
    - name: cache
      mountPath: /app/cache
  volumes:
  - name: tmp
    emptyDir: {}
  - name: cache
    emptyDir: {}

5. 速查表

任務YAML / 指令
以非 root 執行容器securityContext: runAsNonRoot: true
以指定 UID 執行securityContext: runAsUser: 1000
唯讀檔案系統securityContext: readOnlyRootFilesystem: true
Drop 所有 capabilitiescapabilities: drop: ["ALL"]
指定 ServiceAccountspec: serviceAccountName: my-sa
確認容器使用者kubectl exec pod -- whoami

6. 練習題

Q1: Pod spec 的 securityContext.runAsUser 設定為 1000(Pod 層級)。Pod 中某個容器的 securityContext.runAsUser 設定為 2000。該容器以哪個 UID 執行?

  • A) 0(root,Pod 層級覆蓋)
  • B) 1000(Pod 層級優先)
  • C) 2000(Container 層級覆蓋 Pod 層級) ✓
  • D) 同時以兩個 UID 執行

解析: Container 層級的 securityContext 設定會覆蓋 Pod 層級。該容器以 UID 2000 執行。同一 Pod 中沒有設定 Container 層級 securityContext 的其他容器會繼承 Pod 層級的 UID 1000。

Q2: 應用容器需要綁定 port 80(1024 以下的特權埠號),但不應以 root 執行。如何設定?

  • A) 設定 securityContext.privileged: true
  • B) 設定 securityContext.runAsUser: 0
  • C) Drop 所有 capabilities 後只加回 NET_BIND_SERVICE ✓
  • D) 使用 NodePort Service 替代 port 80

解析: Linux capabilities 提供細粒度的權限授予。NET_BIND_SERVICE 允許不以 root 身份綁定 1024 以下的埠號。最佳實踐是先 drop 全部再新增需要的: capabilities: { drop: ["ALL"], add: ["NET_BIND_SERVICE"] }。

Q3: 一個 Pod 設定了 readOnlyRootFilesystem: true。應用嘗試寫入 /tmp 但失敗。最佳解決方案是什麼?

  • A) 移除 readOnlyRootFilesystem: true
  • B) 設定 securityContext.privileged: true
  • C) 在 /tmp 掛載 emptyDir volume ✓
  • D) 在 /tmp 掛載 ConfigMap

解析: readOnlyRootFilesystem 阻止對容器檔案系統的寫入,但 emptyDir volume 是另一個可寫入的掛載點。在 /tmp 掛載 emptyDir 後,根檔案系統保持唯讀,但應用可以寫入暫存檔案。