Etcd简介

Etcd是CoreOS团队于2013年6月发起的开源项目,它的目标是构建一个高可用的分布式键值(key-value)数据库, 用于服务发现、共享配置以及一致性保障等。目前已广泛应用在kubernetes、ROOK、CoreDNS、M3以及openstack等领域。

Etcd内部采用raft协议作为一致性算法,基于Go语言实现。从组成上来看,Etcd主要由四个部分组成:HTTP Server、Store、Raft以及WAL。我们可以通过Etcd架构图来更好的了解Etcd,Etcd架构图可见下图所示:

图-1  Etcd架构图

Etcd比较常见的版本有v2版本和v3版本,v2、v3版本的共同点是共享同一套raft协议代码,不同点是二者为两个独立的应用,互不兼容,其接口、存储都是不相同的。

值得注意的是,Kubernetes集群已经在Kubernetes v1.11中弃用Etcdv2 版本,在新版本的Kubernetes中,Kubernetes采用 Etcd v3存储数据。

Etcd与Kubernetes

在对Etcd有了初步了解之后,我们来看一下Kubernetes中Etcd的应用。

在Kubernetes集群中,存在有控制平面组件以及Node组件两大类组件,在这两类组件中包含了多种不同功能的组件,这些组件共同保证了Kubernetes集群的正常运行。Kubernetes集群组件结构可参照下图:

图- 2  Kubernetes集群组件

Etcd在Kubernetes中扮演着控制平面组件的角色,是兼具一致性和高可用性的键值数据库,在Kubernetes集群中扮演着保存 Kubernetes 所有集群数据的后台数据库的角色。

Kubernetes系统中一共有两个服务需要用到Etcd进行协同和与存储,分别是Kubernetes自身与网络插件 flannel。

在Kubernetes 集群的配置过程中,需要安装Etcd组件,Etcd的yaml文件可见下图:

图- 3  Etcd组件配置文件

从上文配置文件可见,Etcd在配置过程中需要配置两个url地址:listen-client-urls以及 listen-peer-urls,分别监听在2379端口以及2380端口。其中listen-peer-urls用于 etcd 集群同步信息并保持连接,而listen-client-urls则用于接收用户端发来的 HTTP请求。

Ectd常见风险

Etcd常见风险包括:

  1. 启动etcd时,未使用client-cert-auth参数打开证书校验;

  2. Etcd 2379端口公网暴露;

  3. 由于SSRF漏洞导致Etcd 127.0.0.1:2379 可访问;

  4. Etcd cert泄露。

我们分别来看一下以上四个风险点分别是如何对Etcd造成威胁的。

首先来看一下未使用client-cert-auth参数打开证书校验带来的风险:

在启动etcd时,正确的做法是使用client-cert-auth参数打开证书校验,见下图配置文件红框处:

图- 4  开启证书校验

在打开证书校验选项后,通过本地127.0.0.1:2379地址可以免认证访问Etcd服务,但通过其他地址访问要携带cert进行认证访问

在未使用client-cert-auth参数打开证书校验时,任意地址访问Etcd服务都不需要进行证书校验,此时Etcd服务存在未授权访问风险。

接下来,我们分析一下Etcd 2379端口公网暴露所带来的风险

在配置Etcd时,正确的做法是为listen-client-urls参数配置一个合理的IP地址,Etcd将监听在给定端口和接口上,如下图红框处:

图- 5  配置listen-client-urls

由于错误的配置,将listen-client-urls IP配置为0.0.0.0,那么Etcd 将会在所有接口上监听给定端口,这将导致Etcd 2379端口在公网暴露。

接下来,我们分析一下由于SSRF漏洞导致Etcd 127.0.0.1:2379 可访问风险:

即使Etcd进行了正确的配置,由于服务器上应用程序的SSRF漏洞,导致Etcd 127.0.0.1:2379 可访,此接口默认不需要证书校验,因此攻击者可以通过SSRF漏洞访问此接口并读取Etcd中的敏感数据。

最后,我们来看一下Etcd cert泄露所带来的风险

