跳转到内容

安全加固

业务场景

云咖啡公司的业务发展迅速,系统已经稳定运行了一段时间。随着公司规模扩大,安全团队提出了以下要求:

  • 不同部门的员工需要不同的操作权限
  • 各个服务之间需要网络隔离
  • 容器运行需要遵循安全规范
  • 敏感数据需要加密存储

作为运维工程师,你需要为云咖啡的 K8S 集群实施安全加固。

学习目标

完成本阶段后,你将掌握:

  • RBAC 权限管理:控制谁可以对哪些资源执行什么操作
  • NetworkPolicy:限制 Pod 之间的网络通信
  • Pod 安全标准:确保容器以安全的方式运行
  • Secret 加密:保护敏感数据的安全

前置知识

本阶段需要以下基础知识:

  • Kubernetes 核心概念(Pod、Deployment、Service)
  • 基本的 K8S 操作经验
  • 了解认证和授权的基本概念

提示:如果你已经掌握这些知识,可以直接开始实战。


第一部分:RBAC 权限管理

什么是 RBAC

RBAC(Role-Based Access Control,基于角色的访问控制)是 K8S 中控制权限的核心机制。它通过以下概念实现权限管理:

  • Role/ClusterRole:定义权限规则(能做什么)
  • ServiceAccount:代表一个身份(是谁)
  • RoleBinding/ClusterRoleBinding:将角色绑定到身份(谁能做什么)

场景:为开发团队创建只读权限

云咖啡公司的开发团队需要查看生产环境的资源状态,但不能修改。

步骤1:创建命名空间和测试资源

首先,创建 rbac-namespace.yaml 文件:

bash
cat > rbac-namespace.yaml << 'EOF'
# RBAC 演示:命名空间和测试资源
# 用途:创建 cloud-coffee-prod 命名空间和示例 Deployment
apiVersion: v1
kind: Namespace
metadata:
  name: cloud-coffee-prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee-shop
  namespace: cloud-coffee-prod
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coffee-shop
  template:
    metadata:
      labels:
        app: coffee-shop
    spec:
      containers:
      - name: coffee-shop
        image: nginx:alpine
        ports:
        - containerPort: 80
EOF

应用配置:

bash
kubectl apply -f rbac-namespace.yaml

步骤2:创建 ServiceAccount

创建 rbac-serviceaccount.yaml 文件:

bash
cat > rbac-serviceaccount.yaml << 'EOF'
# RBAC 演示:ServiceAccount
# 用途:创建 developer 服务账号
apiVersion: v1
kind: ServiceAccount
metadata:
  name: developer
  namespace: cloud-coffee-prod
EOF

应用配置:

bash
kubectl apply -f rbac-serviceaccount.yaml

步骤3:创建 Role(命名空间级别权限)

创建 rbac-role.yaml 文件:

bash
cat > rbac-role.yaml << 'EOF'
# RBAC 演示:Role(命名空间级别权限)
# 用途:定义 developer 的只读权限
# 权限说明:
#   - apiGroups:资源所属的 API 组
#   - resources:资源类型
#   - verbs:允许的操作(get 获取单个资源,list 列出资源,watch 监听变化)
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: developer-read-only
  namespace: cloud-coffee-prod
