6.1 API Server认证管理

我们知道,Kubernetes集群中所有资源的访问和变更都是通过Kubernetes API Server的REST API实现的,所以集群安全的关键点就在于如何识别并认证客户端身份(Authentication),以及随后访问权限的授权(Authorization)这两个关键问题,本节将讲解认证管理的内容。

Kubernetes集群有两种用户账号:第1种是集群内部的Service Account;第2种是外部的用户账号,可能是某个运维人员或外部应用的账号。Kubernetes并不支持常规的个人账号,但拥有被Kubernetes集群的CA证书签名的有效证书,个人用户就可被授权访问Kubernetes集群了,在这种情况下,证书中Subject(主题)里的信息被当作用户名如"/CN=bob"。因此,任一Kubernetes API的访问都属于以下三种方式之一:

◎ 以证书方式访问的普通用户或进程,包括运维人员及kubectl、kubelets等进程;

◎ 以Service Account方式访问的Kubernetes的内部服务进程;

◎ 以匿名方式访问的进程。

Kubernetes集群提供了以下用户身份认证方式。

◎ HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式。

◎ HTTP Bearer Token认证:通过一个Bearer Token识别合法用户。

◎ OpenID Connect Token第三方认证:通过第三方OIDC协议进行认证。

◎ Webhook Token认证:通过外部Webhook服务进行认证。

◎ Authenticating Proxy认证:通过认证代理程序进行认证。

本节对这些认证方式的原理和使用方式进行详细说明。

6.1.1 HTTPS证书认证

这里需要有一个CA证书,CA是PKI系统中通信双方都信任的实体,被称为可信第三方(Trusted Third Party,TTP)。CA作为可信第三方的重要条件之一,就是其行为具有非否认性。作为第三方而不是简单的上级,就必须让信任者有追究自己责任的能力。CA通过证书证实他人的公钥信息,在证书上有CA的签名。如果用户因为信任证书而有了损失,证书就可以作为有效的证据用于追究CA的法律责任。CA正是因为对责任的承诺,也被称为可信第三方。在很多情况下,CA与用户都是相互独立的实体,CA作为服务提供方,有可能因为服务质量问题(例如发布的公钥数据有错误)而给用户带来损失。在证书中绑定了公钥数据和相应私钥拥有者的身份信息,并带有CA的数字签名;在证书中也包含了CA的名称,以便于依赖方找到CA的公钥,验证证书上的数字签名。

CA认证涉及诸多安全术语,比如根证书、自签名证书、密钥、私钥、加密算法及HTTPS等,本节主要讲解CA认证的工作流程,以进一步理解Kubernetes CA认证的配置流程。

如图6.1所示,CA认证的工作流程如下。

(1)HTTPS通信双方的服务端向CA机构申请证书,CA机构是可信的第三方机构,它可以是一个公认的权威企业,也可以是企业自身。企业内部系统一般都用企业自身的认证系统。CA机构下发根证书、服务端证书及私钥给申请者。

(2)HTTPS通信双方的客户端向CA机构申请证书,CA机构下发根证书、客户端证书及私钥给申请者。

(3)客户端向服务端发起请求,服务端下发服务端证书给客户端。客户端在接收到证书后,通过私钥解密证书,并利用服务端证书中的公钥认证证书信息比较证书里的消息,例如,比较域名和公钥与服务器刚刚发送的相关消息是否一致,如果一致,则客户端认可这个服务器的合法身份。

(4)客户端发送客户端证书给服务端,服务端在接收到证书后通过私钥解密证书,获得客户端证书公钥,并用该公钥认证证书的信息,确认客户端是否合法。

(5)客户端通过随机密钥加密信息,并发送加密后的信息给服务端。在服务端和客户端协商好加密方案后,客户端会产生一个随机的密钥,客户端通过协商好的加密方案加密该随机密钥,并发送该随机密钥到服务端。服务端接收这个密钥后,双方通信的所有内容都通过该随机密钥加密。

图6.1 CA认证的工作流程

上述是双向CA认证协议的具体通信流程,在这种情况下要求服务器和用户双方都拥有证书。单向认证协议则不需要客户端拥有CA证书,对于上面的步骤,只需将服务端验证客户证书的过程去掉,之后协商对称密码方案和对称通话密钥时,服务端发送给客户端的密码没被加密即可。

