摘要:当用户通过浏览器访问HTTPS网址时,浏览器首先会获取网站的数字证书(内含数字签名,该证书由CA认证机构签发),浏览器通过内置的CA根数字证书的公钥,来验证该网站数字证书中数字签名的合法性,验证通过后,才能使用该数字证书,进行后续的数据传输工作(传输过程如之前的RSA算法所述)。该证书不可与API Server的CA共用,根据官网关于 CA Reusage and Conflicts 的说明,问题主要出在Kubernetes的架构设计上:client在访问API Server时,需要参考以下顺序进行证书验证工作:。

【编者的话】笔者旨在通过自己的学习研究及实际工作实践,来揭开Kubernetes中证书体系的层层神秘面纱,希望能为正在学习和Kubernetes实践过程中有着同样困惑的朋友指点迷津。

序言

作为Kubernetes一个初学者,当你在初次搭建Kubernetes环境的过程中,相信一定注意到过,Control Plane(控制平面)各个核心组件的启动参数中,关联了相当多的安全证书。它们所构成复杂的证书体系,对于初学Kubernetes而又对密码学一知半解的你来说,很可能是一道很难逾越的关卡。事实上,现阶段国内外互联网上关于Kubernetes的公共资源中(包括官网),都没有系统地介绍过这些证书的来龙去脉以及协同工作的机制。本篇文章中,笔者旨在通过自己的学习研究及实际工作实践,来揭开Kubernetes中证书体系的层层神秘面纱,希望能为正在学习和Kubernetes实践过程中有着同样困惑的朋友指点迷津。

HTTPS的前世今生

初学Kubernetes的朋友想必都了解,Control Plane各个核心组件均采用了HTTPS协议进行相互通信。因此,在了解Kubernetes的证书体系之前,为了做到不浅尝辄止,在这里有必要对HTTPS的安全体系进行一个介绍。该体系涉及到许多密码学的相关内容,如果您对于非对称加密算法、CA认证机构、数字证书、双向认证这些术语非常陌生,那么我相信以下的内容,会为你打开一扇学习密码学的大门,同时会为你后续了解Kubernetes数字证书体系做好充足的知识储备。

从名字组成上看,很容易就能猜到,HTTPS中的S就是Secure的意思。从技术角度来讲,HTTPS是HTTP Over TLS或者HTTP Over SSL的缩写,HTTPS协议经由HTTP进行通信,同时利用SSL/TLS来加密数据包,而TLS(Transport Layer Security)其实是SSL(Secure Sockets Layer)的演进版本。

因此,为了理解HTTPS,我们就要先从SSL开始,而要了解SSL,就不得不提及"数据传输加密算法"。这个事情如果真要追根溯源的话,故事可要从上世纪40年代第二次世界大战开始谈起。

图片出处: SSL Handshake and HTTPS Bindings on IIS

对称加密与非对称加密

众所周知,我们在现代网络环境中发送信息时,在没有加密的情况下,数据包默认都是明文,传输内容非常容易被第三方截获造成数据泄露。早在二战时期,军方就考虑到这个问题,在电报中开始使用"密码本"配合"密码机"发送和接收电报。而这种加密方式的弊端也显而易见,如果"密码本"和"密码机"同时被截获,密码就形同虚设。

我们身边耳熟能详的例子,当属德军在二战中使用的"谜“氏密码机—Enigma。由于它的存在,使得德军的军事行动神出鬼没,尤其是隔三差五、突如其来的空袭,使盟军苦不堪言。当然,由于"密码机"和"密码本"的缴获,它最终还是被盟军破译,而破译的功臣就是图灵(没错,就是你知道的那个Alan Turing),成功破译使得第二次世界大战至少提前两年结束,但Enigma的秘密本身在战后50年仍被列为政府最高机密。如果你看过2014年度拿到8项奥斯卡提名、由"卷福"主演的电影《模仿游戏》,相信你一定会对这个Enigma密码机印象深刻,要知道,这是德国70年前已经达到的密码机制作水平。

从密码学的发展历史来看,Enigma这种"密码本"和"密码机"的加密方法,其实就是"对称加密算法"(Symmetric-key algorithm)的雏形。这种加密方式下,通信双方都持有同一秘钥用来加密和解密数据,因此该算法也称为"单钥加密"(private key cryptography)。但正如之前提到的网络明文传输问题,双方在交换秘钥过程中,一旦秘钥泄露,加密信息就不再安全。

