Kubernetes 的证书认证

简介: 今天让我们聊聊 Kubernetes 的公私钥和证书认证。 本文内容会提及如何根据需要对 CA、公私钥进行组织并对集群进行设置。 Kubernetes 的组件中有很多不同的地方可以放置证书之类的东西。

今天让我们聊聊 Kubernetes 的公私钥和证书认证

本文内容会提及如何根据需要对 CA、公私钥进行组织并对集群进行设置。


Kubernetes 的组件中有很多不同的地方可以放置证书之类的东西。在进行集群安装的时候,我感觉有一百多亿个不同的命令参数是用来设置证书、密钥的,真不明白是怎么弄到一起工作的。

当然了,没有一百亿那么多的参数,不过的确很多的。比如 API Server 的参数吧,有大概 16 个参数是跟这些东西有关的(下面是节选):

--cert-dir string The directory where the TLS certs are located. If --tls-cert-file and --tls-private-key-file are provided, this flag will be ignored. (default "/var/run/kubernetes") --client-ca-file string If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate. --etcd-certfile string SSL certification file used to secure etcd communication. --etcd-keyfile string SSL key file used to secure etcd communication. --kubelet-certificate-authority string Path to a cert file for the certificate authority. --kubelet-client-certificate string Path to a client cert file for TLS. --kubelet-client-key string Path to a client key file for TLS. --proxy-client-cert-file string Client certificate used to prove the identity of the aggregator or kube-apiserver when it must call out during a request. This includes proxying requests to a user api-server and calling out to webhook admission plugins. It is expected that this cert includes a signature from the CA in the --requestheader-client-ca-file flag. That CA is published in the 'extension-apiserver-authentication' configmap in the kube-system namespace. Components recieving calls from kube-aggregator should use that CA to perform their half of the mutual TLS verification. --proxy-client-key-file string Private key for the client certificate used to prove the identity of the aggregator or kube-apiserver when it must call out during a request. This includes proxying requests to a user api-server and calling out to webhook admission plugins. --requestheader-allowed-names stringSlice List of client certificate common names to allow to provide usernames in headers specified by --requestheader-username-headers. If empty, any client certificate validated by the authorities in --requestheader-client-ca-file is allowed. --requestheader-client-ca-file string Root certificate bundle to use to verify client certificates on incoming requests before trusting usernames in headers specified by --requestheader-username-headers
--service-account-key-file stringArray File containing PEM-encoded x509 RSA or ECDSA private or public keys, used to verify ServiceAccount tokens. If unspecified, --tls-private-key-file is used. The specified file can contain multiple keys, and the flag can be specified multiple times with different files. --ssh-keyfile string If non-empty, use secure SSH proxy to the nodes, using this user keyfile
--tls-ca-file string If set, this certificate authority will used for secure access from Admission Controllers. This must be a valid PEM-encoded CA bundle. Alternatively, the certificate authority can be appended to the certificate provided by --tls-cert-file. --tls-cert-file string File containing the default x509 Certificate for HTTPS. (CA cert, if any, concatenated after server cert). If HTTPS serving is enabled, and --tls-cert-file and --tls-private-key-file are not provided, a self-signed certificate and key are generated for the public address and saved to /var/run/kubernetes. --tls-private-key-file string File containing the default x509 private key matching --tls-cert-file. --tls-sni-cert-key namedCertKey A pair of x509 certificate and private key file paths, optionally suffixed with a list of domain patterns which are fully qualified domain names, possibly with prefixed wildcard segments. If no domain patterns are provided, the names of the certificate are extracted. Non-wildcard matches trump over wildcard matches, explicit domain patterns trump over extracted names. For multiple key/certificate pairs, use the --tls-sni-cert-key multiple times. Examples: "example.crt,example.key" or "foo.crt,foo.key:*.foo.com,foo.com". (default [])

接下来是 Controller Manager 的:

--cluster-signing-cert-file string Filename containing a PEM-encoded X509 CA certificate used to issue cluster-scoped certificates (default "/etc/kubernetes/ca/ca.pem") --cluster-signing-key-file string Filename containing a PEM-encoded RSA or ECDSA private key used to sign cluster-scoped certificates (default "/etc/kubernetes/ca/ca.key") --root-ca-file string If set, this root certificate authority will be included in service account's token secret. This must be a valid PEM-encoded CA bundle.
--service-account-private-key-file string Filename containing a PEM-encoded private RSA or ECDSA key used to sign service account tokens.

