Kubernetes安全加固:我踩过的6个大坑和解决方案

2 阅读6分钟

为什么写这篇文章

最近在整理K8s安全相关的资料,发现大部分文章都是在罗列"应该做什么",但很少有人告诉你"为什么要做"以及"怎么做会踩坑"。

我自己在生产环境中踩过不少坑,有的甚至导致了线上事故。今天就把这些经验分享出来,希望能帮大家少走一些弯路。

💡 本文特色:每个配置都有真实的踩坑经历,不是简单的复制粘贴

坑1:RBAC没配好,实习生删了生产环境

问题描述

我们刚上K8s的时候,为了方便,给了所有开发人员管理员权限。当时觉得,都是自己人,应该没问题。

结果有个实习生在测试命令的时候,不小心执行了:

kubectl delete namespace production

直接把生产环境删了...

解决方案

# 给普通开发人员只读权限
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

---
# 绑定给具体用户
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: read-pods
  namespace: default
subjects:
- kind: User
  name: developer  # 换成你的用户名
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

怎么验证配置对不对

# 用developer用户测试
kubectl auth can-i list pods --as=developer
# 应该输出:yes

kubectl auth can-i delete pods --as=developer
# 应该输出:no

我的思考

RBAC配置看起来麻烦,但比起出事后的损失,这点麻烦算什么呢?建议一开始就配好,别等到出事了才后悔。

坑2:容器以root运行,被扫描出高危漏洞

问题描述

我们有个Java应用,容器启动后默认是root用户。当时也没在意,觉得反正容器是隔离的。

结果安全扫描发现,攻击者可以利用这个漏洞逃逸到宿主机...

解决方案

apiVersion: v1
kind: Pod
metadata:
  name: secure-pod
spec:
  securityContext:
    runAsNonRoot: true  # 强制非root运行
    runAsUser: 1000     # 指定用户ID
    fsGroup: 2000
  containers:
  - name: app
    image: your-app:latest
    securityContext:
      allowPrivilegeEscalation: false  # 禁止提权
      readOnlyRootFilesystem: true     # 只读文件系统
      capabilities:
        drop:
          - ALL  # 去掉所有权限
        add:
          - NET_BIND_SERVICE  # 只保留绑定端口的权限

踩坑经验

一开始我们设置了readOnlyRootFilesystem: true,结果应用启动失败,因为它需要写日志到本地目录。

怎么解决的?用emptyDir挂载一个临时目录:

volumes:
- name: tmp-dir
  emptyDir: {}
containers:
- name: app
  volumeMounts:
  - name: tmp-dir
    mountPath: /tmp

我的思考

容器安全不是可选项,而是必须项。虽然配置起来有点麻烦,但能避免很多潜在的风险。

坑3:Pod之间随便通信,一个被攻全军覆没

问题描述

我们的微服务架构里有十几个服务,默认情况下它们可以互相访问。

有一次,一个测试环境的服务被攻破,攻击者横向移动,直接打到了生产数据库...

解决方案:用NetworkPolicy限制Pod通信

# 先禁止所有通信
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
  namespace: production
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

---
# 再按需开放
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-web-to-api
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: api
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: web  # 只允许web访问api
    ports:
    - protocol: TCP
      port: 8080

效果:配置完后,只有web可以访问API,其他服务都被隔离了。虽然配置过程有点麻烦,但安全感直接拉满。

我的思考

最小权限原则在K8s中特别重要。不要觉得"都是自己人"就放松警惕,攻击者可能就在你身边。

坑4:Secret直接写在配置文件里,差点被Git记录

问题描述

当时为了赶进度,直接把数据库密码写在了deployment.yaml里,然后提交到了Git仓库。

后来被安全扫描发现了,幸好还没上线...

解决方案:用Sealed Secrets加密存储

# 安装Sealed Secrets
kubectl apply -f https://github.com/bitnami-labs/sealed-secrets/releases/download/v0.24.0/controller.yaml

# 加密Secret
echo -n 'my-database-password' | kubectl create secret generic db-password \
  --from-file=password=/dev/stdin \
  --dry-run=client -o yaml | kubeseal -o yaml > sealed-secret.yaml

# 使用时会自动解密

血泪教训

  1. 永远不要把Secret提交到Git
  2. 用加密存储方案
  3. 定期轮换密钥

我的思考

Secret管理是K8s安全中最容易被忽视的一环。很多团队为了方便,直接把密码写在配置文件里,这是非常危险的行为。

坑5:镜像有漏洞都不知道,出了事才后悔

问题描述

我们有个老项目,用的是两年前的nginx镜像。当时觉得能跑就行,没去管它。

结果安全扫描发现这个镜像有十几个高危漏洞...

解决方案:在CI/CD里集成镜像扫描

# GitHub Actions示例
- name: 扫描镜像漏洞
  uses: aquasecurity/trivy-action@master
  with:
    image-ref: 'myapp:${{ github.sha }}'
    format: 'table'
    exit-code: '1'  # 发现高危漏洞就失败
    severity: 'CRITICAL,HIGH'

建议

  1. 定期扫描所有在用镜像
  2. 发现漏洞及时更新
  3. 建立镜像更新机制

我的思考

镜像安全是K8s安全的基础。如果基础镜像有漏洞,上面跑的所有服务都是不安全的。

坑6:没有审计日志,出事了查不到

问题描述

有一次线上出了问题,我们怀疑是人为操作导致的,但查了半天日志,什么都没查到。

后来才知道,K8s默认没开审计日志...

解决方案:启用审计日志

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# 记录所有对Pod的操作
- level: Metadata
  resources:
  - group: ""
    resources: ["pods", "services"]

# 重点记录Secret的操作
- level: RequestResponse
  resources:
  - group: ""
    resources: ["secrets", "configmaps"]
  verbs: ["create", "update", "delete"]

然后用ELK收集分析:

# 安装Filebeat收集日志
helm install filebeat elastic/filebeat

# 用Kibana查看
# 访问 http://localhost:5601

我的思考

审计日志是事后追溯的关键。虽然配置起来有点麻烦,但出事时能帮你快速定位问题。

我的安全检查清单

每次部署前,我都会过一遍这个清单:

部署前检查

  • 镜像扫描过了吗?
  • Secret加密存储了吗?
  • RBAC配好了吗?
  • NetworkPolicy启用了吗?
  • 资源限制设了吗?
  • 审计日志开了吗?

运行时检查

  • 监控告警配了吗?
  • 日志收集了吗?
  • 定期审计做了吗?

每月必做

  • 检查镜像漏洞
  • 更新依赖版本
  • 审查RBAC权限
  • 检查安全配置

写在最后

Kubernetes安全是个持续的过程,不是配一次就完事了。

我建议:

  1. 从简单的开始 - 先把RBAC和NetworkPolicy配好
  2. 逐步完善 - 每次迭代加一点安全措施
  3. 持续监控 - 建立告警,及时发现问题
  4. 定期审计 - 每月检查一次安全配置

安全确实麻烦,但比起出事后的损失,这点麻烦算什么呢?


你遇到过哪些K8s安全问题?欢迎在评论区分享你的经验!