1977年,为了解决这个问题,美国三位科学家Rivest、Shamir 和 Adleman,设计了一种新的算法,并以三位科学家的名字命名,想必你已经猜到,这就是IT圈中赫赫有名的" RSA算法 ",它是一种典型的"非对称加密算法"(asymmetric cryptography)。与对称加密算法不同的是,RSA算法中秘钥分为两种:即公钥(公开)和私钥(不公开),所以该算法也称为"双钥加密"(public key cryptography)。2002年,三位科学家因为RSA算法的杰出贡献获得了图灵奖,直至今日,RSA算法仍然是使用最广泛的"非对称加密算法",毫不夸张地说,只要有计算机网络的地方,就有RSA算法。

那么RSA算法到底是什么,我们试着用下面这张图解释一下使用RSA算法的Client/Server通讯过程:

图片出处: Keyless SSL: The Nitty Gritty Technical Details

  1. [明文传输]Client发送随机数client_random和支持的加密方式列表
  2. [明文传输]Server返回随机数server_random、Server的公钥证书
  3. [密文传输]Client使用Server公钥证书中的公钥,加密premaster secret,并发送给Server
  4. [Server端]Server使用私钥解密premaster secret
  5. [对称加密]C/S两端同时使用client_random,server_random 和premaster secret 生成master secret(即图中的session key),作为对称加密的通信秘钥

上图中1-4步骤即为RSA非对称加密算法,最后一步是使用session key的对称加密。

从此看出,"非对称加密算法"与"对称加密算法"并不只是非此即彼的关系,实际加密过程中,二者相辅相成,各有千秋:

  • 非对称加密的优势:
    • premaster secret的引入,这个阶段由于是使用公钥加密的密文传输,该字段无法被攻击者窃听
    • 对称加密中使用的session key是由RSA算法中的前三个随机数生成,增加了攻击者破解的难度
  • 非对称加密的劣势:
    • 加密效率低,耗时长,因此一般在C/S通讯模型的握手过程中会使用非对称加密,在握手结束后,双方会使用对称加密方式进行数据传输工作

CA认证、数字证书及数字签名

上文我们介绍了非对称加密算法的一个重要应用——消息加密。接下来我们要谈一下该算法的另一个重要应用——数字签名。

尽管RSA算法解决了明文传输的弊端,但是传输内容仍然存在着被劫持的可能,那就是" 中间人攻击 "。简单来讲,"中间人攻击"就是在非对称加密过程中,Client和Server的通讯被第三方劫持(比如通过DNS劫持或ARP投毒的方式),造成的结果就是在整个通信过程中,双方并没有直接通信,而都是在跟第三方— 即中间人交互数据,限于篇幅原因,关于中间人攻击的详细原理,感兴趣的朋友可以自行搜索维基百科。

图片出处: Who and how is using forged SSL certificates worldwide?

由上图的示例不难看出,出现中间人攻击的根源在于:在通讯中,Client接收的实际上是中间人的Server公钥证书,它无法验证接收的Server公钥是否真的来自于Server。如果想解决这个问题,就需要引入CA认证体系—包括"证书颁发机构(CA)"、"数字证书"和"数字签名"这三个概念,即在中间人攻击的例子中,让一个第三方认证机构(CA)来验证Server公钥的合法性,这三个概念简要说明如下:

证书颁发机构(Certificate Authority)

从维基百科的定义可以看到,CA(Certificate Authority)是负责发放和管理数字证书的权威机构,作为电子商务交易中受信任的第三方,承担着公钥体系中公钥的合法性检验的责任。

全球知名的CA认证机构如下图所示,可以看到,目前各大组织和公司使用的CA厂商基本为国外机构。尽管国内亦有认证机构涉及(如早期的CNNIC、后期由360主导的沃通),但事实是,如果经常访问国内大中型银行的网上银行,你就会发现,目前它们使用的数字证书均是由国外CA认证机构签发。从另一个侧面来看,我们日常使用的主流浏览器,如IE、Chrome、Firefox中,都预先内置了大量CA认证机构提供的根数字证书,但并不是所有CA认证机构根证书都会被内置在浏览器中,这些浏览器选择哪些CA认证机构,或多或少都代表了浏览器厂商对于这些CA认证机构的信任程度。

