容器技术和编排管理是云原生生态的两大核心部分——前者负责执行,后者负责控制和管理,共同构成云原生技术有机体,我们以 Kubernetes 为例,对容器编排平台可能面临的风险进行分析
作为最为流行的云原生管理与编排系统,Kubernetes具有强大的功能,但同时也具有较高的程序复杂性。我们知道,风险和程序复杂性之间具有一定程度的关系,不过要分析一个复杂系统的风险并不容易
以下是Kubernetes的架构图:
一个常见的Kubernetes集群,由一个Master节点和三个 Worker 节点组成,Pod 之间借助CNI插件Flannel 实现通信。 Kubernetes 自身的系统Pod(kube-system命名空间内的Pod)主要运行在Master 节点上,除此之外,每个 Worker 节点上也分别有一个 Flannel Pod 和 kube-proxy Pod,所有业务 Pod 分布在三个 Worker 节点上。另外,每个节点上还有一个 Kubelet 服务,负责管理容器
事实上,编排系统和容器之间并非完全独立,列如,我们在Kubernetes集群中需要以 YAML 声明式文件的形式来创建 Pod,而 Pod 只是 一个在逻辑上的概念,实际由一个或者多个容器组成,对容器的配置须以 Pod 的配置方式下发
我们主要从 Kubernetes的接口、网络、访问控制机制和软件漏洞四个方面来讨论容器编排系统所面临的风险
在 Kubernetes 的环境中,容器基础设施面临的风险主要有以下几点:
Kubernetes 中组件漏洞众多,绝大多数组件以基于 HTTP 或 HTTPS 的 API 形式提供服务,其中,我们日常接触比较多的服务及其端口如下表所示:
组件 | 默认端口 | 说明 |
---|---|---|
API Server | 6443 | 基于HTTPS的安全端口 |
API Server | 8080 | 不安全的HTTP端口,不建议启用 |
Kubelet | 10248 | 用于检查 Kubelet 健康状态的 HTTP 端口 |
Kubelet | 10250 | 面向 API Server 提供服务的 HTTPS 端口 |
Dashboard | 8001 | 提供 HTTP服务的端口 |
etcd | 2379 | 客户端与服务端之间通信的端口 |
etcd | 2380 | 不同服务端实例之间通信的端口 |
接下来,我们对这些服务进行风险分析:
默认情况下,API Server 在 8080 和 6443 两个端口提供服务,其中 8080端口提供的是没有 TLS 加密的 HTTP 服务,且所有达到该端口的请求将绕过所有认证和授权模块(但是仍然会被准入控制模块所处理)。保留该端口主要是为了方便测试及集群初启动
然而生产环境开放 8080 端口,即使绑定本地回环地址(localhost)也是很危险的。如果将该端口暴露在互联网上,那么任何网络可达的攻击者都能通过该端口直接与 API Server 交互,继而控制整个集群
相比之下,6443端口提供的是使用 TLS 加密的 HTTPS 服务,到达的请求必须通过认证和授权机制才能被成功处理。在认证和授权机制配置正确的情况下,6443 端口提供的服务和安全性会更高
默认情况下,我们需要先执行 Kubectl proxy,然后才能通过本地8001端口访问 Dashboard 。但是,如果直接将Dashboard端口映射在宿主机的节点,或者在执行 Kubectl proxy时指定了额外地址参数,那么所有能够访问到宿主机的用户,包括攻击者,都将能够直接访问 Dashboard
kubetcl proxy --address 0.0.0.0 --accept-hosts='^*$'
另外,默认情况下Dashboard 需要登陆认证,但是,如果用户在 Dashboard 的启动参数添加了 --enable-skip-login 选项,那么攻击者能够直接点击 Dashboard 界面 ”跳过“ 按钮,无需登录便可直接进入Dashboard
我们知道,API Server 是整个Kubernetes的神经中枢,以 RESTful API的形式对外提供了大量的应用接口。事实上,Kubelet 也提供了 RESTful API 服务,供 API Server 调用以获取或改变某个Kubernetes 节点上的资源状态
默认配置下,Kubelet 在 10250 端口开放 API服务,另外还监听 10248端口,以供其他组件检查 Kubelet 的运行状态:
curl http://IP:10248/healthz
10248 端口服务相对简单,不存在特别的风险,但10250端口却未必。默认情况下,API Server 在访问 Kubelet 的 API 时需要使用客户端证书,相对来说比较安全,但是还是有列外的情况:
1)攻击者通过某种方式窃取了 API Server 访问 Kubelet 的客户端证书
2)将Kubelet的 --anonymous-auth 参数设置为 true ,且 authorization mode 设置为 AlwaysAllow
如果出现了上述的情况,则网络攻击者都能够直接将 Kubelet 进行交互,从而实现对其所在节点的控制
Kubernetes集群内的各种资源及其状态均存储在etcd中,如果有办法读取etcd中的数据,就可能获取高权限,从而控制集群。目前,etcd 启动后监听 2379 和 2380 两个端口,前者用于客户端连接,后者用于多个etcd 实例之间的对端通信。再多节点的集群中,为了实现高可用etcd往往在节点IP上(非本地IP)监听,以实现多节点之间的互通、这可能允许外部攻击者访问etcd
默认情况下,两个端口提供的服务都需要相应证书才能访问(禁止匿名访问),这为etcd 的安全性提供了保障。如果攻击者窃取了证书、或者用户将etcd 设置为 允许匿名访问,那么攻击者就可能直接访问 etcd 并窃取数据
为了实现集群 Pod 间相互通信,在安装部署 Kubernetes 后,我们往往还要额外安装一个网络插件,常见的网络插件有 Flannel、Calico 和 Cilium 等
在没有其他网络隔离策略和 Pod 安全策略的默认情况下,由于 Pod 与 Pod 之间彼此可连通,且 Pod 内的root用户具有 CAP_NET_RAW权限,集群内部可能发生网络探测、嗅探、拒绝服务和中间人攻击等网络攻击
Kubernetes 中的访问控制机制主要由认证机制、授权机制和准入机制三个部分组成,每一个部分通常会有一种或多种具体实现的机制可供选择。如果访问控制过于宽松,高权限账户可能会滥用,从而对Kubernetes 自身及正在运行的容器产生威胁,除此之外,如果允许针对Kubernetes 的未授权访问,攻击者可能借此直接获得集群管理员的权限
作为一个复杂系统,Kubernetes自然被曝出许多安全漏洞,这类自然也属于 Kubernetes 所面临的的风险
参考资料:《云原生安全-攻防实践与体系构建》