rules:
- apiGroups: [""]
  resources: ["pods", "deployments", "services", "configmaps", "secrets"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets"]
  verbs: ["get", "list", "watch"]
EOF

应用配置:

bash
kubectl apply -f rbac-role.yaml

步骤4:创建 RoleBinding

创建 rbac-rolebinding.yaml 文件:

bash
cat > rbac-rolebinding.yaml << 'EOF'
# RBAC 演示:RoleBinding
# 用途:将 developer-read-only 角色绑定到 developer 服务账号
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: developer-read-only-binding
  namespace: cloud-coffee-prod
subjects:
- kind: ServiceAccount
  name: developer
  namespace: cloud-coffee-prod
roleRef:
  kind: Role
  name: developer-read-only
  apiGroup: rbac.authorization.k8s.io
EOF

应用配置:

bash
kubectl apply -f rbac-rolebinding.yaml

步骤5:验证权限

bash

# 使用 developer 身份测试
kubectl auth can-i list pods -n cloud-coffee-prod --as=system:serviceaccount:cloud-coffee-prod:developer
# 输出: yes

kubectl auth can-i delete pods -n cloud-coffee-prod --as=system:serviceaccount:cloud-coffee-prod:developer
# 输出: no

📌 关于 --as 参数的解释

--as 用于模拟指定用户或服务账号执行命令,常用于 RBAC 权限测试。

语法--as=<用户名或服务账号>

使用场景

  • 测试 RBAC 规则是否正确配置
  • 验证用户是否有指定权限
  • 排查权限问题

常用命令

bash
# 检查当前用户权限
kubectl auth can-i list pods

# 模拟服务账号检查权限
kubectl auth can-i create deployments \
  --as=system:serviceaccount:myns:mysa \
  -n myns

# 模拟用户获取资源
kubectl get pods --as=developer -n myns

提示:需要有 impersonate 权限才能使用 --as

常用角色模板

只读权限

yaml
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps"]
  verbs: ["get", "list", "watch"]

开发权限(可部署应用):

yaml
rules:
- apiGroups: [""]
  resources: ["pods", "services", "configmaps", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "watch", "create", "update", "delete"]

管理员权限

yaml
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

第二部分:NetworkPolicy 网络策略

什么是 NetworkPolicy

NetworkPolicy 是 K8S 中控制 Pod 之间网络通信的机制。默认情况下,所有 Pod 可以相互通信,NetworkPolicy 可以限制这种通信。

注意:NetworkPolicy 需要网络插件支持(如 Calico、Cilium、Weave),Flannel 默认不支持。

场景:隔离云咖啡各服务

云咖啡系统包含:

  • 前端服务(coffee-frontend)
  • 后端 API(coffee-api)
  • 数据库(coffee-db)

安全要求:

  • 前端只能访问 API
  • API 只能访问数据库
  • 数据库只能被 API 访问

步骤1:部署测试应用

创建 networkpolicy-apps.yaml 文件:

bash
cat > networkpolicy-apps.yaml << 'EOF'
# NetworkPolicy 演示:测试应用部署
# 用途:部署前端、后端和数据库三个服务用于测试网络隔离
# 架构:frontend -> api -> db
apiVersion: v1
kind: Namespace
metadata:
  name: cloud-coffee
  labels:
    name: cloud-coffee
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee-frontend
  namespace: cloud-coffee
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coffee-frontend
  template:
    metadata:
      labels:
        app: coffee-frontend
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        ports:
        - containerPort: 80
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee-api
  namespace: cloud-coffee
spec:
  replicas: 2
  selector:
    matchLabels:
      app: coffee-api
  template:
    metadata:
      labels:
        app: coffee-api
    spec:
      containers:
      - name: api
        image: nginx:alpine
        ports:
        - containerPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: coffee-db
  namespace: cloud-coffee
spec:
  replicas: 1
  selector:
    matchLabels:
      app: coffee-db
  template:
    metadata:
      labels:
        app: coffee-db
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "root123"
        ports:
        - containerPort: 3306
EOF

应用配置:

bash
kubectl apply -f networkpolicy-apps.yaml

步骤2:创建默认拒绝策略

创建 networkpolicy-default-deny.yaml 文件:

bash
cat > networkpolicy-default-deny.yaml << 'EOF'
# NetworkPolicy 演示:默认拒绝策略
# 用途:拒绝所有入站和出站流量,作为安全基线
# 注意:此策略会阻断所有 Pod 的通信,需要配合其他策略使用
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny
  namespace: cloud-coffee
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress
EOF

应用配置:

bash
kubectl apply -f networkpolicy-default-deny.yaml

说明:此策略拒绝所有入站和出站流量,作为安全基线。

步骤3:允许前端访问 API

创建 networkpolicy-api.yaml 文件:

bash
cat > networkpolicy-api.yaml << 'EOF'
# NetworkPolicy 演示:API 服务策略
# 用途:
#   - 允许前端服务访问 API(入站)
#   - 允许 API 访问数据库(出站)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: coffee-api-policy
  namespace: cloud-coffee
spec:
  podSelector:
    matchLabels:
      app: coffee-api
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: coffee-frontend
    ports:
    - protocol: TCP
      port: 8080
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: coffee-db
    ports:
    - protocol: TCP
      port: 3306
EOF

应用配置:

bash
kubectl apply -f networkpolicy-api.yaml

步骤4:允许 API 访问数据库

创建 networkpolicy-db.yaml 文件:

bash
cat > networkpolicy-db.yaml << 'EOF'
# NetworkPolicy 演示:数据库策略
# 用途:只允许 API 服务访问数据库
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: coffee-db-policy
  namespace: cloud-coffee
spec:
  podSelector:
    matchLabels:
      app: coffee-db
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: coffee-api
    ports:
    - protocol: TCP
      port: 3306
EOF

应用配置:

bash
kubectl apply -f networkpolicy-db.yaml

步骤5:允许前端接受外部流量

创建 networkpolicy-frontend.yaml 文件:

bash
cat > networkpolicy-frontend.yaml << 'EOF'
# NetworkPolicy 演示:前端服务策略
# 用途:
#   - 允许所有外部流量访问前端(入站)
#   - 允许前端访问 API(出站)
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: coffee-frontend-policy
  namespace: cloud-coffee
spec:
  podSelector:
    matchLabels:
      app: coffee-frontend
  policyTypes:
  - Ingress
  - Egress
  ingress:
  - from: []  # 允许所有入站流量
    ports:
    - protocol: TCP
      port: 80
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: coffee-api
    ports:
    - protocol: TCP
      port: 8080
EOF

应用配置:

bash
kubectl apply -f networkpolicy-frontend.yaml

网络策略验证

bash
# 测试连接(使用临时 Pod)
# 测试前端是否可以访问 API(应该成功)
kubectl run test --image=busybox -n cloud-coffee --rm -it -- wget -qO- coffee-api:8080

# 测试前端是否可以直接访问数据库(应该失败)
kubectl run test --image=busybox -n cloud-coffee --rm -it -- wget -qO- coffee-db:3306

第三部分:Pod 安全标准

什么是 Pod 安全标准

Pod 安全标准定义了不同安全级别的容器运行要求:

  • Privileged(特权):不受限制,可能存在安全风险
  • Baseline(基线):禁止明显的特权提升
  • Restricted(受限):严格限制,遵循最佳实践

场景:为云咖啡配置安全策略

首先,创建启用 Pod 安全标准的命名空间:

bash
cat > pod-security-namespace.yaml << 'EOF'
# Pod 安全标准演示:安全命名空间
# 用途:创建启用 Restricted 安全策略的命名空间
# 标签说明:
#   - enforce:强制执行,违反策略的 Pod 会被拒绝
#   - audit:记录审计日志,不阻止
#   - warn:发出警告,不阻止
apiVersion: v1
kind: Namespace
metadata:
  name: cloud-coffee-secure
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
    pod-security.kubernetes.io/audit: restricted
    pod-security.kubernetes.io/warn: restricted
EOF

应用配置:

bash
kubectl apply -f pod-security-namespace.yaml

安全的 Pod 配置示例

创建符合 Restricted 标准的 Deployment:

bash
cat > pod-security-deployment.yaml << 'EOF'
# Pod 安全标准演示:安全 Deployment 配置
# 用途:展示符合 Restricted 标准的 Pod 安全配置
# 安全特性:
#   - 非 root 用户运行
#   - 只读根文件系统
#   - 禁止权限提升
#   - 移除所有 Linux capabilities
#   - 使用默认 seccomp 配置
apiVersion: apps/v1
kind: Deployment
metadata:
  name: secure-app
  namespace: cloud-coffee-secure
spec:
  replicas: 1
  selector:
    matchLabels:
      app: secure-app
  template:
    metadata:
      labels:
        app: secure-app
    spec:
      securityContext:
        runAsNonRoot: true
        runAsUser: 1000
        fsGroup: 1000
        seccompProfile:
          type: RuntimeDefault
      containers:
      - name: app
        image: nginx:alpine
        securityContext:
          allowPrivilegeEscalation: false
          readOnlyRootFilesystem: true
          capabilities:
            drop:
            - ALL
        ports:
        - containerPort: 80
        volumeMounts:
        - name: tmp
          mountPath: /tmp
        - name: cache
          mountPath: /var/cache/nginx
        - name: run
          mountPath: /var/run
      volumes:
      - name: tmp
        emptyDir: {}
      - name: cache
        emptyDir: {}
      - name: run
        emptyDir: {}
EOF

应用配置:

bash
kubectl apply -f pod-security-deployment.yaml

安全配置说明

配置项作用
runAsNonRoot: true禁止以 root 用户运行
runAsUser: 1000指定非特权用户 ID
readOnlyRootFilesystem: true根文件系统只读,防止篡改
allowPrivilegeEscalation: false禁止权限提升
capabilities.drop: ALL移除所有 Linux 能力
seccompProfile.type: RuntimeDefault使用默认的系统调用过滤

第四部分:Secret 加密存储

为什么需要加密 Secret

默认情况下,Secret 存储在 etcd 中是明文的。攻击者如果获得 etcd 访问权限,可以读取所有敏感数据。

⚠️ K3s 环境说明

K3s 使用 SQLite 而不是 etcd 作为默认存储后端,且已经内置了加密功能。本部分的 etcd 加密配置主要适用于标准 Kubernetes 集群(使用 kubeadm 部署)。

K3s 用户:可以了解加密原理,但不需要执行以下配置步骤。

场景:启用 Secret 加密(标准 K8s 集群)

步骤1:创建加密配置

创建 encryption-config.yaml 文件:

bash
# 生成 32 字节随机密钥
ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)