图片出处: 维基百科Certificate authority介绍 ,该统计数据来自W3Techs在2018年5月的调研结果

数字证书(Digital Certificate—Public Key Certificate)

介绍完CA,再来看一下CA体系中另一个重要组成部分— 数字证书。结合刚刚提到的"中间人攻击",我们可以看到,只有引入第三方认证机构(CA),Client拥有了由CA机构颁发的数字证书,Server公钥的合法性才能得到保障。由于目前互联网网站中大多数的数字证书都是基于 X.509 V3标准,因此X.509证书已经成为互联网数字证书的代名词,本文中如果无特殊声明,提到的数字证书都是基于X.509标准。

X.509证书主要包含数据加密(Encryption)和数字签名(Digital Signature)内容,以提供认证的实现,确保数据的一致性(Integrity)和机密性(Confidentiality)。下图中以维基百科网站的x509证书为例进行解析,可以看到,里面包含了签发者信息、证书有效信息,主题信息,以及公钥信息和数字签名,还有一些证书扩展信息。

图片出处: 维基百科X.509介绍

数字签名(Digital Signature)

从刚刚介绍的维基百科的数字证书中,我们可以看出,数字证书中通常有两大类内容:一是证书数据(Data File),通常包含签发机构、有效期、公钥信息及扩展信息等内容;二是结尾的数字签名(Digital Signature),在这里,数字签名的作用就是为了证明数字证书中Data File的合法性,从而防止中间人攻击的情况。

数字签名从技术角度,涉及两个过程:签名(Signing)和验证(Verification),签名过程由CA认证机构发起,验证过程由需要进行证书验证的实体发起。

从严谨的角度来讲,需要进行证书验证的实体,可能是需要进行Server验证的Client端,也可能是需要Client验证的Server端。

图片出处: Our choice of digital signature algorithm

签名过程分析(图中Signing部分):

  1. 将证书的Data File使用SHA1算法计算出hash值
  2. 使用私钥(private key)进行对hash值RSA加密,得到数字签名
  3. 将数字签名附加到数字证书中,用于内容验证

验证过程分析:(图中Verification部分):

  1. 将证书中Data File经过SHA1算法加密,计算出hash值H1
  2. 将证书中的数字签名使用CA机构分发的公钥(public key)进行RSA解密,得到hash值H2
  3. 将H1和H2进行对比,如果相同,则为合法证书;如果不同,则为伪造证书。

基于上文对CA认证机构、数字证书和数字签名的介绍,让我们来看一个实际的例子:

当用户通过浏览器访问HTTPS网址时,浏览器首先会获取网站的数字证书(内含数字签名,该证书由CA认证机构签发),浏览器通过内置的CA根数字证书的公钥,来验证该网站数字证书中数字签名的合法性,验证通过后,才能使用该数字证书,进行后续的数据传输工作(传输过程如之前的RSA算法所述)。值得一提的是,"非对称加密算法"中的私钥和公钥在这个通信过程中,有两种应用场景,而在这两种场景中,它们的使用方式恰好是相反的:

  • 数字签名:CA认证机构使用私钥制作签名,需要进行证书验证的实体利用CA根数字证书中的公钥来验证签名
  • 数据加密:Client使用数字证书中的公钥加密传输数据,Server使用私钥解密传输数据。

证书信任链(Certificate Authority Chain)

需要说明的是,网站的证书签发者,很可能不是该CA认证机构的根证书,因为中间会存在一级或多级的中级证书颁发机构(Intermediate Certificate),因此在验证过程中可能会存在"证书链"的验证逻辑,如下图所示:

图片出处: High Performance Browser Networking by Ilya Grigorik

HTTPS双向认证

留心的朋友可能已经注意到,在前面章节中介绍的浏览器访问网站的例子中,Client仅对Server的证书进行单向验证,这种方式称为Server Authentication(下文简称"Server Auth")。而在Kubernetes的证书体系中,API Server和其他组件的交互中,还存在很多Server对Client的验证场景,这种方式称为Client Authentication(下文简称"Client Auth")。两者组合起来,称为"双向认证"— Mutual authentication

