开发者社区> 店家小二> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

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 的证书认证

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Kubernetes安装之证书验证
前言 昨晚(Apr 9,2017)金山软件的opsnull发布了一个开源项目和我一步步部署kubernetes集群,下文是结合我之前部署kubernetes的过程打造的kubernetes环境和opsnull的文章创建 kubernetes 各组件 TLS 加密通信的证书和秘钥的实践。
1027 0
Kubernetes必备知识: Kubernetes Service
Kubernetes中一个应用服务会有一个或多个实例(Pod),每个实例(Pod)的IP地址由网络插件动态随机分配(Pod重启后IP地址会改变)。为屏蔽这些后端实例的动态变化和对多实例的负载均衡,引入了Service这个资源对象
418 0
Kubernetes必备知识: StatefulSet
StatefulSet是为了解决有状态服务的问题(对应Deployments和ReplicaSets是为无状态服务而设计),其应用场景包括  稳定的持久化存储,即Pod重新调度后还是能访问到相同的持久化数据,基于PVC来实现  稳定的网络标志,即Pod重新调度后其PodName和HostName不变,基于Headless Service(即没有Cluster IP的Service)来实现  有序部署,有序扩展,即Pod是有顺序的
492 0
Kubernetes必备知识: Job
首先 kubernetes 的 Job 是一个管理任务的控制器,它可以创建一个或多个 Pod 来指定 Pod 的数量,并可以监控它是否成功地运行或终止; 我们可以根据 Pod 的状态来给 Job 设置重置的方式及重试的次数; 我们还可以根据依赖关系,保证上一个任务运行完成之后再运行下一个任务; 同时还可以控制任务的并行度,根据并行度来确保 Pod 运行过程中的并行次数和总体完成大小。
287 0
Kubernetes必备知识: kubernetes CSI
csi 是一个标准的容器存储接口,规定了如何实现一个容器的存储接口,CSI 本身的定义是基于 gRPC 的,所以有一套样例库可以使用,这里分析一下 kuberntes 实现 csi 的方式,为了兼容 CSI kubernete 其实搞得挺绕的,目前这个 CSI 还是定制中包括后期的 Snapshot 的接口怎么设计等等还在讨论中。kubernetes CSI 主要基于几个外部组件和内部功能的一些改动。
2011 0
Kubernetes必备知识:PersistentVolume
PersistentVolume(PV)用于为用户和管理员提供如何提供和消费存储的API,PV由管理员在集群中提供的存储。它就像Node一样是集群中的一种资源。PersistentVolume 也是和存储卷一样的一种插件,但其有着自己独立的生命周期。PersistentVolumeClaim (PVC)是用户对存储的请求,类似于Pod消费Node资源,PVC消费PV资源。Pod能够请求特定的资源(CPU和内存),声明请求特定的存储大小和访问模式。PV是一个系统的资源,因此没有所属的命名空间。
684 0
Kubernetes必备知识: Selectors
Label不是唯一的,很多object可能有相同的label。 通过label selector,客户端/用户可以指定一个object集合,通过label selector对object的集合进行操作。
299 0
Kubernetes必备知识: CNI
CNI的全称是 Container Network Interface,即容器网络的 API 接口。 它是 K8s 中标准的一个调用网络实现的接口。Kubelet 通过这个标准的 API 来调用不同的网络插件以实现不同的网络配置方式。实现了这个接口的就是 CNI 插件,它实现了一系列的 CNI API 接口。常见的 CNI 插件包括 Calico、flannel、Terway、Weave Net 以及 Contiv。
1358 0
Kubernetes必备知识: Annotations
Annotations(注解) 是 key/value 形式附加于对象的注解。不同于 Labels 用于标志和选择对象,Annotations 则是用来记录一些附加信息,用来辅助应用部署、安全策略以及调度策略等。比如 deployment 使用 annotations 来记录 rolling update 的状态。
2710 0
Kubernetes必备知识: CronJob
CronJobs提供了在特定的时间或者间隔内处理业务逻辑的方法。一般创建一个Cronjob有两种方式,第一种是定义Java类,由Hybris生成脚本并加入数据库。第二种是直接编写groovy脚本语言并插入数据库,这种应该适合逻辑比较少的时候,比如只有一两句逻辑的时候,一般用得比较少。
746 0
+关注
645
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载