Kubernetes:证书,令牌,身份验证和服务帐户
主要是为了个人/学习体验,我创建了很多Kubernetes集群,例如我的Raspberry Pi机架上的集群。我还在Hetzner Cloud的超廉价云服务器上为生产和临时环境创建了两个集群。幸运的是,没有那些严肃的业务环境。
免责声明:我不是Kubernetes专家,也不是安全专家,因此请确保在您依赖它们之前,您可以在此帖子中找到您所获得的信息。我只想公布我在这次旅行中所获得的经验和见解 – 谢谢
为什么那么幸运?
因为我不小心泄漏了我的管理员访问登台集群的证书。我试图使用CircleCI为开源项目设置CI / CD管道。当我逐一测试这些步骤时,我抛弃了内容 ${HOME} /。KUBE /配置
已经从BASE64编码的环境变量创建,如本博客文章中所述。这是致命的,因为a)开源项目的工作日志是公开可见的,b)工作和他们的日志不能手动删除,我不得不伸出援手。哎哟!
那么让我们深入了解这里发生的事情。
创建集群
首先,我使用手动创建了集群 kubeadm
,遵循官方文档。这样做,我创建了一个启用了RBAC的群集和一个 KUBE-配置
已为我创建,其中包括由证书标识的用户。
访问群集
后 kubeadm
成功创建了集群,它会指示您如何访问集群:
“您的Kubernetes控制平面已成功初始化要开始使用您的群集,您需要以普通用户身份运行以下命令:” MKDIR -p $HOME/.kube sudo cp -一世 /etc/kubernetes/admin.conf $HOME/.kube/config sudo chown $(ID -u):$(ID -G) $HOME/.kube/config
该 admin.conf中
kubeadm创建的包括由证书标识的用户:
- 名称: kubernetes管理员 用户: 客户端证书数据: 客户关键数据:
遵循这些说明是使用此方法访问此群集的唯一方法 kubectl
截至目前,所以你应该继续这样做。复制后 admin.conf中
, 你有 集群管理
访问。你是 根
,所以说。
那个怎么样?
什么 kubeadm
确实是它创建了一个新的CA(证书颁发机构)根证书,它是您的群集的主证书。它看起来像这样:
证书:数据:版本:3(0x2)序列号:0(0x0)签名算法:sha256WithRSAEncryption发行人:CN = kubernetes有效期不是之前:5月19日11:11:04 2019年GMT未经过:5月16日11:11:04 2029 GMT主题:CN = kubernetes主题公钥信息:公钥算法:rsaEncryption公钥:(2048位)模数: 指数:65537(0x10001)X509v3扩展:X509v3密钥用法:关键数字签名,密钥加密货币,证书签名X509v3基本约束:关键CA:TRUE签名算法:sha256WithRSAEncryption
所以……除了它是CA的信息之外,它实际上并不包含太多,它的CN(=公共名称)是Kubernetes。这是因为此证书仅作为群集上用于不同目的的其他证书的根。你可以看看 的/ etc / kubernetes / PKI
要查看集群中使用的一些证书,并且已经过CA签名:
丹尼尔@ KUBE-框:〜# LS 的/ etc / kubernetes / PKI / -1 apiserver.crt apiserver-etcd-client.crt apiserver-etcd-client.key apiserver.key apiserver-kubelet-client.crt apiserver -kubelet-client.key ca.crt ca.key etcd front-proxy-ca.crt front- proxy-ca.key front-proxy-client.crt front-proxy-client.key sa.key sa.pub
可以允许访问使用CA信任的证书对自身进行身份验证的客户端。传递此功能即可启用此功能 ca.crt
至 KUBE-控制器经理
在里面 --client-CA-文件
参数。这是文档必须说的:
--client-ca-file字符串如果设置,则表示由client-ca文件中的某个权限签名的客户端证书的任何请求都将使用与客户端证书的CommonName对应的标识进行身份验证。
回到你的 KUBE-配置
:您的BASE64中包含的证书 admin.conf中
由那个确切的CA签署。这就是群集信任的原因。我们来看看证书:
grep的 '客户证书数据:' ${家}/.kube/config | SED 's /.* client-certificate-data://' | BASE64 -d | openssl x509 - 在 - - 文本 证书:数据:版本:3 (0X2) 序列号:3459994011761527671 (0x30045e38cc064b77) 签名算法:sha256与RSAEncryption Issuer:CN = kubernetes有效期不在:5月12日10:54:39 2019 GMT未及之后:5月11日10:54:42 GMT主题:O = system:masters,CN = kubernetes-admin主题公钥信息:公钥算法:rsaEncryption公钥: (2048位) 模数: 指数:65537 (0x10001) X509v3扩展:X509v3密钥用法:关键数字签名,密钥加密货币X509v3扩展密钥用法:TLS Web客户端身份验证签名算法:sha256WithRSAEncryption
这个证书告诉我们(和集群)是什么?
a)它由我们发布并信任 kubernetes
簇
b)它确定了组织(Ø
) 系统:大师
,被kubernetes解释为一组
c)它标识了通用名称(CN
) kubernetes管理员
,被kubernetes解释为用户
换句话说:此证书以用户身份登录 kubernetes管理员
与小组 系统:大师
。这就是为什么你不需要提供组名的原因 KUBE-配置
,以及为什么你可以随意改变用户的名字 KUBE-配置
,这不会改变正在登录的实际用户。
权限在哪里定义?
在启用RBAC的群中心化,权限定义于 角色
(每个命名空间)或 ClusterRoles
(对于所有名称空间)。然后使用这些权限授予对象 RoleBindings
和 ClusterRoleBindings
。所以你需要寻找的是 RoleBindings
和 ClusterRoleBindings
授予该组权限 系统:大师
或者用户 kubernetes管理员
。您可以通过查看输出来完成此操作
kubectl -A = true获取rolebindings && kubectl -A = true获取clusterrolebindings
默认设置 kubeadm
为我创造了一个针对该搜索的命中, ClusterRoleBinding
命名 集群管理
,授予权限 ClusterRole
同名。这是定义:
类: ClusterRole 元数据: 名称: 集群管理 规则: - apiGroups: - “*” 资源: - “*” 动词: - “*” - nonResourceURLs: - “*” 动词: - “*” --- apiVersion: rbac.authorization.k8s.io/v1 类: ClusterRoleBinding 元数据: 名称: 集群管理 roleRef: apiGroup: rbac.authorization.k8s.io 类: ClusterRole 名称: 集群管理 主题: - apiGroup: rbac.authorization.k8s.io 类: 组 名称: 系统:大师
因此,我们有它群组 系统:大师
,证书授权的,使用所有动词授予对所有资源的'*'权限,从而获得完全访问权限。
未经验证的假设:我认为在这种情况下,用户和组仅在证书中定义,新用户可以 创建
通过发布新的证书,将CommonName设置为所需的用户名,并将组织设置为所需的组。然后,可以使用此用户名和组,而无需进一步使用 ClusterRoleBindings
和 RoleBindings
。但是,我没有花时间来验证这一点,这可以通过使用发布新证书来实现 OpenSSL的
,使用群集的CA签名。如果有人可以在评论中确认或揭穿这个假设,那就太棒了
谜
所以我做到了这一点,发现了如何识别用户和组以及如何授予该用户和组权限。我的猜测是当我删除时 ClusterRoleBinding
,或者更确切地说删除该组 系统:大师
从中,证书不再具有对集群的访问权限。如果我这样做了,并且它有预期的结果,我将失去对群集的所有访问权限,并且会成功地将我退出。所以我先加了一个 serviceaccount
并创建了一个 KUBE-配置
使用令牌登录的 serviceaccount
并验证访问是否有效。我们稍后会看到如何做到这一点。然后,在将安全网设置到位后,我移除了 系统:大师
主题来自 ClusterRoleBinding
。令我惊讶的是,这并没有锁定用户。我仍然可以使用旧的完全访问集群 KUBE-配置
…也许有人可以在评论中解释这种行为?
备选方案1:更换CA.
使泄露的证书无效的一种确定的方法是替换群中心化的CA.但是,这需要重新启动群集。它需要重新发布我们上面看到的所有证书,也许还需要更多。我认为完全搞定所有事情的可能性并且在旅行中浪费了多个小时,大约99%,所以我放弃了计划。 🙂
备选方案2:重建整个集群
幸运的是,它是一个升级群集,所以我有充足的自由。在开始我的调查之前,我关闭了所有节点。然后,在没有找到合适的解决方案只使泄漏的证书无用之后,我使用了整个集群
kubeadm重置 R M -rf 在/ etc / kubernetes R M -rf 在/ var / lib中/ kubelet
并用kubeadm从头开始重新创建。 (顺便说一下,这太棒了)
然后我继续进行了几十次提交,阅读“不再打印kube-config的内容”,“让CI / CD工作”,“也许现在有效”,“呃什么?”,“那就得做”工作','**ckCI / CD',…… 🙂
经验教训:使用带有令牌的服务帐户
(或者其他身份验证方法,比如OpenID,正如这个很棒的帖子所推荐的那样。)
所以我吸取的教训是做我在大型托管kubernetes提供商处看到的内容:使用服务帐户及其访问令牌进行授权。在这里,我将展示如何设置使用令牌而不是证书的超级用户:
kubectl -n kube-system创建serviceaccount admin
要授予超级用户权限,最简单的方法是创建新的权限 ClusterRoleBinding
将此服务帐户绑定到 集群管理
ClusterRole
:
kubectl create clusterrolebinding add-on-cluster-admin --clusterrole=集群管理 --serviceaccount=KUBE-系统:管理
使用您的新服务帐户
您的管理员用户现已准备就绪并已配备。现在我们需要使用此用户登录。我假设你有 admin.conf中
在 ${HOME} /。KUBE / conf目录
。我们现在想要添加由其标记标识的新用户,并添加使用该用户的新上下文:
TOKENNAME=`kubectl -n kube-system获取serviceaccount / admin -o jsonpath='{.secrets(0)。名称}'` TOKEN=`kubectl -n kube系统变得秘密 $TOKENNAME -o jsonpath='{.data.token}' | BASE64 -d` kubectl config set-credentials admin --token=$令牌 kubectl config set-context admin @ kubernetes - 簇 kubernetes - 用户 管理
现在继续尝试新的,闪亮的服务帐户:
kubectl config use-context admin @ kubernetes kubectl -n kube-system得到所有
如果进展顺利,您应该继续删除基于证书的用户和相应的上下文:
kubectl配置 未设置 users.kubernetes-admin kubectl config delete-context kubernetes-admin @ kubernetes
好极了现在我们有一个 KUBE-conf的
仅包含基于令牌的访问权限。这很好,因为如果此配置可能被泄露或发布,则很容易撤销该令牌。
如何使泄露的令牌无效
这很简单只需删除与用户令牌对应的秘密即可。我们已经看到了如何找出哪个是正确的秘密:
kubectl -n kube-system获取serviceaccount / admin -o YAML
您将在“secrets”数组中看到一个字段“name”。这是保存此服务帐户令牌的机密名称。现在继续简单地删除它:
kubectl -n kube-system删除秘密/ token-admin-xyz123
然后等待几秒钟,然后尝试访问您的群集:
dainel @ kube-box:〜#kubectl -n kube-system获取所有错误:您必须登录 在 到服务器 (擅自)
Wohoo
但是你如何重新获得访问权限?好吧,如果你在你的主节点上,只需复制 admin.conf中
回到你的 ${HOME} /。KUBE / conf目录
并重复“使用您的新服务帐户”中的步骤。 Kubernetes现在已经创建并分配了一个新令牌。
我希望这有帮助,我很乐意在评论中听到反馈,勘误等等
另外,请务必阅读Peter Benjamin撰写的非常易于理解和精彩的帖子“Kubernetes Security Best-Practices”。
非常感谢Andreas Antonsson,vaizki和Alan J Castonguay,他们帮助我在官方的Kubernetes Slack频道上更好地了解正在发生的事情。