再来个 Kubelet:

--client-ca-file string If set, any request presenting a client certificate signed by one of the authorities in the client-ca-file is authenticated with an identity corresponding to the CommonName of the client certificate. --tls-cert-file string File containing x509 Certificate used for serving HTTPS (with intermediate certs, if any, concatenated after server cert). If --tls-cert-file and --tls-private-key-file are not provided, a self-signed certificate and key are generated for the public address and saved to the directory passed to --cert-dir. --tls-private-key-file string File containing x509 private key matching --tls-cert-file.

本文假设读者:

  • 对 TLS 认证和 CA 有一些了解。
  • 能把这些东西跑起来,但是不知道为啥。

下面还会说明在 Kubernetes 中的不同 CA,以及不同 CA 的协同工作。

另外有些我在工作中学到的一些:

  • 不要用 CA 来检查 Service Account Key。Service Account key 有点古怪,他跟其他的 Key 不是一同处理的。
  • 如果 kubernetes 建立用户和组的方式不适合需求,可以(应该)设置一个认证代理。
  • API Server 如果设置了太多 CA,会显得有点乱。

这个题目有点复杂,如果阅读中发现任何问题请通知我。

PKI 和 Kubernetes

在阅读 Kubernetes 材料的过程中,我注意到一个词出现了很多次:“PKI”,我不很清楚这是个什么。

如果你有个在运行的 Kubernetes 集群,其中可能有几百上千个公钥私钥(客户端认证、服务认证等等)。

如果这几百个 Key 是独立的互不相关的,就会让安全性堕入泥潭。因此我们需要个 CA,CA 的职责就是签发证书,并告诉用户“这个公钥是我发的,靠谱”。

PKI 就是组织 Key 的方式 —— 什么 Key 是用什么 CA 签发的。

例如:

  • 可以为每个集群准备一个 CA,集群所有的私钥都从这个 CA 签发(Kubernetes 文档中多数是这个情况)。
  • 可以准备一个全局 CA,所有的私钥都从此而来。
  • 单独给服务使用一个 CA,对外可见;内部另外使用一个 CA 作为专门用途。
  • 还有其他。

我不是安全专家,所以不想说如何管理私钥和 CA 才更好。但是不管你用的什么样的模型,其实都可以跟 Kubernetes 协调工作。

下面根据需求来确认管理 PKI 的方式,以及如何在 Kubernetes 中实现。

Kubernetes 集群需要一个单根结构的 CA 么?不

如果你读了不少 Kubernetes 集群的安装文档,会注意到总有一步:设置一个 CA。Kelsey Hightower 的大作 “Kubernetes the hard way” 中是第二步,“在集群中信任 TLS ”中说:

每个 Kubernetes 集群都有一个集群根 CA。CA 一般用于集群中的组件验证 API Server 的合法性,在 API Serverl 来说,就是验证 kubelet 客户端的证书,诸如此类的。

基本上来说:

  1. 设置一个 CA
  2. 用这个 CA 生成不同的证书,给 Kubernetes 集群的不同组件使用。

如果不想为每个集群设置一个新的 CA 呢?可能有很多理由。但是我担心,最终还是需要提供一个根 CA。

这好像说上面的话是假的,其实可以使用很多不同的 CA 签发的证书来管理 Kubernetes。总的说来,还是要结合具体场景的需求。

接下来我们来探讨一下证书相关的参数,以及互相之间的关系。每一节都会包含一个可以定义的 CA。每一个都是独立的,并不需要一致。不过在实际操作中,可能你并不想管理 6 个不同的 CA。

API Server 的 TLS 证书(以及 CA)

–tls-cert-file string

包含缺省的 x509 https 认证的文件(可以包含 CA 证书),如果启用了 HTTPS 服务,又没有指定–tls-cert-file和–tls-private-key-file参数,就会在 /var/run/kubernetes生成一个自签名证书以及 Key