# 创建加密配置文件
cat > encryption-config.yaml << EOF
apiVersion: apiserver.config.k8s.io/v1
kind: EncryptionConfiguration
resources:
  - resources:
    - secrets
    providers:
    - aescbc:
        keys:
        - name: key1
          secret: ${ENCRYPTION_KEY}
    - identity: {}
EOF

步骤2:配置 kube-apiserver

⚠️ 生产环境注意事项

  • 此操作需要访问控制平面节点
  • 修改 kube-apiserver 配置需要重启服务
  • 建议在维护窗口执行
  • 执行前请备份现有配置

encryption-config.yaml 复制到控制平面节点:

bash
# 复制到 API Server 配置目录(在所有控制平面节点执行)
sudo cp encryption-config.yaml /etc/kubernetes/encryption-config.yaml
sudo chmod 600 /etc/kubernetes/encryption-config.yaml

编辑 kube-apiserver 静态 Pod 配置:

bash
# 编辑 kube-apiserver 配置
sudo vim /etc/kubernetes/manifests/kube-apiserver.yaml

command 部分添加以下参数:

yaml
- --encryption-provider-config=/etc/kubernetes/encryption-config.yaml

添加卷挂载:

yaml
volumeMounts:
- name: encryption-config
  mountPath: /etc/kubernetes/encryption-config.yaml
  readOnly: true

