Kuberetes通过一系列机制来实现集群的安全控制,其中包括API Server的认证授权、准入控制机制及保护敏感信息的Secret机制等。集群的安全性必须考虑如下几个目标。
(1) 保证容器与其所在宿主机的隔离。
(2) 限制容器给基础设施或其他容器带来的干扰。
(3) 最小权限原则一合理限制所有组件的权限,确保组件只执行它被授权的行为,通过限制单个组件的能力来限制它的权限范围。
(4) 明确组件间边界的划分。
(5) 划分普通用户和管理员的角色。
(6) 在必要时允许将管理员权限赋给普通用户。
(7) 允许拥有Secret数据(Keys、Certs、passwords)的应用在集群中运行。
下面分别从Authentication、Authorization、AdmissionControl、Secret和Service Account等方面来说明集群的安全机制。
我们知道,Kubernetes集群中所有资源的访问和变更都是通过Kubernetes API Server的REST API来实现的,所以集群安全的关键点就在于如何识别并认证客户端身份(Authentication),以及随后访问权限的授权(Authorization)这两个关键问题,本节对认证管理进行说明。
Kubernetes集群提供了3中级别的客户端身份认证方式。
最严格的HTTPS证书认证:基于CA根证书签名的双向数字证书认证方式。
首先说说HTTPS证书认证的原理。
这里需要有一个CA证书,我们知道CA是PKI系统只通信双双方都信任的实体,被称为可信第三方。CA作为可信第三方的重要条件之一就是CA的行为具有非否认性。作为第三方而不是简单的上级,就不必须能让信任者有追究自己责任的能力。CA通过证书证实他人的公钥信息,证书上有CA的签名。用户如果因为信任证书而有了损失,则证书可以作为有效的证据用于追究CA的法律责任。正是因为CA承担责任的承诺,所以CA也被称为可信第三方。在很多情况下,CA与用户是相互独立的实体,CA作为服务提供方,有可能因为服务质量问题(例如,发布的公钥数据有错误)而给用户带来损失。在证书绑定了公钥数据和相应私钥拥有者的身份信息,并带有CA的数字签名;在证书中也包含了CA的名称,以便于依赖方找到CA的公钥,验证证书上的数字签名。
CA认证涉及诸多概念,比如根证书、自签名证书、私钥、密钥、加密算法及HTTPS等,本书大致讲述SSL协议的流程,有助于理解CA认证和Kubernetes CA认证的配置过程。
CA证书大概包含下面几个步骤。
(1) HTTPS通信双方的服务器端向CA机构申请证书,CA机构是可信的第三方机构,它可以是一个公认的权威企业,也可以是企业自身。企业内部系统一般都用企业自身的认证系统。CA机构下发根证书、服务端证书及私钥给申请者。
(2) HTTPS通信双方的客户端向CA机构申请证书,CA机构下发根证书、客户端证书及私钥给申请者。
(3) 客户端向服务器端发起请求,服务端下发服务端证书给客户端。客户端接收到证书后,通过私钥解密证书,并利用服务器端证书中的公钥证书信息比较证书里的信息,例如,比较域名和公钥与服务器刚刚发送的相关信息是否一致,如果一致,则客户端认可这个服务器的合法身份。
(4) 客户端发送客户端证书给服务器端,服务端在接受到证书后,通过私钥解密证书,获得客户端证书公钥,并用该公钥认证证书信息,确认客户端是否合法。
(5) 客户端通过随机密钥加密信息,并发送加密后的信息给服务端。在服务器端和客户端协商好加密方案后,客户端会产生一个随机的密钥,客户端通过协商好的加密方案加密该随机密钥,并发送该随机密钥到服务器端。服务器端接收这个密钥后,双发通信的所有内容都通过该随机密钥加密。
上述是双向认证SSL协议的具体通信过程,这种情况要求服务器和用户双方都有证书。单向认证SSL协议则不需要客户端拥有CA证书,对于上面的步骤,只需将服务器端验证客户证书的过程去掉,之后协商对称密码方案和对称通话密钥时,服务器发送给客户的密码没被加密即可。
HTTP Token的认证使用一个很长的特殊编码方式的并且难易被模仿的字符串——Token来表明客户身份的一种方式。
在通常情况下,Token是一个很复杂的字符串,比如我们用私钥签名一个字符串后的数据就可以被当作一个Token。此外,每个Token对应一个用户名,存储在API Server能访问的一个文件中。当客户端发起API调用请求时,需要在HTTP Header里放入Token,这样一来,API Server就能识别合法用户和非法用户了。
最后说说HTTP Base认证。
我们知道,HTTP是无状态的,浏览器和Web服务器之间可以通过Cooki来进行身份识别。桌面应用程序(比如新浪桌面客户端、SkyDrive客户端、命令行程序)一般不会使用Cookie,那么它们与Web服务器之间是如何进行身份识别的呢?这就用到了HTTP Base认证,这种认证方式是把“用户名+冒号+密码”用BASE64算法进行编码后的字符串放在HTTP Request中的Header Authorization域里发送给服务端,服务端在收到后进行解码,获取用户名及密码,然后进行用户身份鉴权。
当客户端发起API Server调用是,API Server内部要先进性用户认证,然后执行用户授权流程,即通过授权策略来决定一个API 调用是否合法。 对合法用户进行授权并且随后在用户访问时进行鉴权,是权限与安全系统的重要一环。 简单地说,授权就是授予不同的用户不同的访问权限。API Server目前支持一下几种授权策略(通过API Server的启动参数“--authorization-mode”设置)。
API Server在接收到请求后,会读取该请求中的数据,生成一个访问策略对象,如果在该请求中不带某些属性(如 Namesoace),则这些属性的值将根据属性类型的不同,设置不同的默认值(例如,为字符串类型的属性设置一个空字符串;为布尔类型的属性设置false;为数值类型的属性设置0)。然后将这个访问策略对象和授权策略文件中的所有访问策略对象逐条匹配,如果至少有一个策略对象被匹配,则该请求被鉴权通过,否则终止API调用流程,并返回客户端的错误调用码。
在API Server启用ABAC模式时,需要指定授权策略文件的路径和名称(--authorization- policy-file=SOME_FILENAME),授权策略文件里的每一行都以一个Map类型的JSON对象进行设置,这被称为“访问策略对象”。通过设置访问策略对象中的apiVersion、kind、spec属性来确定具体的授权策略,其中,apiVersion当前版本为abac.authorization.kubernetes.io/v1beta1;kind被设置为Policy;spec指详细的策略设置,包括主题属性、资源属性、非资源属性这三个字段,如下所述。
(1)主体属性
◎ user(用户名):字符串类型,该字符串类型的用户名来源于Token文件(--token-auth-file参数设置的文件)或基本认证文件中用户名称段的值。
◎ group(用户组):在被设置为“system:autheticated”时表示匹配所有已认证的请求,在被设置为“system:unauthenticated”时表示匹配所有未认证的请求。
(2)资源属性
◎ apiGroup(API组):字符串类型,表明匹配哪些API Group,例如extensions或*(表示匹配所有API Group)。
◎ namespace(命名空间):字符串类型,表明该策略允许访问某个Namespace的资源,例如kube-system或*(表示匹配所有Namespace)。
◎ resource(资源):字符串类型,API资源对象,例如pods或*(表示匹配所有资源对象)。
(3)非资源属性
◎ nonResourcePath(非资源对象类路径):非资源对象类的URL路径,例如/version或/apis,*表示匹配所有非资源对象类的请求路径,也可以设置为子路径,/foo/*表示匹配所有/foo路径下的所有子路径。
◎ readonly(只读标识):布尔类型,当它的值为true时,表明仅允许GET请求通过。
下面对ABAC授权算法、使用kubectl时的授权机制、常见ABAC授权示例、以及如何对Service Account进行授权进行说明。
API Server进行ABAC授权的算法为: 在API Server收到请求之后,首先识别出请求携带的策略对象的属性,然后根据在策略文件中定义的策略对这些属性逐条匹配,以判定是否允许授权。如果有至少一条匹配成功,那么这个请求就通过了授权(不过还是可能在后续其他授权校验中失败)。常见的策略配置如下。
◎ 要允许所有认证用户做某件事,可以写一个策略,将group属性设置为system:authenticated。
◎ 要允许所有未认证用户做某件事,可以把策略的group属性设置为system:unauthenticated。
◎ 要允许一个用户做任何事,将策略的apiGroup、namespace、resource和nonResourcePath属性设置为“*”即可。
kubectl使用API Server的/api和/apis端点来获取版本信息。要验证kubectl create/update命令发送给服务器的对象,kubectl需要向OpenAPI进行查询,对应的URL路径为/openapi/v2。
当使用ABAC授权模式时,下列特殊资源必须显示通过nonResourcePath属性进行设置。
◎ API版本协商过程中的/api、/api/*、/apis、和/apis/*。
◎ 使用kubectl version命令从服务器获取版本时的/version。
◎ create/update操作过程中的/swaggerapi/*
在使用kubectl操作时,如果需要查看发送到API Server的HTTP请求,则可以将日志级别设置如下:
kubectl --v=8 version
下面通过几个授权策略文件(JSON格式)示例说明ABAC的访问控制用法。
(1) 允许用户alice对所有资源做任何操作:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1","kind": "Policy","spec":{"user":"alice","namespace":"*","resource":"*","apiGroup":"*"}}
(2) kubelet可以读取任意Pod:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec": {"user": "", "namespace": "*", "resource": "pods", "readonly": true}}
(3) kubelet 可以读写Event 对象:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy", "spec" : {"user" : "kubelet", "namespace": "*" , "resource": "events"}}
(4) 用户bob只能读取projectCariboy中的Pod:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1", "kind": "Policy","spec":{"user": "bob", "namespace": "projectCarbou", "resource": "pods","readonly":true}}
(5) 任何用户都可以对非资源类路径进行只读请求:
{"apiVersion": "abc.authorization.kubernetes.io/v1beta1", "kind":"Policy", "spec":{"group": "system:authenticated","readonly":true,"nonResourcePath": "*"}}
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1","kind":"Policy, "spec": {"group": "system.unautheticated", "readonly": true, "nonResourcePath": "*"}}
如果添加了新的ABAC策略,则需要重启API Server以使其生效。
Service Account会自动生成一个ABAC用户名(username),用户名按照以下命名规则生成:
systemm:serviceaccount::
创建新的命名空间时,会产生一个如下名称的Service Account:
system:serviceaccount::default
如果希望kube-system命令空间中的Service Account "default"具有全部权限,就要在策略文件中加入如下内容:
{"apiVersion": "abac.authorization.kubernetes.io/v1beta1","kind":"Policy","spec":{"user": "system:serviceaccount:kube-system:default", "namespace":"*" "resource":"*","apiGroup":"*"}}
Webhook定义了一个HTTP回调接口,实现Webhook的应用会再指定事件发生时,向一个URL地址发送(POST)通知信息。启用Webhook授权模式后,Kubernetes会调用外部REST服务对用户进行授权。
Webhook模式用参数--authorization-webhook-config-file=SOME_FILENAME来设置远端授权服务的信息。
配置文件使用的是kubeconfig文件的格式。文件里user一节的内容指的是API Server。相对于远程授权服务来说,API Server是客户端,也就是用户;cluster一节的内容指的是远程授权服务器的配置。下面的例子为设置一个使用HTTPS客户端认证的配置:
clusters: #指定远端服务
- name: name-of-remoto-authz-service
certificate-authority: /path/to/ca.pem # 验证远端服务的CA
server: https://authz.example.com/authorize # 远端服务的URL,必须使用HTTPS
users: # API Server 的Webhook配置
- name: name-of-api-server
user:
client-certificate: /path/to/cert.pem # Webhook插件使用的证书
client-key: /path/to/key.pem
current-context: webhook # kubeconfig 文件需要设置 context
contexts:
- context:
cluster: name-of-remote-authz-service
user: name-of-api-server
name: webhook
在授权开始时,API Server会生成一个api.authorization.v1beta1.SubjectAccessReview对象,用于描述操作信息,在进行JSON序列化之后POST出来。在这个对象中包含用户尝试访问资源的请求动作的描述,以及被访问资源的属性。
Webhook API 对象和其他API对象一样,遵循同样的版本兼容性规则,在实现时要注意apiVersion字段的版本,以实现正确的反序列化操作。另外,API Server必须启用authorization.k8s.io/v1beta1 API扩展(--runtime-config=authorization.k8s.io/v1beta1=true)。
下面是一个希望获取Pod列表的请求报文示例:
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"resourceAttributes": {
"namespace": "kittensandponies",
"verb": "get",
"group": "unicorn.example.org"
"resource": "pods"
},
"user": "jane",
"group": [
"group1",
"group2"
]
}
}
远端服务需要填充请求中的SubjectAccessReviewStatus字段,并返回允许或不允许访问的结果。应答报文中的spec字段是无效,也可以省略。
一个返回“运行访问”的应答报文示例恶如下:
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"status": {
"allowed": true
}
}
一个返回“不运行访问”的应答报文示例如下:
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"status": {
"allowed": false,
"reason": "user does not have read access to the namespace"
}
}
非资源的访问请求路径包括/api、/apis、/metrics、/resetMetrics、/logs、/debug、/healthz、/swagger-ui/、/swaggerapi/、/ui和/version。通常可以对/api、/api/*、/apis、/apis/*和/version对于客户端发现服务器提供的资源和版本信息给予“允许”授权,对于其他非资源的访问一般可以禁止,以限制客户端对API Server进行没有必要的查询。
查询/debug的请求报文示例如下:
{
"apiVersion": "authorization.k8s.io/v1beta1",
"kind": "SubjectAccessReview",
"spec": {
"nonResourceAttributes": {
"path": "/debug",
"verb": "get"
},
"user": "jane",
"group": [
"group1"
"group2"
]
}
}
小结:
本节内容到此结束,谢谢大家的支持~
多多点关注哦。