2. 云原生基础概念回顾:容器、编排、微服务、CI/CD与不可变基础设施

各位同学,在深入5G核心网的攻击面之前,我们得先把地基打牢。云原生这玩意儿,说白了就是一套让应用跑得更快、更稳、更弹性的方法论。我见过不少安全同行,一上来就盯着K8s的漏洞猛挖,结果连Pod和容器的边界都没搞清楚——这不行。今天我们就花点时间,把几个核心概念过一遍。

我个人习惯,讲技术之前先画个图。下面这张图,就是云原生世界的骨架。

云原生技术栈核心逻辑 容器 (Docker) —— 应用的打包与隔离 容器编排 (Kubernetes) —— 集群的调度与管理 微服务 —— 应用的解构与通信 CI/CD —— 自动化交付流水线 不可变基础设施 —— 不可修改的运行时

2.1 容器(Docker)—— 应用的打包与隔离

容器是什么?我经常跟团队里的小朋友说,你就把它当成一个轻量级的虚拟机。但它跟虚拟机最大的区别在于——它共享宿主机内核。这意味着什么?意味着启动快、资源占用少,但也意味着隔离性没那么强。

我在项目中遇到过好几次,有人把容器当虚拟机用,在里面跑sshd、装systemd,搞得跟个小操作系统似的。嗯,这其实是个坏习惯。容器的哲学是「一个进程一个容器」,你想想看,如果每个容器里都跑一堆乱七八糟的服务,那攻击面得有多大?

来看一个典型的Dockerfile:

FROM alpine:3.18
RUN apk add --no-cache python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]

这里要注意几个安全点:

  • 基础镜像:别用latest,指定具体版本。我曾经见过有人用了一个过时的镜像,里面带着CVE-2023-xxxx,结果被攻破了还不知道怎么回事。
  • 最小化原则:alpine只有5MB,比ubuntu小多了。攻击面自然也就小了。
  • 不要以root运行:Docker默认是root,但你可以用USER指令切到普通用户。
⚠️ 避坑指南:我曾经在客户现场发现,他们的容器里居然有curl、wget、bash这些调试工具。这些工具对攻击者来说就是「武器库」。记住:生产环境的容器,能删的都删掉。

2.2 容器编排(Kubernetes)—— 集群的调度与管理

单个容器好管,但当你有了几百个容器,怎么办?这就是Kubernetes出场的时候了。说白了,K8s就是一个容器的大脑,它决定你的容器跑在哪台机器上、怎么互相通信、挂了怎么重启。

我个人习惯,把K8s的核心组件分成两拨:

控制平面组件 工作节点组件
kube-apiserver(所有操作的入口) kubelet(跟容器运行时打交道)
etcd(集群状态存储) kube-proxy(网络代理)
kube-scheduler(调度决策) 容器运行时(如containerd)
kube-controller-manager(控制器)

你想想看,攻击者最想打哪个?当然是etcd。为什么?因为etcd里存着整个集群的配置、密钥、证书。我见过一个案例,攻击者通过一个未授权的API端口,直接dump了etcd,整个集群就沦陷了。

🔑 关键安全点:K8s的RBAC一定要配好。默认的ServiceAccount权限太大,很多人图省事直接给了cluster-admin。我曾经在渗透测试中,就是通过一个被攻破的Pod,利用它的ServiceAccount token,拿到了整个集群的控制权。

2.3 微服务—— 应用的解构与通信

微服务,就是把一个大单体应用拆成一堆小服务。每个服务独立部署、独立扩展、独立运维。听起来很美,对吧?但代价是什么?是网络通信的复杂性。

在5G核心网里,AMF、SMF、UPF这些网元,现在都变成了微服务。它们之间怎么通信?通常有两种方式:

  • 同步通信:HTTP/REST、gRPC。简单直接,但容易产生级联故障。
  • 异步通信:消息队列(Kafka、NATS)。解耦性好,但引入了消息中间件这个新的攻击面。

我记得有一次,一个团队把所有的微服务都暴露在同一个K8s Namespace里,服务之间没有任何网络策略。结果一个边缘服务被攻破后,攻击者直接横向移动到了核心数据库。这就是典型的「微服务架构,单体安全」——架构拆了,安全没拆。

💡 我的建议:每个微服务都应该有自己的ServiceAccount,并且用NetworkPolicy限制它只能访问必要的服务。别嫌麻烦,这是基本功。

2.4 CI/CD—— 自动化交付流水线

CI/CD,持续集成和持续交付。说白了,就是让代码从开发到上线,全自动跑一遍。Git push之后,自动编译、自动测试、自动打包、自动部署。

但这里有个大坑——CI/CD流水线本身就是一个巨大的攻击面。你想想看,如果攻击者能控制你的CI/CD系统,他就能往你的镜像里植入后门,然后这个后门会被自动部署到生产环境。

我曾经在审计一个客户的Jenkins时发现,他们的Pipeline里直接硬编码了Docker Hub的密码。嗯,这等于把家门钥匙放在了门口的地毯下面。

# 错误示范:硬编码凭证
docker login -u admin -p 'P@ssw0rd!'

# 正确做法:使用密钥管理
docker login -u $DOCKER_USER -p $DOCKER_PASS

这里要注意几个安全实践:

  • 凭证管理:用Vault、K8s Secrets或CI/CD平台自带的凭证管理功能。
  • 镜像签名:用Notary或Cosign给镜像签名,确保部署的镜像是你构建的那个。
  • 流水线隔离:不同的分支用不同的流水线,别让feature分支能直接部署到生产。

2.5 不可变基础设施—— 不可修改的运行时

这个概念,我特别喜欢。什么叫不可变基础设施?就是一旦部署了,就不允许修改。如果出了问题,不是上去修,而是直接销毁重建。

你想想看,传统的服务器运维是什么样?SSH上去,改配置文件,重启服务。时间长了,每台机器都变得独一无二,谁也说不清上面跑了什么。这就是「配置漂移」——安全的大敌。

在云原生世界里,我们怎么做?

  • 镜像一旦构建,就不修改。要更新?重新构建一个新版本。
  • 容器一旦运行,就不进去改东西。要改配置?更新ConfigMap,然后滚动重启。
  • Pod一旦出问题,直接杀掉重建,而不是进去调试。
🔒 安全收益:不可变基础设施天然防御了「持久化后门」。攻击者即使攻入了容器,也无法持久化——因为容器一重启,所有修改都消失了。当然,前提是你没有挂载持久化卷。

嗯,说到这里,我想起一个真实的案例。有一次,一个团队发现他们的容器里被人植入了挖矿程序。他们第一反应是SSH进去杀掉进程。但第二天,挖矿程序又出现了。为什么?因为攻击者修改了镜像,而他们用的是latest标签,每次重启都拉到了被篡改的镜像。这就是典型的「可变基础设施」的教训。

好了,以上就是云原生基础概念的回顾。这些概念看似简单,但每一个都跟安全息息相关。后面的章节,我们会基于这些基础,深入分析5G核心网在云原生环境下的具体攻击面。


专注资料整理