14-Pod 安全上下文

Pod 安全上下文

概念引入

直接跑一个默认容器会发生什么?

bash 复制代码
kubectl exec my-pod -- whoami
# 输出:root  ← 默认就是 root!

默认情况下,容器以 root 用户运行,拥有几乎所有 Linux 能力。如果你的应用有漏洞被攻破,攻击者可以:

  • 修改系统文件
  • 安装后门工具
  • 横向攻击其他 Pod

SecurityContext 就是给容器"降权"的手段------让容器以非 root 用户运行,只给必要的能力。
#mermaid-svg-JGv4FkSjAPFpyHG0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-JGv4FkSjAPFpyHG0 .error-icon{fill:#552222;}#mermaid-svg-JGv4FkSjAPFpyHG0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-JGv4FkSjAPFpyHG0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .marker.cross{stroke:#333333;}#mermaid-svg-JGv4FkSjAPFpyHG0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-JGv4FkSjAPFpyHG0 p{margin:0;}#mermaid-svg-JGv4FkSjAPFpyHG0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .cluster-label text{fill:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .cluster-label span{color:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .cluster-label span p{background-color:transparent;}#mermaid-svg-JGv4FkSjAPFpyHG0 .label text,#mermaid-svg-JGv4FkSjAPFpyHG0 span{fill:#333;color:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .node rect,#mermaid-svg-JGv4FkSjAPFpyHG0 .node circle,#mermaid-svg-JGv4FkSjAPFpyHG0 .node ellipse,#mermaid-svg-JGv4FkSjAPFpyHG0 .node polygon,#mermaid-svg-JGv4FkSjAPFpyHG0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .rough-node .label text,#mermaid-svg-JGv4FkSjAPFpyHG0 .node .label text,#mermaid-svg-JGv4FkSjAPFpyHG0 .image-shape .label,#mermaid-svg-JGv4FkSjAPFpyHG0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-JGv4FkSjAPFpyHG0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .rough-node .label,#mermaid-svg-JGv4FkSjAPFpyHG0 .node .label,#mermaid-svg-JGv4FkSjAPFpyHG0 .image-shape .label,#mermaid-svg-JGv4FkSjAPFpyHG0 .icon-shape .label{text-align:center;}#mermaid-svg-JGv4FkSjAPFpyHG0 .node.clickable{cursor:pointer;}#mermaid-svg-JGv4FkSjAPFpyHG0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .arrowheadPath{fill:#333333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGv4FkSjAPFpyHG0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-JGv4FkSjAPFpyHG0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGv4FkSjAPFpyHG0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-JGv4FkSjAPFpyHG0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .cluster text{fill:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 .cluster span{color:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-JGv4FkSjAPFpyHG0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-JGv4FkSjAPFpyHG0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-JGv4FkSjAPFpyHG0 .icon-shape,#mermaid-svg-JGv4FkSjAPFpyHG0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-JGv4FkSjAPFpyHG0 .icon-shape p,#mermaid-svg-JGv4FkSjAPFpyHG0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-JGv4FkSjAPFpyHG0 .icon-shape .label rect,#mermaid-svg-JGv4FkSjAPFpyHG0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-JGv4FkSjAPFpyHG0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-JGv4FkSjAPFpyHG0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-JGv4FkSjAPFpyHG0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} SecurityContext
✅ 加了 SecurityContext
user: 1000 (非 root)
capabilities: 全删,只加 NET_BIND_SERVICE
readOnlyRootFilesystem: true
❌ 默认(不安全)
user: root
CAP_SYS_ADMIN 等全部能力
可写文件系统

原理讲解

SecurityContext 的两个级别

级别 作用域 配置位置
Pod 级别 整个 Pod 所有容器 spec.securityContext
容器级别 单个容器 spec.containers[].securityContext
冲突时 容器级覆盖 Pod 级 更具体的生效

核心字段

yaml 复制代码
apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  # Pod 级别安全上下文
  securityContext:
    runAsNonRoot: true      # 必须以非 root 用户运行
    runAsUser: 1000         # 指定 UID
    runAsGroup: 3000        # 指定 GID
    fsGroup: 2000           # volume 挂载后文件的属组

  containers:
  - name: app
    image: nginx:1.27
    # 容器级别安全上下文(覆盖 Pod 级别)
    securityContext:
      allowPrivilegeEscalation: false    # 禁止提权
      readOnlyRootFilesystem: true        # 根文件系统只读
      capabilities:
        drop: ["ALL"]                     # 先删掉所有能力
        add: ["NET_BIND_SERVICE"]        # 再加回必要的最小能力
      runAsNonRoot: true

关键字段详解

字段 作用 推荐值
runAsNonRoot 强制以非 root 运行 true
runAsUser 指定运行用户 UID ≥ 1000
privileged 特权模式 永远 false
allowPrivilegeEscalation 允许提权 false
readOnlyRootFilesystem 根文件系统只读 true(需要写临时文件时注意挂 emptyDir)
capabilities.drop 删除的 Linux 能力 ["ALL"]
capabilities.add 额外添加的能力 按需加(如 NET_BIND_SERVICE 绑定低端口)