–tls-private-key-file

–tls-cert-file证书的 x509 私钥。

如果用 TLS 连接 API Server,就需要这两个参数来选择 API Server 使用的证书。

证书设置了之后,还需要给各个组件的 kubeconfig 文件进行相关设置。

current-context: my-context
apiVersion: v1
clusters: - cluster:
 certificate-authority: /path/to/my/ca.crt # 签发 API Server 证书的 CA 证书
 server: https://horse.org:4443
 name: my-cluster
kind: Config
users: - name: green-user
 user:
 client-certificate: path/to/my/client/cert # 后面会讲
 client-key: path/to/my/client/key # 后面会讲

有个让我惊奇的事情就是——这个宇宙里面的几乎所有其他使用 TLS 的系统都会去 /etc/ssl 查找一个本机信任的 CA 列表,但是 Kubernetes 很傲娇,他不会去找,必须显式的进行告知签发 CA。

可以使用参数–kubeconfig /path/to/kubeconfig.yaml将配置文件分配给各个组件进行使用。

这样我们完成了第一个 CA 的设置:签发 API Server 证书的 CA。这个 CA 跟其他的 CA 可以不一致。

API Server 客户证书认证

–client-ca-file

如果设置了这一参数,所有的请求都应该使用该文件中所包含的 CA 签发的证书进行签署,证书中的 Common Name 会作为用户名进行使用。

Kubernetes 组件获得 API Server 认证的方法之一就是使用这一参数。

所有客户端证书都应该由这一 CA 签发(不需要和 API Server 的 CA 一致)。

当使用 kubeconfig 文件的时候,可以按照如下方式设置使用证书:

kind: Config
users: - name: green-user
 user:
 client-certificate: path/to/my/client/cert
 client-key: path/to/my/client/key

Kubernetes 做了很多用户证书方面的假设(用户名就是 Common Name,Group 就是 Organization)。如果这些假设不符合需求,那么就应该停用客户端证书认证,改用认证代理。

请求 Header 的证书认证(或者:认证代理)

API server 参数

–requestheader-allowed-names stringSlice

–requestheader-username-headers 中指定的 Header 中包含用户名,这一参数的列表确定了允许有效的 Common Name,如果这一参数的列表为空,则所有通过–requestheader-client-ca-file校验的都允许通过。

–requestheader-client-ca-file string

针对收到的请求,在信任–requestheader-username-headers中指定的 Header 里面包含的用户名之前,首先会用这一 CA 对客户证书进行验证。

另外一个设置 Kubernetes 认证的方式就是认证代理。如果你对如何向 API Server 发送用户名和组有很多想法,可以设置一个代理,这一代理会使用 HTTP Header 将用户名和组发送给 API Server。

文档中简单的解释了一下工作方式。代理使用一个客户端证书表明身份,–requestheader-client-ca-file告知 API Server,该证书所属的 CA。

我觉得——API Server 有太多认证方式了(客户端认证、认证代理、Token 等等),让人很迷惑。建议用户尽量少的同时使用认证方式,便于管理、使用和除错。

service account 私钥(不是 CA 签发的)

API Server 参数

–service-account-key-file

PEM 编码的 X509 RSA 或者 ECDSA 的私钥或者公钥,用于检验 ServiceAccount 的 token。如果没指定的话,会使用–tls-private-key-file替代。文件中可以包含多个 Key,这一参数可以重复指定多个文件。

Controller Manager 参数

–service-account-private-key-file

PEM 编码的 X509 RSA 或者 ECDSA Key,用于签署 Service Account Token。

Controller Manager 使用私钥签署 Service Account Token。跟 Kubernetes 中使用的其他私钥不同的是,这个私钥是不支持同一 CA 验证的,因此上,需要给每个 Controller Manager 指定一致的私钥文件。

这个 Key 也不需要什么 CA 来做签署,生成很容易:

openssl genrsa -out private.key 4096

然后分发给每个 Controller Manager 和 API Server 就可以了。

使用和–tls-private-key-file一致的文件是可以工作的——只要你给每个 API Server 用的都是同一个 TLS Key(一般都这么做的吧?)。(这里我假设你运行的一个有高可用支持的,多个 API Server 和多个 Controller Manager同时运行的集群)