我们可以通过以下图例,了解双向认证的通信过程:

图片出处: An Introduction to Mutual SSL Authentication

图中步骤1-3就是上文中谈到的Server Auth,而步骤4-5就是Client Auth,两者的认证都需要借助CA认证机构(当然并不一定是同一家CA认证机构)进行校验,因此这种认证称为"双向认证"。实际生活中也有这样的例子,比如我们在网上银行中经常使用的U盾,税务系统中企业报税使用的CA证书,都是Server校验Client证书的典型实践,下图是一个某省电子认证公司的广告宣传,仅供参考:

Kubernetes数字证书体系

从这里开始,我们开始正式介绍Kubernetes数字证书的相关内容,如果你在阅读过程中,对其中的一些概念和术语还是比较陌生,建议你重新回顾上一章节内容,温故而知新。

在介绍Kubernetes核心组件的证书体系之前,以下图为例,画一下重点,后续会分类进行详细说明:

由于涉及证书数量众多,为了便于理解,基于刚刚提到的双向认证概念,我们将证书体系分成两类:Server Auth和Client Auth,后续的很多分析都是依照这个分类逻辑进行介绍。

Server Auth

  1. 如上图,从架构体系这个维度来看,集群环境中最重要的组件其实就两个—etcd和API Server,etcd作为所有Kubernetes中对象的配置信息库,API Server提供所有组件的API访问接口。因而在证书体系中,两者是各需要一套CA证书链。
  2. 除了etcd和API Server外,kubelet在master和node的通信中,也扮演着重要的角色,在有些Kubernetes环境中(比如kubespray默认模式部署),kubelet也存在的一套CA证书链(但不是必要的)。另外,默认情况下,API Server访问kubelet时,不需要对kubelet进行Server Auth。

Client Auth

  1. 对于访问API Server的其他组件,除了需要确认API Server是可信之外(Server Auth),更重要是是向API Server证明自己是可信的(Client Auth),因此在很多API Server相关组件不同形式的配置参数和文件中,都会见到Client Certificate的身影。
  2. 如果集群中部署了extension API Server(比如Metrics),访问extension API Server也需要进行Client Auth(对应API Server启动参数中proxy-client和requestheader相关内容)。
  3. 如果存在多集群管理的容器平台,那么该容器平台无论通过Web API或者kubectl客户端方式访问某个集群的API Server,都需要将容器平台的Root CA证书附加到API Server的信任CA证书中,否则API Server会认为该容器平台是不可信的,容器平台将无法通过API访问该集群。

Kubernetes环境中,除了主要使用CA认证体系之外,常见认证方式还有其他类型,比如对Service Account进行签名验证,该验证使用的是JWT—JSON Web Token方式,本文中限于篇幅原因暂不展开讨论。

CA根证书和证书信任链

初学者在搭建Kubernetes的时候,各种CA证书会让人摸不着头脑,相信很多朋友总有这样一个疑问:Kubernetes集群中到底有几个Root CA,或者说有几套CA的证书链。

笔者通过对Kubernetes的官方资料的研究及实践,发现在目前主流版本的Kubernetes单集群中,最多存在四条CA信任链,而在大多数环境中,则至少需要两条CA信任链,即API Server CA信任链和etcd CA信任链。

etcd的CA信任链由于只涉及apiserver的两方通信,逻辑较为简单,本文中不做展开介绍。

apiserver涉及众多核心组件,比较复杂,后续专门开一个小节进行分析。

apiserver CA信任链(必要)

  • CA根证书存放路径:/etc/kubernetes/pki
  • CA根证书文件名称:ca.crt
  • 功能描述:用于Server/Client Authentication的证书签发,签发证书主要用于以apiserver为中心的内部组件互访

etcd CA信任链(必要)

  • CA根证书存放路径:/etc/kubernetes/pki/etcd
  • CA根证书文件名称:ca.pem
  • 功能描述:用于Server/Client Authentication的证书签发,签发证书主要用于apiserver访问etcd(Server+Client Auth),etcd集群内节点互信(Peer Auth)

extension apiserver CA信任链(可选,但不可与API Server共用CA证书)

  • CA根证书存放路径:/etc/kubernetes/pki
  • CA根证书文件名称:front-proxy-ca.crt
  • 用于访问extension apiserver(比如监控组件Metrics)的Client Auth