Capabilities:Linux 能力的精细化控制

Linux 的 root 权限被拆成了 ~40 个细粒度的"能力"(capabilities)。Docker/K8s 默认给容器一部分能力。
#mermaid-svg-ksMgJqszr6qqy4at{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ksMgJqszr6qqy4at .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ksMgJqszr6qqy4at .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ksMgJqszr6qqy4at .error-icon{fill:#552222;}#mermaid-svg-ksMgJqszr6qqy4at .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ksMgJqszr6qqy4at .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ksMgJqszr6qqy4at .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ksMgJqszr6qqy4at .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ksMgJqszr6qqy4at .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ksMgJqszr6qqy4at .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ksMgJqszr6qqy4at .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ksMgJqszr6qqy4at .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ksMgJqszr6qqy4at .marker.cross{stroke:#333333;}#mermaid-svg-ksMgJqszr6qqy4at svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ksMgJqszr6qqy4at p{margin:0;}#mermaid-svg-ksMgJqszr6qqy4at .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ksMgJqszr6qqy4at .cluster-label text{fill:#333;}#mermaid-svg-ksMgJqszr6qqy4at .cluster-label span{color:#333;}#mermaid-svg-ksMgJqszr6qqy4at .cluster-label span p{background-color:transparent;}#mermaid-svg-ksMgJqszr6qqy4at .label text,#mermaid-svg-ksMgJqszr6qqy4at span{fill:#333;color:#333;}#mermaid-svg-ksMgJqszr6qqy4at .node rect,#mermaid-svg-ksMgJqszr6qqy4at .node circle,#mermaid-svg-ksMgJqszr6qqy4at .node ellipse,#mermaid-svg-ksMgJqszr6qqy4at .node polygon,#mermaid-svg-ksMgJqszr6qqy4at .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ksMgJqszr6qqy4at .rough-node .label text,#mermaid-svg-ksMgJqszr6qqy4at .node .label text,#mermaid-svg-ksMgJqszr6qqy4at .image-shape .label,#mermaid-svg-ksMgJqszr6qqy4at .icon-shape .label{text-anchor:middle;}#mermaid-svg-ksMgJqszr6qqy4at .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ksMgJqszr6qqy4at .rough-node .label,#mermaid-svg-ksMgJqszr6qqy4at .node .label,#mermaid-svg-ksMgJqszr6qqy4at .image-shape .label,#mermaid-svg-ksMgJqszr6qqy4at .icon-shape .label{text-align:center;}#mermaid-svg-ksMgJqszr6qqy4at .node.clickable{cursor:pointer;}#mermaid-svg-ksMgJqszr6qqy4at .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ksMgJqszr6qqy4at .arrowheadPath{fill:#333333;}#mermaid-svg-ksMgJqszr6qqy4at .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ksMgJqszr6qqy4at .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ksMgJqszr6qqy4at .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ksMgJqszr6qqy4at .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ksMgJqszr6qqy4at .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ksMgJqszr6qqy4at .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ksMgJqszr6qqy4at .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ksMgJqszr6qqy4at .cluster text{fill:#333;}#mermaid-svg-ksMgJqszr6qqy4at .cluster span{color:#333;}#mermaid-svg-ksMgJqszr6qqy4at div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ksMgJqszr6qqy4at .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ksMgJqszr6qqy4at rect.text{fill:none;stroke-width:0;}#mermaid-svg-ksMgJqszr6qqy4at .icon-shape,#mermaid-svg-ksMgJqszr6qqy4at .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ksMgJqszr6qqy4at .icon-shape p,#mermaid-svg-ksMgJqszr6qqy4at .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ksMgJqszr6qqy4at .icon-shape .label rect,#mermaid-svg-ksMgJqszr6qqy4at .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ksMgJqszr6qqy4at .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ksMgJqszr6qqy4at .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ksMgJqszr6qqy4at :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 最佳实践:先全删再加
drop: ALL
add: NET_BIND_SERVICE
K8s 默认保留的
全部 Linux Capabilities (~40 种)
CAP_SYS_ADMIN
CAP_NET_ADMIN
CAP_SYS_TIME
CAP_NET_BIND_SERVICE
CAP_CHOWN
CAP_KILL
...

常见能力场景:

能力 何时需要
NET_BIND_SERVICE 绑定 1024 以下的端口(如 80、443)
NET_ADMIN 修改网络配置(iptables 等)
SYS_ADMIN 挂载文件系统、修改内核参数(危险
SYS_TIME 设置系统时间

Pod Security Standards(PSS)

除了手动配 SecurityContext,K8s 提供了三个开箱即用的安全策略级别:

复制代码
┌──────────────────────────────────────┐
│  privileged  →  unrestricted ← 啥都不限制        │
│  baseline    →  常见攻击应对 ← 禁止特权容器等      │
│  restricted  →  最强限制     ← 必须非 root + 只读  │
└──────────────────────────────────────┘

在 Namespace 上打标签来启用:

yaml 复制代码
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
  • enforce:违规就拒绝
  • audit:违规记审计日志但不拒绝
  • warn:违规发出警告

动手实验

配套实验位于 docs/labs/beginner/pod-security/

步骤 1:部署实验环境

bash 复制代码
cd docs/labs/beginner/pod-security
bash setup.sh

步骤 2:对比 root vs non-root

bash 复制代码
# 查看默认 Pod 的运行用户
kubectl exec default-pod -- whoami
# 输出:root

# 查看安全 Pod 的运行用户
kubectl exec secure-pod -- whoami
# 输出:whoami: unknown uid 1000 (1000 是故意设置的,不是 root)

步骤 3:验证只读文件系统

bash 复制代码
# 尝试在只读根文件系统中写入(/home 不在 emptyDir 挂载点上)
kubectl exec secure-pod -- touch /home/test
# 预期:touch: /home/test: Read-only file system  ← 拒绝写入!

# 对比:默认 Pod 可以写
kubectl exec default-pod -- touch /home/test
# 预期:成功(无输出)

步骤 4:验证 capabilities 裁剪

bash 复制代码
# 对比两个 Pod 的 capabilities
kubectl exec default-pod -- cat /proc/1/status | grep -i cap
kubectl exec secure-pod -- cat /proc/1/status | grep -i cap
# secure-pod 的 CapEff(有效能力集)明显更小

步骤 5:清理

bash 复制代码
bash teardown.sh

自检问题

  1. 基础 为什么默认以 root 运行容器不安全?runAsNonRoot: true 做了什么?

  2. 理解 capabilities.drop: ["ALL"] 然后 add: ["NET_BIND_SERVICE"] 这种做法好在哪里?直接保留默认能力不行吗?

  3. 应用 你的 Node.js 应用需要:① 绑定 80 端口 ② 写日志到 /var/log/app/ ③ 不能以 root 运行。写出对应的 SecurityContext 配置。

查看答案

  1. 默认以 root 运行意味着:容器进程拥有 root 权限和大量 Linux 能力(capabilities)。如果应用存在漏洞(如命令注入、路径穿越),攻击者可以利用这些权限修改系统文件、安装后门、甚至通过容器逃逸影响宿主机。runAsNonRoot: true 强制容器必须以非 0 的 UID 运行------如果你用 root 镜像,Pod 会直接启动失败(CreateContainerError),从源头防止了以 root 运行。

  2. 默认保留的能力(CAP_CHOWN, CAP_KILL 等约 15 种)对大多数应用来说是多余的 ------你的 Node.js 应用不需要 CAP_KILL 去杀别人的进程。最佳实践是"最小权限原则":全删后只加你明确需要的。这大大缩小了攻击面------即使应用被攻破,攻击者也没有能力做更多破坏。

yaml 复制代码
securityContext:
  runAsNonRoot: true
  runAsUser: 1000
  capabilities:
    drop: ["ALL"]
    add: ["NET_BIND_SERVICE"]  # 绑定 80 端口
# 日志目录需要写,所以根文件系统不能设为只读
# 或者更安全的做法:单独挂 emptyDir 到 /var/log/app/

📚 本文来自 K8s Guide ------ 开源免费的 Kubernetes 中文学习指南

  • 🗺️ 初学者轨道 + 面试轨道,从零基础到拿 Offer 一站式覆盖
  • 🧪 每篇文章配套 Kind 实验脚本,本地一键运行
复制代码
  🔗 本文源码:docs/beginner/20-gateway-api.md
相关推荐
山东科恩光电1 小时前
如何通过安全地毯提升工业环境的防护效果?
安全
zhbcddxr1 小时前
北京企业GEO防御风控能力测评:投毒监测与偏差修正排行
网络·人工智能·安全
AOwhisky3 小时前
Linux(CentOS)系统管理入门笔记(第二十一期)——防火墙管理(Firewalld)——zone、服务端口、富规则与端口转发
linux·运维·笔记·安全·centos·防火墙
腾飞开源4 小时前
01_K8s干货笔记之认识K8s
运维·笔记·云原生·容器·kubernetes·k8s·容器化部署
笨鸟先飞,勤能补拙10 小时前
AI 赋能网络安全:技术全景、成熟度评估与实战案例
人工智能·python·安全·web安全·网络安全·sqlite·github
加密狗复制模拟10 小时前
使用x64dbg进行超级狗super dog 加密狗逆向分析复制 超级狗克隆备份
安全·软件工程·个人开发·同态加密
ZeroNews内网穿透11 小时前
内网部署企业知识库,通过 HTTPS 隧道实现异地安全访问
安全·内网穿透
笨鸟先飞,勤能补拙12 小时前
AI 赋能网络安全领域深度剖析
网络·人工智能·windows·安全·web安全·网络安全·github
张忠琳13 小时前
【NPU】Ascend Docker Runtime v26.0.1 之二 runtime/process/process.go — 超深度逐行分析
云原生·容器·架构·kubernetes·npu·docker-runtime