6.1.2 HTTP Bearer Token认证

为了验证使用者的身份,需要客户端向服务端提供一个可靠的身份信息,称之为Token,这个Token被放在HTTP Header头里,在Token里有信息来表明客户身份。Token通常是一个有一定长度的难以被篡改的字符串,比如 31ada4fd-adec-460c-809a-9e56ceb75269,我们用私钥签名一个字符串后的数据也可被当作一个加密的Token。在Kubernetes中,每个Bearer Token都对应一个用户名,存储在API Server能访问的一个文件中(Static Token file)。客户端发起API调用请求时,需要在HTTP Header里放入此Token,这样一来,API Server就能识别合法用户和非法用户了。

要使用这种认证方式,就需要为API Server服务设置一个保存用户信息和Token的文件,通过启动参数--token-auth-file=SOMEFILE指定文件路径。该文件为CSV文本文件格式,每行内容都由以下字段组成:

对其中各字段说明如下。

◎ token:必填,Token字符串。

◎ user:必填,用户名。

◎ uid:必填,用户ID。

◎ groupnames:可选,用户组列表,如果有多个组,则必须使用双引号。

Token文件示例如下:

通过Service Account认证方式访问API Server,其实也采用了与HTTP Bearer Token相同的实现方式。我们知道,每个Service Account都对应一个Secret对象,在Secret对象中就有一个加密的Token字段,这个Token字段就是Bearer Token。这个Token是用哪个私钥加密的,要取决于API Server的启动参数--service-account-key-file设置的文件,如果没有指定该参数,则会采用API Server自己的私钥进行加密。为了方便Pod里的用户进程使用这个Token访问API Server,Secret Token里的内容会被映射到Pod中固定路径和名字的文件中。另外,如果API Server设置了启动参数--service-account-lookup=true,API Server就会验证Token是否在etcd中存在,如果已从etcd中删除,则将注销容器中Token的有效性。

6.1.3 OpenID Connect Token第三方认证

Kubernetes也支持使用OpenID Connect协议(简称OIDC)进行身份认证。OIDC协议是基于OAuth 2.0协议的身份认证标准协议,在OAuth 2.0上构建了一个身份层,OIDC的登录过程与OAuth相比,最主要的扩展就是提供了ID Token,这是一个JWT格式的加密Token。API Server本身与OIDC Server(即Identity Provider)没有太多交互,用户(主要是kubectl用户)通过OIDC Server得到一个合法的ID Token,并作为命令行参数(或者kubectl的配置文件)传递给API Server,API Server则通过验证该Token是否合法及是否有效来确定用户的身份。虽然在OIDC Server中可以做到用户的权限管理,但Kubernetes并不使用OIDC Server的权限管理,因为它有自己完善的BRAC权限管理体系。

要使用OIDC Token认证方式,就需要为API Server配置以下启动参数。

◎ --oidc-issuer-url:必填,设置允许API Server发现公共签名密钥的URL,仅支持HTTPS,通常应为/.well-known/openid-configuration路径的上一级URL,例如谷歌提供的公共签名密钥URL为“https://accounts.google.com/.well-known/openid-configuration”,则将该参数的值设置为“https://accounts.google.com”。

◎ --oidc-client-id:必填,需要颁发Token的客户端ID,例如“kubernetes”。

◎ --oidc-username-claim:可选,用作用户名的JWT Claim名称,默认值为“sub”。

◎ --oidc-username-prefix:可选,设置用户名Claim的前缀,以防止与已存在的名称(如以system:开头的用户名)产生冲突,例如“oidc:”。

◎ --oidc-groups-claim:可选,用作用户组的JWT Claim名称,需要将其设置为字符串数组格式。

◎ --oidc-groups-prefix:可选,设置用户组Claim的前缀,以防止与已存在的名称(如以system:开头的组名)产生冲突,例如“oidc:”。

◎ --oidc-required-claim:可选,设置ID Token中必需的Claim信息,以key=value的格式设置,重复该参数以设置多个Claim。

◎ --oidc-ca-file:可选,将其设置为对ID提供商的Web证书进行签名的CA根证书全路径,例如/etc/kubernetes/ssl/kc-ca.pem。