在配置安全通信后, 需要使用TLS 身份验证来完成Etcd服务的访问,通常使用如下的方式有效证书证书进行访问:

    ETCDCTL_API=3 etcdctl --endpointsetcd_ip:2379 \ --cert=/etc/kubernetes/pki/etcd/client.crt \ --key=/etc/kubernetes/pki/etcd/client.key \  --cacert=/etc/kubernetes/pki/etcd/ca.crt \

    如果证书被窃取,攻击者可以使用获取到的证书访问Etcd服务。

    Ectd攻击场景

    在搭建Kubernetes并配置Etcd服务时,如果出现了上一章节中提到的错误配置或漏洞风险点,攻击者可以利用Etcd的风险点发起攻击。

    我们在这里列举集中常见的攻击者攻击方式,通过以攻促防的方式,带领读者了解Etcd服务所面临的风险以及威胁。

    在开始介绍攻击常见前,我们先来了解一款常见的etcd命令行工具——etcdctl。

    etcdctl是一款命令行客户端,提供一些简洁的命令,用户无需使用HTTP API,可以直接使用etcdctl提供的指令与etcd服务进行交互。

    可以通过如下地址进行下载:

    https://github.com/coreos/etcd/releases

    接下来我们对几种攻击场景逐一进行分析。

    Etcd初始访问

    Etcd 2379端口公网暴露

    在这个场景中,攻击者可以利用暴露在公网上的2379端口访问Etcd服务。但在这个场景中,攻击者依然面临着两个不同的情况,即当前Etcd服务在启动时是否使用client-cert-auth参数开启证书校验。

    如果当前Etcd服务未进行证书校验,则存在未授权访问漏洞,可以通过如下指令获取top-levelkeys数据

    /etcdctl--endpoints=https://etcd_ip:2379/ get / --prefix --keys-only

    具体操作可见下图:

    图- 6  获取top-level keys数据

    如果当前Etcd服务使用证书进行校验,则需要使用获取到的证书进行配置并访问

    在使用etcdctl工具之前,需要配置如下三个环境变量:

    • ETCDCTL_CERT

    • ETCDCTL_CACERT

    • ETCDCTL_KEY

    在配置了正确的证书后,即可通过etcdctl工具对Etcd服务进行访问。

    由于SSRF漏洞导致Etcd localhost端口访问

    在这个场景中,由于SSRF漏洞导致Etcd 127.0.0.1:2379可访问,而且Etcd 127.0.0.1:2379地址默认不需要进行证书校验,即可以直接访问,因此当Etcd服务器上应用程序存在SSRF漏洞时,攻击者可以通过构造内外请求的方式,向Etcd服务API接口发送恶意指令。

    Etcd凭据窃取

    通过初始访问阶段,攻击者获取了Etcd服务的访问权限,并可以使用etcdctl工具读取Etcd中存储的数据,接下来介绍一下在此阶段中应用的技术。

    获取clusterrole key

    可以使用如下指令读取存储于Etcd中的与clusterrole有关的key

    etcdctl--endpoints=https://etcd_ip:2379/ get / --prefix --keys-only | grep/secrets/kube-system/clusterrole。

    图- 7  读取clusterrole有关的key

    获取token key值

    可以通过如下指令,通过上一步中获取到的key,读取其中的值:

    etcdctl--endpoints=https://etcd_ip:2379/ get / /xxx/secrets/kube-system/clusterrole-xxx

    从返回的数据中,挑选出一个具有高权限的role并读取其token。toke数据通常以字符串”ey”开头,并截取到字符串

    “#kubernetes.io/service-account-token”之前部分,见下图选中部分:

    图表- 8  截取token数据

    至此,我们已经获取了有效的Kube Apiserver 访问token。

    Kube Apiserver命令执行

    通过上一阶段窃取到的token认证访问Kube Apiserver,使用kubectl接管集群。具体操作如下:

    kubectl--insecure-skip-tls-verify -s https://kube_apiserver:6443/--token="[ey...]" -n kube-system get nodes

    图表- 9  使用kubectl接管集群

    使用上下文简化kubectl操作

    生成context

    可以使用如下命令生成context:

    图表- 10  生成context

    配置context简化kubectl操作

    Kubernetes通过上下文(context),使用简便的名称来对访问参数进行分组。每个上下文都有三个参数:cluster、namespace 和user。kubectl工具可以通过kubeconfig参数指定我们生成的上下文 context_config:

    图表- 11  配置context

    通过这个方式,即可简化kubectl操作,无需每次执行kubectl命令时填写TOKEN。

    Etcd防御与加固

    通过上文攻击场景介绍,我们提出如下的防护建议用以加固Etcd服务:

    1. 在启动Etcd时,使用client-cert-auth参数打开证书校验;

    2. Etcd数据加密存储,确保Etcd数据泄露后无法利用;

    3. 正确的配置listen-client-urls参数,防止外网暴露;

    4. 尽量避免在Etcd所在的节点上部署Web应用程序,以防通过Web应用漏洞攻击Etcd localhost地址。

    写在最后

    Etcd组件在Kubernetes中充当着保存集群数据的后台数据库这一重要角色,因此Etcd组件安全对集群来说也是尤为重要。通过上文分析可见,虽然Etcd组件提供了较为安全的鉴权功能,以保证数据的安全性,但是由于用户在配置使用Etcd组件时安全意识不足或配置错误,将会导致集群数据被非法访问或篡改。Ectd数据泄露,将会为集群带来严重的安全问题。未来我们将持续关注Etcd组件安全问题。

    参考链接

    https://yeasy.gitbook.io/docker_practice/etcd/etcdctl

    https://kubernetes.io/zh/docs/concepts/overview/components/

    https://www.huweihuang.com/kubernetes-notes/etcd/etcdctl-v3.html

    https://www.cdxy.me/?p=827

    https://tttang.com/archive/1465/

    声明:本文来自安全内参,版权归作者所有。文章内容仅代表作者独立观点,不代表安全内参立场,转载目的在于传递更多信息。如有侵权,请联系 anquanneican@163.com。