Pod 和镜像安全
Pod 和镜像安全
Pod 和容器镜像是应用安全的基础,本节介绍如何加固 Pod 和镜像安全。
Security Context
Security Context 定义 Pod 和容器的权限和访问控制设置。
Pod 级别 Security Context
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
spec:
securityContext:
runAsNonRoot: true # 必须以非 root 用户运行
runAsUser: 1000 # 指定用户 ID
runAsGroup: 3000 # 指定组 ID
fsGroup: 2000 # 文件系统组 ID
fsGroupChangePolicy: "OnRootMismatch" # 仅在不匹配时更改
seccompProfile:
type: RuntimeDefault # 使用默认 seccomp 配置
containers:
- name: app
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false # 禁止权限提升
readOnlyRootFilesystem: true # 只读根文件系统
capabilities:
drop:
- ALL # 删除所有 capabilities
add:
- NET_BIND_SERVICE # 只添加必需的
Capabilities 管理
# ❌ 危险:给予过多权限
securityContext:
capabilities:
add:
- SYS_ADMIN # 几乎等同于 root
- NET_ADMIN
# ✅ 推荐:最小权限
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE # 绑定 1024 以下端口
- CHOWN # 更改文件所有权(如果需要)
常用 Capabilities:
NET_BIND_SERVICE: 绑定特权端口(< 1024)CHOWN: 更改文件所有权DAC_OVERRIDE: 绕过文件读写权限检查SETUID: 设置进程 UIDSETGID: 设置进程 GID
只读根文件系统
apiVersion: v1
kind: Pod
metadata:
name: readonly-root
spec:
containers:
- name: app
image: myapp:1.0
securityContext:
readOnlyRootFilesystem: true
# 挂载可写目录
volumeMounts:
- name: tmp
mountPath: /tmp
- name: cache
mountPath: /var/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
Pod Security Standards
Kubernetes 1.25+ 推荐使用 Pod Security Standards 替代 PSP。
三个级别
- Privileged: 无限制(不推荐)
- Baseline: 最低限制(基本安全)
- Restricted: 严格限制(推荐生产环境)
使用 Pod Security Admission
# 在 Namespace 上设置
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
Restricted 级别要求
apiVersion: v1
kind: Pod
metadata:
name: restricted-pod
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: myapp:1.0
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
镜像安全
镜像扫描 - Trivy
# 安装 Trivy
brew install aquasecurity/trivy/trivy
# 扫描镜像
trivy image myapp:latest
# 输出示例:
# myapp:latest (alpine 3.18.4)
# Total: 5 (CRITICAL: 1, HIGH: 2, MEDIUM: 2, LOW: 0)
#
# ┌────────────┬──────────────┬──────────┬──────────────┬───────────────┐
# │ Library │ Vulnerability│ Severity │ Installed │ Fixed Version │
# ├────────────┼──────────────┼──────────┼──────────────┼───────────────┤
# │ openssl │ CVE-2023-xxx │ CRITICAL │ 3.1.1 │ 3.1.2 │
# └────────────┴──────────────┴──────────┴──────────────┴───────────────┘
# 只显示高危及以上
trivy image --severity HIGH,CRITICAL myapp:latest
# 扫描并失败(CI/CD 中使用)
trivy image --exit-code 1 --severity CRITICAL myapp:latest
在 CI/CD 中集成 Trivy
# GitHub Actions
name: Scan Image
on: [push]
jobs:
scan:
runs-on: ubuntu-latest
steps:
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Run Trivy
uses: aquasecurity/trivy-action@master
with:
image-ref: 'myapp:${{ github.sha }}'
format: 'sarif'
output: 'trivy-results.sarif'
severity: 'CRITICAL,HIGH'
- name: Upload results
uses: github/codeql-action/upload-sarif@v2
with:
sarif_file: 'trivy-results.sarif'
镜像签名 - Cosign
# 安装 Cosign
brew install cosign
# 生成密钥对
cosign generate-key-pair
# 签名镜像
cosign sign --key cosign.key myregistry/myapp:v1.0.0
# 验证签名
cosign verify --key cosign.pub myregistry/myapp:v1.0.0
使用签名验证准入控制器
# 使用 Kyverno 验证镜像签名
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
name: verify-image-signature
spec:
validationFailureAction: enforce
rules:
- name: verify-signature
match:
any:
- resources:
kinds:
- Pod
verifyImages:
- imageReferences:
- "myregistry/*"
attestors:
- entries:
- keys:
publicKeys: |-
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE...
-----END PUBLIC KEY-----
私有镜像仓库
# 创建 Docker Registry Secret
kubectl create secret docker-registry regcred \
--docker-server=https://registry.example.com \
--docker-username=myuser \
--docker-password=mypassword \
--docker-email=myemail@example.com \
-n production
# 在 Pod 中使用
apiVersion: v1
kind: Pod
metadata:
name: myapp
spec:
imagePullSecrets:
- name: regcred
containers:
- name: app
image: registry.example.com/myapp:v1.0.0
Dockerfile 最佳实践
安全的 Dockerfile
# ❌ 不安全的写法
FROM ubuntu:latest
RUN apt-get update && apt-get install -y curl
COPY app /app
CMD ["/app"]
# ✅ 安全的写法
# 1. 使用特定版本标签
FROM node:18.19-alpine3.19
# 2. 创建非 root 用户
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
# 3. 设置工作目录
WORKDIR /app
# 4. 复制依赖文件并安装
COPY --chown=nodejs:nodejs package*.json ./
RUN npm ci --only=production && \
npm cache clean --force
# 5. 复制应用代码
COPY --chown=nodejs:nodejs . .
# 6. 切换到非 root 用户
USER nodejs
# 7. 暴露端口
EXPOSE 3000
# 8. 健康检查
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s \
CMD node healthcheck.js
# 9. 启动应用
CMD ["node", "server.js"]
多阶段构建
# 构建阶段
FROM node:18-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 生产阶段
FROM node:18-alpine AS production
RUN addgroup -g 1001 -S nodejs && \
adduser -S nodejs -u 1001
WORKDIR /app
COPY --from=builder --chown=nodejs:nodejs /app/dist ./dist
COPY --from=builder --chown=nodejs:nodejs /app/node_modules ./node_modules
COPY --chown=nodejs:nodejs package*.json ./
USER nodejs
EXPOSE 3000
CMD ["node", "dist/main.js"]
镜像优化
# 1. 使用 .dockerignore
# .dockerignore 文件:
node_modules
npm-debug.log
.git
.env
*.md
tests/
# 2. 合并 RUN 命令减少层数
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
# 3. 使用构建缓存
COPY package*.json ./
RUN npm ci
COPY . .
# 4. 清理不必要的文件
RUN npm ci --only=production && \
npm cache clean --force && \
rm -rf /tmp/*
PodDisruptionBudget
确保应用在节点维护时的可用性:
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
namespace: production
spec:
minAvailable: 2 # 至少保持 2 个 Pod 运行
selector:
matchLabels:
app: myapp
# 或使用百分比
apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
name: myapp-pdb
namespace: production
spec:
maxUnavailable: 1 # 最多 1 个 Pod 不可用
selector:
matchLabels:
app: myapp
运行时安全 - Falco
Falco 是云原生运行时安全工具,监测异常行为。
安装 Falco
# 使用 Helm 安装
helm repo add falcosecurity https://falcosecurity.github.io/charts
helm install falco falcosecurity/falco \
--namespace falco \
--create-namespace
Falco 规则示例
# 检测在容器中执行的 shell
- rule: Terminal shell in container
desc: A shell was spawned in a container
condition: >
spawned_process and container and
shell_procs and proc.tty != 0
output: >
Shell spawned in container
(user=%user.name container_id=%container.id
image=%container.image.repository)
priority: WARNING
# 检测容器中的特权升级
- rule: Privilege Escalation Detected
desc: Detect privilege escalation attempt
condition: >
spawned_process and container and
(proc.name in (sudo, su)) and
not user_known_privilege_escalation_activities
output: >
Privilege escalation detected
(user=%user.name command=%proc.cmdline
container=%container.id)
priority: CRITICAL
# 检测容器写入敏感目录
- rule: Write to sensitive directories
desc: Detect writes to sensitive directories
condition: >
open_write and container and
fd.name startswith /etc
output: >
File write to sensitive directory
(user=%user.name file=%fd.name
container=%container.id)
priority: WARNING
AppArmor 配置
AppArmor 提供强制访问控制(MAC)。
创建 AppArmor Profile
# /etc/apparmor.d/docker-nginx
#include <tunables/global>
profile docker-nginx flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
# 允许网络访问
network inet tcp,
network inet udp,
# 允许读取必要文件
/usr/sbin/nginx mr,
/etc/nginx/** r,
/var/log/nginx/** w,
# 拒绝其他访问
deny /etc/shadow r,
deny /etc/passwd w,
deny /proc/sys/** w,
}
在 Pod 中使用 AppArmor
apiVersion: v1
kind: Pod
metadata:
name: nginx-apparmor
annotations:
container.apparmor.security.beta.kubernetes.io/nginx: localhost/docker-nginx
spec:
containers:
- name: nginx
image: nginx:1.25-alpine
安全检查清单
# ✅ 使用以下配置
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-app
spec:
template:
spec:
# 1. ServiceAccount
serviceAccountName: app-sa
automountServiceAccountToken: false # 如果不需要
# 2. Pod Security Context
securityContext:
runAsNonRoot: true
runAsUser: 1000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault
containers:
- name: app
# 3. 镜像
image: myapp:v1.2.3 # 使用特定版本,不用 latest
imagePullPolicy: Always
# 4. Container Security Context
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
runAsNonRoot: true
capabilities:
drop:
- ALL
# 5. 资源限制
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 500m
memory: 512Mi
# 6. 健康检查
livenessProbe:
httpGet:
path: /health
port: 8080
readinessProbe:
httpGet:
path: /ready
port: 8080
# 7. 可写卷
volumeMounts:
- name: tmp
mountPath: /tmp
volumes:
- name: tmp
emptyDir: {}
小结
本节介绍了 Pod 和镜像安全:
✅ Security Context:runAsNonRoot、capabilities、只读文件系统
✅ Pod Security Standards:Restricted 级别配置
✅ 镜像扫描:Trivy 漏洞扫描
✅ 镜像签名:Cosign 签名验证
✅ Dockerfile:最佳实践和多阶段构建
✅ PDB:保证应用可用性
✅ 运行时安全:Falco、AppArmor
✅ 安全清单:生产级配置模板
下一节:Secret 管理和审计。