# Implementing Pod Security Admission Controller

> 使用内置准入控制器在命名空间级别实施 Kubernetes Pod Security Admission（Pod 安全准入），强制执行基线和受限安全配置文件。

- Skill: `killvxk/implementing-pod-security-admission-controller` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add killvxk/implementing-pod-security-admission-controller`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/implementing-pod-security-admission-controller/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/implementing-pod-security-admission-controller

---


# 实施 Pod Security Admission 控制器

## 概述

Pod Security Admission（PSA，Pod 安全准入）是 Kubernetes 内置的准入控制器（v1.25 起稳定版），在命名空间级别强制执行 Pod 安全标准（Pod Security Standards）。它替代了已弃用的 PodSecurityPolicy（PSP），提供三种安全配置文件：Privileged（特权）、Baseline（基线）和 Restricted（受限），以及三种强制模式：enforce（强制）、audit（审计）和 warn（警告）。

## 前置条件

- Kubernetes v1.25+（PSA 为稳定/GA 版）
- 具有 cluster-admin 权限的 kubectl
- 无需依赖外部工具 - PSA 内置于 kube-apiserver

## Pod 安全标准

### Privileged（特权）配置文件
- **无限制** - 不施加任何限制
- 用例：系统级 Pod（kube-system、监控）

### Baseline（基线）配置文件
- **最低限制** - 防止已知权限提升
- 阻止：特权容器、hostPID、hostIPC、hostNetwork、hostPorts、某些卷类型、超出运行时默认值的能力添加

### Restricted（受限）配置文件
- **严格限制** - 遵循安全最佳实践
- 要求：非 root 运行、放弃所有能力、seccomp RuntimeDefault、考虑只读根文件系统
- 阻止：基线配置文件中的一切，加上 root 运行、权限提升、非批准的卷类型

## 强制模式

| 模式 | 行为 | 用例 |
|------|----------|----------|
| enforce | 拒绝违反策略的 Pod | 生产强制执行 |
| audit | 将违规记录到审计日志 | 强制执行前评估 |
| warn | 向用户显示警告 | 开发者反馈 |

## 实施

### 通过 Label 应用到命名空间

```yaml
# 受限强制执行，同时启用审计和警告
apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: v1.28
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: v1.28
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: v1.28
```

```yaml
# staging 使用基线强制执行
apiVersion: v1
kind: Namespace
metadata:
  name: staging
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/enforce-version: v1.28
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/audit-version: v1.28
    pod-security.kubernetes.io/warn: restricted
    pod-security.kubernetes.io/warn-version: v1.28
```

```yaml
# 系统命名空间使用特权模式
apiVersion: v1
kind: Namespace
metadata:
  name: kube-system
  labels:
    pod-security.kubernetes.io/enforce: privileged
```

### 使用 kubectl 应用 Label

```bash
# 设置受限强制执行
kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted \
  pod-security.kubernetes.io/enforce-version=v1.28 \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

# 设置基线强制执行
kubectl label namespace staging \
  pod-security.kubernetes.io/enforce=baseline \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted

# 检查当前 label
kubectl get namespace production -o jsonpath='{.metadata.labels}' | jq .
```

## 演练测试

```bash
# 测试在命名空间上应用受限策略的效果
kubectl label --dry-run=server --overwrite namespace staging \
  pod-security.kubernetes.io/enforce=restricted

# 输出显示已有哪些 Pod 会违反该策略
# 警告：命名空间 "staging" 中的现有 Pod 违反了新的 PodSecurity enforce 级别 "restricted:latest"
```

## 集群范围默认值（AdmissionConfiguration）

```yaml
# /etc/kubernetes/psa-config.yaml
apiVersion: apiserver.config.k8s.io/v1
kind: AdmissionConfiguration
plugins:
  - name: PodSecurity
    configuration:
      apiVersion: pod-security.admission.config.k8s.io/v1
      kind: PodSecurityConfiguration
      defaults:
        enforce: baseline
        enforce-version: latest
        audit: restricted
        audit-version: latest
        warn: restricted
        warn-version: latest
      exemptions:
        usernames: []
        runtimeClasses: []
        namespaces:
          - kube-system
          - kube-public
          - kube-node-lease
          - calico-system
          - gatekeeper-system
          - monitoring
          - falco