添加卷定义:

yaml
volumes:
- name: encryption-config
  hostPath:
    path: /etc/kubernetes/encryption-config.yaml
    type: File

保存后,kube-apiserver 会自动重启。

步骤3:加密现有 Secret

bash
# 创建测试 Secret
kubectl create secret generic db-password --from-literal=password=secret123 -n cloud-coffee

# 加密所有 Secret(重新写入触发加密)
kubectl get secrets --all-namespaces -o json | kubectl replace -f -

步骤4:验证加密

bash
# 直接读取 etcd(应该看到加密数据)
ETCDCTL_API=3 etcdctl get /registry/secrets/cloud-coffee/db-password \
  --endpoints=https://127.0.0.1:2379 \
  --cacert=/etc/kubernetes/pki/etcd/ca.crt \
  --cert=/etc/kubernetes/pki/etcd/server.crt \
  --key=/etc/kubernetes/pki/etcd/server.key

实战任务

完成以下任务巩固所学知识:

  1. 创建开发人员角色

    • 创建一个 ServiceAccount dev-user
    • 创建 Role 允许查看和创建 Deployment、Pod、Service
    • 验证权限是否正确
  2. 配置网络隔离

    • 部署三个应用:web、api、db
    • 配置 NetworkPolicy 实现:web->api->db 的单向访问
    • 验证隔离效果
  3. 安全加固 Pod

    • 创建一个符合 Restricted 标准的 Pod
    • 验证安全配置是否生效

课程总结

本阶段学习了 K8S 安全加固的核心技能:

内容作用生产环境重要性
RBAC控制访问权限
NetworkPolicy网络隔离中高
Pod 安全标准容器安全
Secret 加密数据保护

下一步学习第九阶段:生产运维

评论区

专业的Linux技术学习平台,从入门到精通的完整学习路径