平台基础设施安全:容器运行时安全、Kubernetes集群安全加固、节点与主机安全基线

好,咱们进入第二章。平台基础设施安全,说白了就是给PaaS平台打好地基。我见过太多团队,一上来就搞微服务、搞编排,结果底层容器和主机全是漏洞,跑起来心惊胆战。今天咱们就聊聊这三块硬骨头:容器运行时、K8s集群、还有节点主机。

容器运行时安全

容器不是轻量级虚拟机。这个观念我反复跟团队强调。你想想看,容器共享宿主机内核,一旦内核被突破,整个宿主机就沦陷了。所以运行时安全,核心就两件事:限制容器能做什么,以及监控它在做什么。

1. 使用非root用户运行容器

默认情况下,容器里的进程是root。但容器里的root,其实就是宿主机上的root。嗯,这里要注意。我建议在Dockerfile里显式指定用户:

FROM alpine:3.18
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
COPY --chown=appuser:appgroup ./app /app
CMD ["/app/entrypoint.sh"]

我在项目中遇到过,有团队直接把生产镜像里的root用户保留着,结果被攻破后攻击者直接拿到了宿主机root权限。后来我们强制要求所有基础镜像必须包含非root用户配置。

2. 只读根文件系统

容器运行时,根文件系统应该是只读的。临时数据挂载到tmpfs或emptyDir。这样就算容器被写入了恶意文件,重启后就没了。

核心原则:容器应该是不可变的。任何需要持久化的数据,都通过卷挂载进来。

securityContext:
  readOnlyRootFilesystem: true
  runAsNonRoot: true
  capabilities:
    drop: ["ALL"]

3. 限制Linux内核能力

容器不需要那么多capabilities。我习惯的做法是:先全部drop,再按需添加。比如一个Web服务,可能只需要NET_BIND_SERVICE就够了。

避坑指南:我曾经遇到过,开发说容器需要SYS_PTRACE来调试,结果上线后忘了去掉。攻击者利用这个能力绕过了AppArmor。所以,生产环境一定要最小化capabilities。

4. 使用Seccomp和AppArmor

Seccomp限制系统调用,AppArmor限制文件访问和网络。这两个配合使用,效果很好。K8s从1.19开始默认启用Seccomp,但很多团队不知道。

securityContext:
  seccompProfile:
    type: RuntimeDefault
  appArmorProfile:
    type: RuntimeDefault

Kubernetes集群安全加固

K8s集群安全,我把它分成三个层面:控制面安全、工作负载安全、网络策略。咱们一个一个说。

1. 控制面安全:API Server是第一道门

API Server是集群的大脑。谁控制了API Server,谁就控制了整个集群。我建议做以下几件事:

  • 启用RBAC:别用ABAC,那玩意维护起来太痛苦。RBAC清晰明了。
  • 禁用匿名访问--anonymous-auth=false,这个必须配。
  • 使用ServiceAccount:每个应用用独立的ServiceAccount,别用default。
  • 审计日志:开启审计日志,记录谁在什么时候做了什么。

注意:审计日志会占用大量磁盘空间。我建议只记录Metadata级别,除非你怀疑有攻击行为才提升到RequestResponse级别。

2. 工作负载安全:Pod安全标准

K8s从1.23开始引入了Pod Security Standards(PSS)。分三个级别:Privileged、Baseline、Restricted。我建议生产环境至少用Baseline,敏感业务用Restricted。

级别 说明 适用场景
Privileged 无限制,基本等于裸奔 系统组件、监控Agent
Baseline 限制已知的提权路径 大多数业务应用
Restricted 最严格,强制非root、只读根文件系统等 金融、支付等敏感业务

你可以用Pod Security Admission来强制实施:

apiVersion: v1
kind: Namespace
metadata:
  name: production
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/audit: restricted

3. 网络策略:默认拒绝一切

K8s默认网络是扁平的,所有Pod都能互相通信。这太危险了。我建议一开始就部署网络策略,默认拒绝所有入站和出站流量,然后按需开放。

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: default-deny-all
spec:
  podSelector: {}
  policyTypes:
  - Ingress
  - Egress

然后针对具体服务开放:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: allow-frontend-to-backend
spec:
  podSelector:
    matchLabels:
      app: backend
  ingress:
  - from:
    - podSelector:
        matchLabels:
          app: frontend
    ports:
    - port: 8080

节点与主机安全基线

节点是容器的家。家不安全,容器再安全也没用。我总结了一套基线,大家可以参考。

1. 操作系统加固

  • 最小化安装:只装必要的包。别装编译器、调试工具。
  • 禁用SSH密码登录:只用密钥,而且密钥要定期轮换。
  • 内核参数调优:比如net.ipv4.ip_forward=0,除非你用了网络插件。
  • 启用SELinux或AppArmor:别关掉它们。很多人嫌麻烦直接关了,这是大忌。

个人经验:我习惯用CIS Benchmark来检查节点安全。跑一遍kube-bench,看看哪些项没通过。刚开始可能一堆红色,但别慌,一条条改就行。

2. 容器运行时守护进程安全

Docker或containerd的守护进程,默认监听在Unix socket上。别把它暴露到网络上。我见过有人把Docker socket挂载到容器里,结果容器里的进程直接控制了宿主机。

# 不要这样做!
volumes:
- name: dockersocket
  hostPath:
    path: /var/run/docker.sock

如果你确实需要管理容器,用K8s的API,别直接操作Docker。

3. 定期扫描与更新

节点上的内核和系统包,必须定期更新。我建议用自动化工具,比如Ansible或Terraform,来管理节点镜像。每次更新后,重新创建节点,而不是原地升级。

核心原则:节点应该是不可变的。一旦部署,就不应该手动登录上去改东西。所有变更都通过基础设施即代码来管理。

4. 监控与告警

节点安全不是配完就完了。你得持续监控。我建议关注这几个指标:

  • Falco告警:检测异常系统调用,比如容器里执行了chmod /etc/shadow
  • 节点资源异常:CPU或内存突然飙升,可能是挖矿程序在跑。
  • 网络连接异常:容器突然连接了未知IP,可能是C2通信。

说白了,安全是个持续的过程。你不可能配一次就高枕无忧。我每次上线新业务,都会重新审视一遍这些基线。嗯,今天就聊到这儿。下一章咱们聊聊数据安全,那可是更刺激的话题。