该证书不可与API Server的CA共用,根据官网关于 CA Reusage and Conflicts 的说明,问题主要出在Kubernetes的架构设计上:client在访问API Server时,需要参考以下顺序进行证书验证工作:

1、--requestheader-client-ca-file指定的CA证书(优先参考)

如果Client证书由该CA证书签发,则对比Client证书中的CN—Common Name和--requestheader-allowed-names是否一致,如果一致,访问请求通过;反之,则拒绝访问。

2、--client-ca-file指定的CA证书(非优先参考)

如果Client证书由该CA证书签发,则通过访问请求,并将client证书中的CN—Common Name和O—Organization作为User和Group字段,用于后续RBAC的授权;反之,则拒绝访问。

试想,如果两者使用同一个CA证书,就会使得原本访问apiserver的client被强制导向到extension apiserver的Client Auth机制上,使得访问无法通过,最典型的结果,就是control plane的相关组件和kubelet无法同apiserver进行正常通信。

kubelet CA信任链(非必要,可并入apiserver CA信任链)

  • CA证书存放路径:可自行指定
  • CA证书文件名称:可自行指定
  • 功能描述:用于API Server访问kubelet时,进行Server Auth(默认情况不验证)

小结一下:

以上这四套CA信任链,apiserver和etcd是必要的。

extension apiserver的CA信任链只有在使用时才会用到,但不可与apiserver CA相同。

kubelet的CA信任链不是必要的,有时根据部署的实际情况,合并到apiserver的CA信任链中。

具体的CA证书链关系可以参考笔者总结的思维导图(基于kubespray部署的Kubernetes环境—版本为v1.12.7)。

注:kubespray默认部署的Kubernetes集群中,证书默认目录为/etc/kubernetes/ssl,不是/etc/kubernetes/pki。

数字证书的几种表现形式

>本案例中,CNI plugin使用的是Flannel,如果使用Calico、Weave者其他的Plugin,可参考相关类似配置。

  • 实体证书,证书(通常为crt或pem扩展名)一般在Pod的启动参数中指定,常见于yaml文件中
  • 内嵌证书(embed),证书通过Base64转码后,存放于对应组件的kubeconfig中,常见于admin、scheduler、controller manager、kubelet等组件(用于Server+Client Auth),各Pod的启动参数需要指定kubeconfig路径
  • secrets,常见于kube-flannel等组件(Server Auth)
  • ConfigMaps,常见于kube-proxy等组件(Server Auth),ConfigMaps中内含kubeconfig+secrets

API Server与各组件的认证关系

由于API Server组件是Kubernetes的核心中枢,在与其他组件进行互访时,都需要进行证书验证,毫不夸张的说,研究Kubernetes的证书体系,基本上就是在研究API Server与其他组件通信时相互证书验证的机制。我们依照之前的思路,还是将互信关系分为Server Auth和Client Auth进行介绍。

本案例中,CNI plugin使用的是Flannel,如果使用Calico、Weave者其他的Plugin,可参考相关类似配置。

Server Auth

API Server使用--tls-cert-file参数指定Server Auth的证书—apiserver.crt(由apiserver CA信任链的CA根证书签发)。由下图可以看到,其他组件以Client身份访问apiserver时,由于信任Root CA,API Server对这些组件来讲,就是一个可信Server。

需要说明的是,各个组件内存放该Root CA证书的形式各异,具体不同可以参考下图中文字说明。

留心的朋友可能已经注意到,截止目前,Kubernetes的最新版本(1.15)的官网资源关于 Master Node Communication 的介绍中,API Server在访问kubelet时,是不需要进行Server Auth验证的。但这种情况如果放在公网环境中,可能导致MITM(中间人攻击),因此如果安全方面有要求,可以在apiserver的启动参数中进行指定相关参数实现对kubelet的Server Auth,具体可以参考下图的说明。

Client Auth

Client Auth的目的是为了让各组件访问apiserver时,让apiserver认为自己是可信的。

