详解Ocm Klusterlet秘钥管理机制

开发 架构
在 hub 集群中的registration-controller​会启动CSRApprovingController​用来负责检查klusterlet​发起的 CSR 请求是否可以自动签发;以及managedClusterController​用来检查对应ManagedCluster​上的hubAccepctsClient​域是否被设置并在hub集群中创建相应的权限。

概述

在open-cluster-management中,为了使控制面有更好的可扩展性,我们使用了hub-spoke的架构:即集中的控制面(hub)只负责处理控制面的资源和数据而无需访问被管理的集群;每个被管理集群(spoke)运行一个称为klusterlet的 agent 访问控制面获取需要执行的任务。在这个过程中,klusterlet需要拥有访问hub集群的秘钥才能和hub安全通信。确保秘钥的安全性是非常重要的,因为如果这个秘钥被泄露的话有可能导致对 hub 集群的恶意访问或者窃取敏感信息,特别是当ocm的被管理集群分布在不同的公有云中的时候。为了保证秘钥的安全性,我们需要满足一些特定的需求:

  1. 尽量避免秘钥在公有网络中的传输
  2. 秘钥的刷新和废除
  3. 细粒度的权限控制

本文将详细介绍ocm是如何实现秘钥的管理来保证控制面板和被管理集群之间的安全访问的。

架构和机制

在 ocm 中我们采用了以下几个机制来确保控制面和被管理集群之间访问的安全性:

  1. 基于CertificateSigniningRequest的 mutual tls
  2. 双向握手协议和动态klusterletID
  3. 认证和授权的分离

基于CertificateSigniningRequest的 mutual tls

使用kubernetes的CertificateSigniningRequest(CSR[1])API 可以方便的生成客户认证证书。这个机制可以让klusterlet在第一次启动访问hub集群时使用一个权限很小的秘钥来创建 CSR。当 CSR 返回了生成的证书后,klusterlet就可以用后续生成的带有更大访问权限的证书来访问hub集群。在使用 csr 的过程中,klusterlet的私钥不会在网络中传输而是一直保存在被管理集群中;只有 CSR 的公钥和初始阶段需要的小权限秘钥(bootstrap secret)会在不同集群间传输。这就最大程度的保证秘钥不会在传输过程中被泄露出去。

双向握手协议和动态klusterletID

那么如果初始阶段的 bootstrap secret 被泄露了会怎么样呢?这就牵涉到 OCM 中的双向握手协议。当被管理集群中的klusterlet使用 bootstrap secret 发起了第一次请求的时候,hub 集群不会立刻为这个请求创建客户证书和对应的访问权限。这个请求将处在Pending状态,直到 hub 集群拥有特定管理权限的管理员同意了klusterlet的接入请求后,客户证书和特定权限才会被创建出来。这个请求中包含了klusterlet启动阶段生成的动态 ID,管理员需要确保这个 ID 和被管理集群上klusterlet的 ID 一致才能同意klusterlet的接入。这也就确保了如果 bootstrap secret 被不慎泄露后,CSR 也不会被管理员轻易的接受。

klusterlet使用的客户证书是有过期时间的,klusterlet需要在证书过期之前使用现有的客户证书发起新的CSR请求来获取新的客户证书。hub集群会检验更新证书的CSR请求是否合法并自动签署新的客户证书。需要注意的是由于klusterlet使用了动态 ID 的机制,只有klusterlet本身发起的CSR请求才会被自动签署。如果klusterlet在集群中被卸载然后重新部署后,它必须重新使用 bootstrap secret 流程来获取客户证书。

认证和授权的分离

在klusterlet的CSR请求被接受后,它获得了被hub集群认证通过的客户证书,但是它在这个时候还没有对hub集群上特定资源访问的权限。ocm中还有一个单独的授权流程。每个被管理集群的klusterlet时候有权限访问hub集群的特定资源是被对应ManagedClusterAPI 上的hubAcceptsClient域来控制的。只有当这个域被置位true时,hub集群的控制器才会为对应klusterlet赋予权限。而设置这个域需要用户在hub集群中对managedcluster/accept具有update权限才可以。如下面的clusterrole的例子表示用户只能对cluster1这个ManagedCluster上的klusterlet赋予权限。

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: open-cluster-management:hub
rules:
- apiGroups: ["register.open-cluster-management.io"]
  resources: ["managedclusters/accept"]
  verbs: ["update"]
  resourceNames: ["cluster1"]

将认证和授权的流程分开的原因是通常情况下hub集群具有approve CSR权限的用户和"允许 klusterlet 接入 hub"集群的用户并不完全一致。以上机制就可以保证即使用户拥有approve CSR的权限也不能给任意的klusterlet赋予接入hub集群的权限。

实现细节

所有认证授权和秘钥管理的代码实现都在registration[2]组件中。大概的流程 如下图所示

图片

当registration-agent在被管理集群中启动后,会首先在自己的namespace里查找是否有hub-kubeconfig的秘钥并验证这个秘钥是否合法。如果不存在或者不合法,registration-agent就进入了 bootstrap 流程,它会首先产生一个动态的agent ID, 然后使用一个更小权限的bootstrap-kubeconfig来创建 client 和 informer,接下来启动一个ClientCertForHubController的 goroutine。这个 controller 会在 hub 集群创建 CSR,等待 CSR 中签署的证书并最终把证书和私钥做为名为hub-kubeconfig的秘钥持久化在被管理集群中。agent 接着持续监控hub-kubeconfig这个秘钥是否已经被持久化。当 agent 发现hub-kubeconfig则意味着 agent 已经获取到了可以访问hub集群的客户证书,agent 就会停掉之前的 controller 并退出 bootstrap 流程。接下来 agent 会重新用hub-kubeconfig创建 client 和 informer,并启动一个新的ClientCertForHubController的 goroutine 来定期刷新客户证书。

在 hub 集群中的registration-controller会启动CSRApprovingController用来负责检查klusterlet发起的 CSR 请求是否可以自动签发;以及managedClusterController用来检查对应ManagedCluster上的hubAccepctsClient域是否被设置并在hub集群中创建相应的权限。

参考资料

[1]CSR: https://kubernetes.io/docs/reference/access-authn-authz/certificate-signing-requests/

[2]registration: https://github.com/open-cluster-management-io/registration

作者:邱见

责任编辑:武晓燕 来源: CNCF
相关推荐

2009-07-08 15:10:00

Servlet会话管理

2010-09-26 13:23:13

JVM内存管理机制

2010-12-10 15:40:58

JVM内存管理

2011-06-29 17:20:20

Qt 内存 QOBJECT

2020-08-18 19:15:44

Redis内存管理

2009-09-02 09:23:26

.NET内存管理机制

2013-09-29 15:11:46

Linux运维内存管理

2010-07-23 09:34:48

Python

2022-06-01 16:01:58

MySQL内存管理系统

2021-02-07 09:02:28

内存管理length

2021-09-03 07:27:38

AndroidGlide管理

2009-09-23 17:48:00

Hibernate事务

2016-09-06 22:05:41

HttpCookieWeb

2020-11-08 14:32:01

JavaScript变量内存管理

2016-10-09 14:41:40

Swift开发ARC

2022-02-28 10:25:17

Python参数传递拷贝

2009-09-25 12:59:53

Hibernate事务

2019-01-23 17:08:52

Python内存管理RealPython

2021-12-15 06:58:27

Go多版本管理

2011-08-18 13:28:35

Objective-C内存
点赞
收藏

51CTO技术栈公众号