需要说明的是,Kubernetes本身不提供OpenID Connect ID服务,用户可以选择使用互联网ID提供商的服务,或者使用第三方系统,例如dex、Keycloak、CloudFoundry UAA、OpenUnison等。

为了与Kubernetes一起工作,ID提供商必须满足以下要求。

◎ 提供OpenID Connect发现机制。

◎ 基于TLS协议运行,并且不存在已过时的密码。

◎ 拥有经过权威CA中心签发的证书。

4.Webhook Token认证

Kubernetes也支持通过外部Webhook认证服务器,配合HTTP Bearer Token来实现自定义的用户身份认证功能。

其工作原理和流程:开启并配置API Server的Webhook Token Authentication功能,API Server在收到客户端发起的一个需要认证的请求后,从HTTP Header中提取出Token信息,然后将包含该Token的TokenReview资源以HTTP POST方式发送给远程Webhook服务进行认证。然后,API Server根据远程Webhook服务返回的结果判断是否认证成功。远程Webhook服务返回的结果也需要是一个TokenReview资源对象,并且它的apiVersion需要与API Server发出请求的apiVersion保持一致,即同为authentication.k8s.io/v1beta1或authentication.k8s.io/v1。

要使用Webhook Token认证方式,就需要为API Server配置以下启动参数。

◎ --authentication-token-webhook-config-file:说明如何访问远程Webhook服务的配置文件。

◎ --authentication-token-webhook-cache-ttl:缓存Webhook服务返回的认证结果的时间,默认值为2min。

◎ --authentication-token-webhook-version:发送给Webhook服务的TokenReview资源的API版本号,API组为authentication.k8s.io,版本号可以为"v1beta1"或"v1",默认版本号为"v1beta1"。

访问远程Webhook服务的配置文件使用kubeconfig格式,其中clusters字段设置远程Webhook服务的信息,users字段设置API Server的信息,例如:

API Server在收到客户端的认证请求之后,提取其HTTP Header中的Token之后,将会生成如下内容的TokenReview资源对象:

API Server将这个TokenReview资源对象的JSON报文序列化后发送给远程Webhook服务,认证结果也以TokenReview资源对象的格式返回给API Server,结果通过status字段进行声明。

一个认证成功的应答TokenReview内容示例如下:

一个认证失败的应答TokenReview内容示例如下:

6.1.4 Authenticating Proxy(认证代理)

在这种方式下,将API Server配置为从HTTP Header(例如X-Remote-User字段)对用户进行识别。这需要与Authenticating Proxy程序一同工作,由Authenticating Proxy设置HTTP Header的值。

要使用这种认证方式,就需要为API Server配置以下启动参数。

◎ --requestheader-username-headers:必填,区分大小写,在HTTP Header中用于设置用户名的字段名称列表,API Server将按顺序检查用户身份。第1个设置了值的Header字段将被用作用户名。常用的字段名为“X-Remote-User”。

◎ --requestheader-group-headers:在Kubernetes 1.6版本以上可配置,可选,区分大小写。在HTTP Header中用于设置用户组的字段名称列表,API Server将按顺序校验用户的身份。常用的字段名为“X-Remote-Group”。

◎ --requestheader-extra-headers-prefix:在Kubernetes 1.6版本以上可配置,可选,区分大小写。Header字段的前缀用于确定用户的其他信息(通常由配置的授权插件使用)。常用的字段名为“X-Remote-Extra-”。

如果在一个请求中包含以下HTTP Header字段:

则将生成如下用户信息:

为了验证Authenticating Proxy程序的身份,Authenticating Proxy程序需要把有效的客户端CA证书先提供给API Server,使得API Server可以向CA中心进行身份认证。只有在API Server验证了该客户端CA证书有效之后,才会校验在HTTP Header中设置的用户名。这需要为API Server通过以下启动参数进行配置。

◎ --requestheader-client-ca-file:必填,Authenticating Proxy程序的有效客户端CA证书文件全路径。

◎ --requestheader-allowed-names:可选,通用名称值(CN)列表,如果设置,则在客户端CA证书中必须包含CN列表中的值;如果将其设置为空,则表示允许任何CN。