如果两个不同的 Controller Manager 用了两个不同的 Key,那就杯具了,他们会用各自的 Key 来生成 Token,最终导致无效判定。我觉得这点不太合理,Kubernetes 应该和其他方面一样,使用 CA 进行管理。通过对源码的月度,我觉得原因可能是 jwt-go 不支持 CA。

Kubelet 证书认证

总算到了 Kubelet 环节了,下面是 API Server 和 Kubelet 相关的内容:

API Server 参数

–kubelet-certificate-authority CA 证书的路径。

–kubelet-client-certificate TLS 证书文件

–kubelet-client-key TLS Key 文件

Kubelet 参数

–client-ca-file

请求中的客户端证书如果是由文件中的 CA 签署的,那么他的 Common Name 就会被用作 ID 进行认证。

–tls-cert-file

用来提供 HTTPS 服务的 x509 证书(其中也可包含中间人证书)。如果不提供–tls-cert-file和–tls-private-key-file,就会为主机地址生成一个自签名的证书和对应的 Key,并保存到–cert-dir目录里。

–tls-private-key-file

–tls-cert-file 对应的 Key

校验 kubelet 的请求是有用的,因为 Kubelet 的职责就是在主机上执行代码。

这里实际上有两个 CA,这里不准备深入描述,情况和 API Server 是一样的,Kubelet 用 TLS 来进行认证,也支持客户证书认证。

另外还要告知 API Server,用什么 CA 检查 Kubelet 的 TLS,另外用什么证书来跟 Kubelet 通信。

再说一次,这两个 CA 是可以不同的。

太多 CA 了

现在我们找到了五个不同的 CA,他们各自独立的为 Kubernetes 提供支持。

其实还有一些没讨论到的证书,不过希望本文能给你阅读官方文档提供一点帮助。

当然了,每个 CA 独立设置可能不是必要的,我是希望帮助读者理解这些东西如何设置使之符合各种需求,而不是简单的面向文档照本宣科。

本文转自中文社区-Kubernetes 的证书认证

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
相关文章
|
15天前
|
Kubernetes 网络协议 网络安全
提升你的云技能:深入了解CKA认证之k8s升级秘籍!
提升你的云技能:深入了解CKA认证之k8s升级秘籍!
18 0
|
18天前
|
JSON Kubernetes Linux
Linux环境签发CA证书和K8s需要的证书
Linux环境签发CA证书和K8s需要的证书
22 0
|
6月前
|
Kubernetes 负载均衡 网络协议
【Kubernetes中Gateway和ServiceEntry使用、SDS认证授权等使用】
【Kubernetes中Gateway和ServiceEntry使用、SDS认证授权等使用】
|
4月前
|
Kubernetes Shell Linux
linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
linux|shell脚本|有趣的知识---格式化输出日志和脚本调试方法以及kubernetes集群核心服务重启和集群证书备份脚本
53 0
|
4月前
|
Kubernetes Cloud Native Go
云原生|kubernetes|kubeadm部署的集群的100年证书
云原生|kubernetes|kubeadm部署的集群的100年证书
110 0
|
Kubernetes 容器
kubeadm 部署的 k8s 增加 ip 并重新生成证书
kubeadm 部署的 k8s 增加 ip 并重新生成证书
929 0
|
1月前
|
Kubernetes 容器
934.【kubernetes】kubeadm版本更新证书
934.【kubernetes】kubeadm版本更新证书
46 2
|
4月前
|
Kubernetes Cloud Native 安全
云原生|kubernetes|kubernetes集群升级+证书更新(Ubuntu-18.04+kubeadm)
云原生|kubernetes|kubernetes集群升级+证书更新(Ubuntu-18.04+kubeadm)
103 0
|
4月前
|
Kubernetes API 网络架构
k8s学习-CKS真题-启用API Server认证,禁止匿名访问
k8s学习-CKS真题-启用API Server认证,禁止匿名访问
61 0
|
4月前
|
Kubernetes Linux 调度
K8S证书过期解决办法之替换证书
K8S证书过期解决办法之替换证书
274 0

推荐镜像

更多