```

### 应用到 API Server

```bash
# 添加到 kube-apiserver 清单
# /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
  containers:
  - command:
    - kube-apiserver
    - --admission-control-config-file=/etc/kubernetes/psa-config.yaml
    volumeMounts:
    - name: psa-config
      mountPath: /etc/kubernetes/psa-config.yaml
      readOnly: true
  volumes:
  - name: psa-config
    hostPath:
      path: /etc/kubernetes/psa-config.yaml
      type: File
```

## 合规 Pod 示例

### 符合 Restricted 要求的 Pod

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: restricted-pod
  namespace: production
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 3000
    fsGroup: 2000
    seccompProfile:
      type: RuntimeDefault
  automountServiceAccountToken: false
  containers:
    - name: app
      image: myregistry/myapp:v1.0.0
      securityContext:
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop:
            - ALL
      resources:
        limits:
          cpu: 500m
          memory: 256Mi
        requests:
          cpu: 100m
          memory: 128Mi
      volumeMounts:
        - name: tmp
          mountPath: /tmp
  volumes:
    - name: tmp
      emptyDir: {}
```

### 符合 Baseline 要求的 Pod

```yaml
apiVersion: v1
kind: Pod
metadata:
  name: baseline-pod
  namespace: staging
spec:
  containers:
    - name: app
      image: myregistry/myapp:v1.0.0
      securityContext:
        allowPrivilegeEscalation: false
      resources:
        limits:
          cpu: 500m
          memory: 256Mi
```

## 从 PodSecurityPolicy 迁移

### 步骤 1：审计当前状态
```bash
# 检查现有 PSP
kubectl get psp

# 检查哪些 ServiceAccount 使用了哪个 PSP
kubectl get clusterrolebinding -o json | \
  jq '.items[] | select(.roleRef.name | startswith("psp-")) | {name: .metadata.name, subjects: .subjects}'
```

### 步骤 2：将 PSP 映射到 PSA 配置文件
```bash
# 对每个命名空间确定所需的 PSA 级别
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
  echo "命名空间：$ns"
  kubectl label --dry-run=server namespace $ns \
    pod-security.kubernetes.io/enforce=restricted 2>&1 | head -5
done
```

### 步骤 3：应用 PSA Label（先审计）
```bash
# 从审计模式开始
kubectl label namespace production \
  pod-security.kubernetes.io/audit=restricted \
  pod-security.kubernetes.io/warn=restricted
```

### 步骤 4：审查并修复违规
```bash
# 检查审计日志中的违规
kubectl get events --field-selector reason=FailedCreate -A
```

### 步骤 5：启用强制执行
```bash
kubectl label namespace production \
  pod-security.kubernetes.io/enforce=restricted
```

## 监控

```bash
# 检查事件中的 PSA 违规
kubectl get events --all-namespaces --field-selector reason=FailedCreate

# 检查审计日志
kubectl logs -n kube-system kube-apiserver-* | grep "pod-security.kubernetes.io"

# 列出命名空间的 PSA label
kubectl get namespaces -L pod-security.kubernetes.io/enforce
```

## 最佳实践

1. **先用审计+警告**，在强制执行前评估影响
2. **使用演练测试**，应用前测试强制执行效果
3. **豁免系统命名空间**（kube-system、监控），在集群默认值中排除
4. **固定版本**（enforce-version），确保跨升级的可预测行为
5. **将集群范围基线设为默认值**，然后针对特定命名空间收紧
6. **与 Gatekeeper 结合**，实现 PSA 之外的额外自定义策略
7. **所有生产工作负载使用受限配置文件**
8. **记录豁免并附清晰理由**

