Day 20 - ServiceAccount、镜像安全与 Pod Security

📘 Day 20:ServiceAccount、镜像安全与 Pod Security

🎯 今日目标

  • 理解 Pod 默认挂载 SA Token 的含义
  • 能用 imagePullSecrets 拉取私有镜像
  • 能用 SecurityContext 控制容器权限
  • 理解 privileged/restricted/baseline 三个级别

🧠 理论精讲(30 分钟)

ServiceAccount 自动挂载

1
2
3
4
5
6
7
8
# 每个 Pod 默认会自动挂载 SA Token:
# /var/run/secrets/kubernetes.io/serviceaccount/token
# /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
# /var/run/secrets/kubernetes.io/serviceaccount/namespace

# 可通过以下方式禁用:
spec:
automountServiceAccountToken: false

SecurityContext 可控制的内容

配置 说明
runAsUser / runAsGroup 指定容器运行用户
runAsNonRoot 强制非 root 运行
privileged 特权模式(尽量不用)
allowPrivilegeEscalation 是否允许提权
readOnlyRootFilesystem 根文件系统只读
capabilities Linux Capabilities 管理

Pod Security Standards(PSS)

级别 说明 适用场景
Privileged 无限制 系统组件
Baseline 禁止已知风险(hostPath、特权) 普通应用
Restricted 严格限制(非 root、只读根文件系统) 安全要求高

🔧 动手实操(120 分钟)

练习 20.1:ServiceAccount 与 Token 管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 1. 查看 Pod 默认挂载的 SA Token
kubectl run sa-test --image=busybox:1.36 --restart=Never -- sleep 3600

kubectl exec sa-test -- ls /var/run/secrets/kubernetes.io/serviceaccount/
# ca.crt namespace token

kubectl exec sa-test -- cat /var/run/secrets/kubernetes.io/serviceaccount/token | head -3

# 2. 禁用自动挂载
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: no-sa-mount
spec:
automountServiceAccountToken: false
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
EOF

kubectl exec no-sa-mount -- ls /var/run/secrets/kubernetes.io/serviceaccount/ 2>&1
# ls: /var/run/secrets/kubernetes.io/serviceaccount/: No such file or directory

# 3. 创建自定义 SA
kubectl create sa custom-sa
kubectl run custom-sa-pod --image=busybox:1.36 --restart=Never --overrides='
{
"spec": {
"serviceAccountName": "custom-sa"
}
}' -- sleep 3600

kubectl get pod custom-sa-pod -o jsonpath='{.spec.serviceAccountName}'
# custom-sa

# 清理
kubectl delete pod sa-test no-sa-mount custom-sa-pod
kubectl delete sa custom-sa

练习 20.2:SecurityContext 安全上下文

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# 1. 非 root 用户运行
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: non-root-pod
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
fsGroup: 2000
containers:
- name: app
image: nginx:alpine
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
EOF

# 验证用户
kubectl exec non-root-pod -- id
# uid=1000 gid=3000

# 2. 设置 ReadOnlyRootFilesystem
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: readonly-pod
spec:
containers:
- name: app
image: nginx:alpine
securityContext:
readOnlyRootFilesystem: true
volumeMounts:
- name: nginx-run
mountPath: /var/run
- name: nginx-cache
mountPath: /var/cache/nginx
volumes:
- name: nginx-run
emptyDir: {}
- name: nginx-cache
emptyDir: {}
EOF

kubectl exec readonly-pod -- touch /test-file
# touch: /test-file: Read-only file system

# 3. Capabilities 管理
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: caps-pod
spec:
containers:
- name: app
image: busybox:1.36
command: ["sleep", "3600"]
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
- CHOWN
EOF

# 清理
kubectl delete pod non-root-pod readonly-pod caps-pod

练习 20.3:私有镜像仓库拉取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 1. 创建 Docker Registry Secret
kubectl create secret docker-registry private-registry \
--docker-server=registry.cn-hangzhou.aliyuncs.com \
--docker-username=your-username \
--docker-password=your-password \
--docker-email=your@email.com

# 2. 方式一:在 Pod 中指定
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: private-image-pod
spec:
imagePullSecrets:
- name: private-registry
containers:
- name: app
image: registry.cn-hangzhou.aliyuncs.com/your-ns/your-image:tag
EOF

# 3. 方式二:绑定到 ServiceAccount(推荐)
kubectl patch serviceaccount default -p '{"imagePullSecrets":[{"name":"private-registry"}]}'

# 验证
kubectl get sa default -o yaml | grep -A3 imagePullSecrets

# 4. 清理
kubectl delete pod private-image-pod
kubectl delete secret private-registry
# 恢复默认 SA
kubectl patch serviceaccount default --type=json \
-p='[{"op":"remove","path":"/imagePullSecrets"}]'

🐛 排错练习(30 分钟)

场景 1:镜像拉取失败(ErrImagePull / ImagePullBackOff)

1
2
3
4
5
6
7
8
9
10
11
12
# 排查步骤
# 1. 查看错误详情
kubectl describe pod <pod-name> | grep -A10 Events

# 2. 是否是私有镜像?
# → 检查是否配置了 imagePullSecrets

# 3. Secret 是否正确?
kubectl get secret <secret-name> -o jsonpath='{.data.\.dockerconfigjson}' | base64 -d | python3 -m json.tool

# 4. 镜像名是否正确?
# registry/namespace/image:tag

场景 2:Pod 启动后立即退出(Permission Denied)

1
2
3
4
5
6
# 可能是因为 SecurityContext 限制了权限
kubectl logs <pod-name>
# Permission denied

# 检查 SecurityContext
kubectl get pod <pod-name> -o yaml | grep -A15 securityContext

🏆 赛题模拟(40 分钟)

⚠️ 严格限时 35 分钟

题目:Pod 安全加固

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
【操作要求】

1. 创建命名空间 secure-workspace

2. 创建 ServiceAccount secure-runner:
- 禁用默认 Token 自动挂载

3. 创建私有仓库 Secret(模拟):
- Server: registry.internal.com
- Username: ci-bot
- Password: ci-token-123
- 将此 Secret 绑定到 secure-runner SA

4. 创建 Deployment secure-app(2副本,nginx:alpine):
- 使用 secure-runner SA
- SecurityContext:
* runAsUser: 1001
* runAsNonRoot: true
* allowPrivilegeEscalation: false
* readOnlyRootFilesystem: false(nginx 需要写临时文件)
* drop ALL capabilities
- 定义 resources.requests 和 limits
- livenessProbe + readinessProbe

5. 验证:
- SA 没有自动挂载 Token
- 容器以 uid 1001 运行
- 容器不能以 root 运行

【评分标准】
- SA 配置正确(15 分)
- 私有仓库 Secret + 绑定(20 分)
- SecurityContext 配置(35 分)
- 探针配置(15 分)
- 安全验证(15 分)