“A9 Team 甲方攻防团队,成员来自某证券、微步、青藤、长亭、安全狗等公司。成员能力涉及安全运营、威胁情报、攻防对抗、渗透测试、数据安全、安全产品开发等领域,持续分享安全运营和攻防的思考和实践。”
01
—
K8S集群组件
表1- K8S 各组件默认端口上述端口表格中:kube-proxy \ dashboard 端口没有特定指定
kube-apiserver
API 服务器是 Kubernetes 控制平面的组件, 该组件负责公开了 Kubernetes API,负责处理接受请求的工作。 API 服务器是 Kubernetes 控制平面的前端。
Kubernetes API 服务器的主要实现是 kube-apiserver。 kube-apiserver 设计上考虑了水平扩缩,也就是说,它可通过部署多个实例来进行扩缩。 你可以运行 kube-apiserver 的多个实例,并在这些实例之间平衡流量。
etcd
一致且高可用的键值存储,用作 Kubernetes 所有集群数据的后台数据库。
Docker remote api
Swarm项目是Docker公司发布三剑客(Swarm,Compose,Machine)中的一员,用来提供容器集群服务,目的是更好的帮助用户管理多个Docker Engine,方便用户使用,像使用Docker Engine一样使用容器集群服务。
而上述的工具会需要docker宿主机开启remote api 故会开启2375这个端口,当然可能也有其他的需求需要开启远程访问控制,也有办法单独的主动开启,具体开启方法可自行百度。
kube-scheduler
kube-scheduler 是控制平面的组件, 负责监视新创建的、未指定运行节点(node)的 Pods, 并选择节点来让 Pod 在上面运行。
调度决策考虑的因素包括单个 Pod 及 Pods 集合的资源需求、软硬件及策略约束、 亲和性及反亲和性规范、数据位置、工作负载间的干扰及最后时限。
kube-controller-manager
kube-controller-manager 是控制平面的组件, 负责运行控制器进程。
从逻辑上讲, 每个控制器都是一个单独的进程, 但是为了降低复杂性,它们都被编译到同一个可执行文件,并在同一个进程中运行。
有许多不同类型的控制器。以下是一些例子:
节点控制器(Node Controller):负责在节点出现故障时进行通知和响应
任务控制器(Job Controller):监测代表一次性任务的 Job 对象,然后创建 Pods 来运行这些任务直至完成
端点分片控制器(EndpointSlice controller):填充端点分片(EndpointSlice)对象(以提供 Service 和 Pod 之间的链接)。
服务账号控制器(ServiceAccount controller):为新的命名空间创建默认的服务账号(ServiceAccount)。
以上并不是一个详尽的列表。
kubelet
kubelet 会在集群中每个节点(node)上运行。 它保证容器(containers)都运行在 Pod 中。
kubelet 接收一组通过各类机制提供给它的 PodSpecs, 确保这些 PodSpecs 中描述的容器处于运行状态且健康。 kubelet 不会管理不是由 Kubernetes 创建的容器。
kube-proxy
kube-proxy 是集群中每个节点(node)上所运行的网络代理, 实现 Kubernetes 服务(Service) 概念的一部分。
kube-proxy 维护节点上的一些网络规则, 这些网络规则会允许从集群内部或外部的网络会话与 Pod 进行网络通信。
如果操作系统提供了可用的数据包过滤层,则 kube-proxy 会通过它来实现网络规则。 否则,kube-proxy 仅做流量转发。
Web 界面(仪表盘)
Dashboard 是 Kubernetes 集群的通用的、基于 Web 的用户界面。 它使用户可以管理集群中运行的应用程序以及集群本身, 并进行故障排除。
K8s configfile泄露
K8s configfile作为k8s集群的管理凭证,其中包含有关K8s集群的详细信息,包括它们API Server的地址和登录凭证。在购买托管容器服务时,云厂商会向用户提供该文件以便于用户可以通过kubectl对集群进行管理。如果攻击者能够访问到此文件(如办公网员工机器入侵、泄露到Github的代码等),就可以直接通过API Server接管K8s集群,带来风险隐患。
docker remote api 未授权:
该未授权访问漏洞是因为docker remote api可以执行docker命令,从官方文档可以看出,该接口是目的是取代docker 命令界面,通过url操作docker。
Docker remote Api未授权访问的攻击原理与之前的Redis未授权访问漏洞大同小异,都是通过向运行该应用的服务器写文件,从而拿到服务器的权限。
参考链接:https://github.com/Threekiii/Vulhub-Reproduce/blob/master/Docker%20daemon%20api%20%E6%9C%AA%E6%8E%88%E6%9D%83%E8%AE%BF%E9%97%AE%E6%BC%8F%E6%B4%9E%20RCE.md
修复建议
1、简单粗暴的方法,对2375端口做网络访问控制,如ACL控制,或者访问规则;
2、修改docker swarm的认证方式,使用TLS认证:Overview Swarm with TLS 和 Configure Docker Swarm for TLS这两篇文档,说的是配置好TLS后,Docker CLI 在发送命令到docker daemon之前,会首先发送它的证书,如果证书是由daemon信任的CA所签名的,才可以继续执行。
API Server 未授权访问:
部署在Master上暴露Kubernetes API,是Kubernetes的控制面。Kubernetes API服务器为API对象验证和配置数据,这些对象包含Pod,Service,ReplicationController等等。API Server提供REST操作以及前端到集群的共享状态,所有其他组件可以通过这些共享状态交互。默认情况,Kubernetes API Server提供HTTP的两个端口:8080,6443。insecure-port: 默认端口8080,在HTTP中没有认证和授权检查。secure-port :默认端口6443, 认证方式,令牌文件或者客户端证书。
1、如果 8080 在外部环境中被暴露出来,攻击者便可以利用此端口进行对集群的攻击, 前提条件略显苛刻(配置失当 + 版本较低),首先 8080 端口服务是默认不启动的,但如果用户在 /etc/kubernets/manifests/kube-apiserver.yaml 中有 --insecure-port=8080 配置项,那就启动了非安全端口,有了安全风险。1.20版本后该选项已无效化。
2、若我们不带任何凭证的访问 API server 的 secure-port 端口,默认会被服务器标记为 system:anonymous 用户, 一般 system:anonymous 用户权限是很低的,但是如果运维人员管理失当,将 system:anonymous 用户绑定到了 cluster-admin 用户组,那么就意味着 secure-port 允许匿名用户以管理员权限向集群下达命令。
漏洞复现:
kubectl -s 127.0.0.1:8080 --namespace=default exec -it nginxfromuzju-59595f6ffc-p8xvk bash
修复建议:
1、升级版本到高版本无该配置
2、修改配置 /etc/kubernets/manifests/kube-apiserver.yaml 中有 --insecure-port=8080 配置项,改为0
Kubernetes Dashboard 未授权访问
漏洞描述Kubernetes Dashboard 是一个通用的,基于 Web 的 Kubernetes 集群用户界面。它允许用户管理集群中运行的应用程序,并对其进行故障排除,以及管理集群本身。在其早期版本中(v1.10.1 之前)存在未授权访问风险,用户在按照官方文档所给方式部署完成后,默认下,需要先执行 kubectl proxy,然后才能通过本地 8001 端口访问 Dashboard。但是,如果直接将 Dashboard 端口映射在宿主机节点上,或者在执行 kubectl proxy 时指定了额外地址参数,如:
kubectl proxy --address 0.0.0.0 --accept-hosts='^*$'
那么所有能够访问到宿主机的用户,包括攻击者,都将能够直接访问 Dashboard。默认情况下 Dashboard 需要登录认证,但是,如果用户在 Dashboard 的启动参数中添加了 --enable-skip-login 选项,那么攻击者就能够直接点击 Dashboard 界面的 “跳过” 按钮,无需登录便可直接进入 Dashboard。关于如何设置 --enable-skip-login ,在 v1.10.1 前,实则是无需配置的,通过在 Kubernetes Dashboard 的 Web 登录界面点击 “跳过” 按钮即可访问,也是因为这个原因,安全意识较为薄弱的用户直接将早期版本以默认的配置方式部署在互联网上使得攻击者无需花费丝毫力气就可以轻易浏览到 Kubernetes 集群的运行状态,因而在 v1.10.1 版本后,开发团队增加了显式配置的功能,需要用户在相应部署的 yaml 文件中指定 --enable-skip-login 参数配置才能开启未授权访问。
kubelet 未授权访问
漏洞描述
kubelet 是在 Node 上用于管理本机 Pod 的,kubectl 是用于管理集群的。kubectl 向集群下达指令,Node 上的 kubelet 收到指令后以此来管理本机 Pod。
Kubelet 服务启动后会监听多个端口,用于接收 Kubernetes API Server 组件发送的请求
10248 : Kubelet healthz 的服务端口,用于判断 Kubelet 组件的健康状态,已于 Kubernetes v1.16 版本后弃用,访问该端口默认需要认证授权
10250 : Kubelet 的 HTTPS 服务,读写端口,提供 Kubernetes 基本资源运行状态, 访问该端口默认需要认证授权
10255 : Kubelet 的 HTTP 服务,只读端口,提供只读形式的 Kubernetes 基本资源运行状态,该端口无需进行认证授权,默认为禁用
漏洞复现:
curl -XPOST -k "https://${IP_ADDRESS}:10250/run/<namespace>/<pod>/<container>" -d "cmd=<command-to-run>"
修复建议:
配置文件中 authentication 选项用于设置 kubelet api 能否被匿名访问,authorization 选项用于设置 kubelet api 访问是否需要经过 Api server 进行授权, 把 authentication-anonymous-enabled 改为 true。
etcd 未授权
在启动etcd时,如果没有指定 --client-cert-auth 参数打开证书校验,并且把listen-client-urls监听修改为0.0.0.0那么也就意味着这个端口被暴露在外,如果没有通过安全组防火墙的限制,就会造成危害
etcd默认端口2379
ps: 不过在安装k8s之后默认的配置2379都只会监听127.0.0.1,而不会监听0.0.0.0,那么也就意味着最多就是本地访问,不能公网访问
kubernetes的master会安装etcd v3用来存储数据,如果管理员进行了错误的配置,导致etcd未授权访问的情况,那么攻击者就可以从etcd中拿到kubernetes的认证鉴权token,从而接管集群。
在真实的场景中,还有一些应用使用etcd来存储各种服务的账号密码、公私钥等敏感数据。而很多etcd服务的使用者完全没有考虑过其安全风险,这种情况和redis的使用情况差不多,在企业内网比较普遍,甚至也有少部分人会将其开放到公网。
kube-proxy 漏洞
Kubernetes官方发布安全公告,其核心组件kube-proxy存在主机边界绕过漏洞(CVE-2020-8558)。利用漏洞攻击者可能通过同一局域网下的容器,或在集群节点上访问同一个二层域下的相邻节点上绑定监听了本地127.0.0.1端口的TCP/UDP服务,从而获取接口信息。如果绑定在端口上的服务没有设置身份验证,则会导致该服务容易受到攻击。例如,如果集群管理员运行监听了127.0.0.1:1234的TCP服务,由于这个bug,该服务将有可能被与该节点在同一局域网中的其他主机,或与该服务运行在同一节点上的容器所访问。如果端口1234上的服务不需要额外的认证(因为假设只有其他localhost进程可以),那么很容易受到利用此bug进行攻击。
Affected Versions
kubelet/kube-proxy v1.18.0-1.18.3
kubelet/kube-proxy v1.17.0-1.17.6
kubelet/kube-proxy <=1.16.10
推荐工具
Kube-Hunter扫描漏洞
kube-hunter是一款用于寻找Kubernetes集群中的安全漏洞扫描器
下载地址: https://github.com/aquasecurity/kube-hunter