该机制主要应用于以下三个方面:

  1. 用于集群内各组件访问apiserver,Client证书通常内嵌于各模块的kubeconfig文件中
  2. 用于集群内apiserver访问kubelet,该证书通常配置于apiserver的启动参数中
  3. 用于集群外系统(如管理多集群的容器平台)访问apiserver,将该系统的Root CA证书附加到API Server的信任CA证书中,否则API Server会认为该系统是不可信的,该系统也就无法通过API访问该集群

上图中出现的容器平台用于我行Kubernetes多集群管理,对于单集群Kubernetes可不采用,这里仅作简单说明。

  • Client CA签发的证书,用于Client Auth,容器平台普通用户和管理员用户访问Kubernetes集群apiserver(kubectl)
  • Portal CA签发的证书,用于Client Auth,容器平台普通用户和管理员用户访问Kubernetes集群apiserver(Web API)

为什么一定是X.509证书?

我们在介绍数字证书中,重点提到了一种证书类型—X.509,它是CA认证体系的重要组成部分。在本篇的结尾,想必很多朋友还会有一个疑问:那就是为什么X.509证书在Kubernetes环境中广泛使用?

通过对Kubernetes官网中关于 Authentication的机制介绍 ,我们可以看到,其实Kubernetes集群在认证方式的选择上,CA认证体系(即X.509证书)并不是唯一的选择。Kubernetes集群支持很多种认证方式(限于篇幅,仅列出常见的几种):

  • Static Token File
  • Static Password File
  • OIDC—Open ID Connect
  • X509 Client Certs—即双向认证中提到的Client Auth

那么为什么x509证书会在Kubernetes核心组件中广泛使用呢?笔者通过研究与实践,认为原因有三:

  1. 从信息安全的角度来看,x509证书运用了非对称加密算法(即双钥加密)以及数字签名,相对于使用password和token方式来讲,更为安全,更难破解。
  2. 从用户管理存储介质的角度来看,Kubernetes是不管理普通用户(Normal User)的,而是将它解耦出来,交给外部的独立组件,比如keystone,又或者在互联网环境,通过OIDC这种方式,交给OAuth2 Provider进行交互验证。单就Kubernetes控制平台的相关用户和组来说,x509证书没有使用任何外部用户管理系统来存储相关的认证信息,而是将这些用户信息内置到证书文件中,使用者不需要付出额外的精力来完成前面提到用户管理的工作。
  3. 从Kubernetes认证和授权体系来看,Kubernetes使用x509证书中CN(Common Name)以及O(Organization)字段对应Kubernetes中的user和group,将Authentication和 RBAC Authorization 结合到了一起,巧妙地将Control Plane中的各个核心User和Group、与操作权限(ClusterRole)进行了绑定(ClusterRoleBinding),这也是笔者认为使用x509证书最重要的一个原因。

如果您对RBAC Authorization的相关部分不了解,可以通过链接阅读Kubernetes官网的相关章节。

下图是基于kubespray搭建Kubernetes环境中(版本为v1.12.7),笔者通过分析各组件Client证书内容,总结的Client Certificate和RBAC授权的关系表,供感兴趣的朋友参考。

结语

Kubernetes作为CNCF的核心项目,在容器技术蓬勃发展的短短几年里,已然成为了容器编排平台以及云原生(Cloud Native)的代名词,无论在国内还是国外,关于Kubernetes的应用和开发内容,也迅速成为了近几年云技术讨论的热门话题。值得注意的是,在各个社区和公司都关注Kubernetes功能性需求的同时,Kubernetes的安全问题也逐渐也成为了摆在容器管理员面前一个不能忽视的话题。

本篇文章中,笔者以HTTPS的相关认证体系为基础,深入解析了Kubernetes内部证书体系中的各层关系,为我行下一步进行容器平台建设和证书体系改造,提供了详实的技术参考和依据。另外,笔者也希望通过本文,能够为正在学习、想深入研究Kubernetes安全认证体系的朋友们抛砖引玉,开拓思路,限于个人技术水平,观点和分析可能存在片面性或不准确之处,也欢迎感兴趣的朋友在公众号留言及讨论。

作者:温啸,任职于民生银行灾备管理中心,10年以上基础架构的设计和运维经验,目前主要致力于异地灾备建设和运维工作,对OpenStack和Kubernetes技术亦有一定的研究。

原文链接: https://mp.weixin.qq.com/s/iXuDbPKjSc65t_9Y1--bog

相关文章