千家信息网

Kubernetes 之 二进制安装(二) 证书详解

发表于:2025-12-02 作者:千家信息网编辑
千家信息网最后更新 2025年12月02日,前言在进行二进制搭建K8S集群前,我们需要梳理通最磨人的一个点,就是各种各样的证书机制。这一步是在安装配置kubernetes的所有步骤中最容易出错也是最难排查问题的一步,而这却刚好是第一步,万事开头
千家信息网最后更新 2025年12月02日Kubernetes 之 二进制安装(二) 证书详解

前言

在进行二进制搭建K8S集群前,我们需要梳理通最磨人的一个点,就是各种各样的证书机制。这一步是在安装配置kubernetes的所有步骤中最容易出错也是最难排查问题的一步,而这却刚好是第一步,万事开头难,不要因为这点困难就望而却步。

一共有多少证书?

官方文档参考:https://kubernetes.io/docs/setup/certificates/

先从Etcd算起:

1、Etcd对外提供服务,要有一套etcd server证书

2、Etcd各节点之间进行通信,要有一套etcd peer证书

3、Kube-APIserver访问Etcd,要有一套etcd client证书

再算kubernetes:

4、Kube-APIserver对外提供服务,要有一套kube-apiserver server证书

5、kube-scheduler、kube-controller-manager、kube-proxy、kubelet和其他可能用到的组件,需要访问kube-APIserver,要有一套kube-APIserver client证书

6、kube-controller-manager要生成服务的service account,要有一对用来签署service account的证书(CA证书)

7、kubelet对外提供服务,要有一套kubelet server证书

8、kube-APIserver需要访问kubelet,要有一套kubelet client证书

加起来共8套,但是这里的"套"的含义我们需要理解。

同一个套内的证书必须是用同一个CA签署的签署不同套里的证书的CA可以相同,也可以不同。例如,所有etcd server证书需要是同一个CA签署的,所有的etcd peer证书也需要是同一个CA签署的,而一个etcd server证书和一个etcd peer证书,完全可以是两个CA机构签署的,彼此没有任何关系。这算两套证书。

为什么同一个"套"内的证书必须是同一个CA签署的

原因在验证这些证书的一端。因为在要验证这些证书的一端,通常只能指定一个Root CA。这样一来,被验证的证书自然都需要是被这同一个Root CA对应的私钥签署,不然不能通过认证。

其实实际上,使用一套证书(都使用一套CA来签署)一样可以搭建出K8S,一样可以上生产,但是理清这些证书的关系,在遇到因为证书错误,请求被拒绝的现象的时候,不至于无从下手,而且如果没有搞清证书之间的关系,在维护或者解决问题的时候,贸然更换了证书,弄不好会把整个系统搞瘫。

TLS bootstrapping 简化kubelet证书制作

Kubernetes1.4版本引入了一组签署证书用的API。这组API的引入,使我们可以不用提前准备kubelet用到的证书。

每个kubelet用到的证书都是独一无二的,因为它要绑定各自的IP地址,于是需要给每个kubelet单独制作证书,如果业务量很大的情况下,node节点会很多,这样一来kubelet的数量也随之增加,而且还会经常变动(增减Node)kubelet的证书制作就成为一件很麻烦的事情。使用TLS bootstrapping就可以省事儿很多。

工作原理:Kubelet第一次启动的时候,先用同一个bootstrap token作为凭证。这个token已经被提前设置为隶属于用户组system:bootstrappers,并且这个用户组的权限也被限定为只能用来申请证书。 用这个bootstrap token通过认证后,kubelet申请到属于自己的两套证书(kubelet server、kube-apiserver client for kubelet),申请成功后,再用属于自己的证书做认证,从而拥有了kubelet应有的权限。这样一来,就去掉了手动为每个kubelet准备证书的过程,并且kubelet的证书还可以自动轮替更新

官方文档参考:https://kubernetes.io/docs/tasks/tls/certificate-rotation/

kubelet证书为何不同

这样做是一个为了审计,另一个为了安全。 每个kubelet既是服务端(kube-apiserver需要访问kubelet),也是客户端(kubelet需要访问kube-apiserver),所以要有服务端和客户端两组证书。

服务端证书需要与服务器地址绑定,每个kubelet的地址都不相同,即使绑定域名也是绑定不同的域名,故服务端地址不同

客户端证书也不应相同,每个kubelet的认证证书与所在机器的IP绑定后,可以防止一个kubelet的认证证书泄露以后,使从另外的机器上伪造的请求通过验证。

安全方面,如果每个node上保留了用于签署证书的bootstrap token,那么bootstrap token泄漏以后,是不是可以随意签署证书了?安全隐患非常大。所以,kubelet启动成功以后,本地的bootstrap token需要被删除。

正式制作证书

虽然可以用多套证书,但是维护多套CA实在过于繁杂,这里还是用一个CA签署所有证书。

需要准备的证书:

  • admin-key.pem

  • admin.pem

  • ca-key.pem

  • ca.pem

  • kube-proxy-key.pem

  • kube-proxy.pem

  • kubernetes-key.pem

  • kubernetes.pem

使用证书的组件如下:

  • etcd:使用 ca.pem、kubernetes-key.pem、kubernetes.pem

  • kube-apiserver:使用 ca.pem、kubernetes-key.pem、kubernetes.pem

  • kubelet:使用 ca.pem

  • kube-proxy:使用 ca.pem、kube-proxy-key.pem、kube-proxy.pem

  • kubectl:使用 ca.pem、admin-key.pem、admin.pem

  • kube-controller-manager:使用 ca-key.pem、ca.pem

我们使用CFSSL来制作证书,它是cloudflare开发的一个开源的PKI工具,是一个完备的CA服务系统,可以签署、撤销证书等,覆盖了一个证书的整个生命周期,后面只用到了它的命令行工具。

注:一般情况下,K8S中证书只需要创建一次,以后在向集群中添加新节点时只要将/etc/kubernetes/ssl目录下的证书拷贝到新节点上即可。

下载安装cfssl命令行工具

[root@dong bin]# mkdir -p /usr/local/bin/cfssl[root@dong bin]# wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 [root@dong bin]# wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 [root@dong bin]# wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 [root@dong bin]# chmod +x cfssl*[root@dong bin]# mv cfssl_linux-amd64 /usr/local/bin/cfssl[root@dong bin]# mv cfssljson_linux-amd64 /usr/local/bin/cfssljson[root@dong bin]# mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo[root@dong bin]# export PATH=/usr/local/bin:$PATH

创建CA证书

创建存放证书目录

[root@dong bin]# mkdir -p /opt/kubernetes/ssl/[root@dong bin]# cd /opt/kubernetes/ssl/

创建证书配置文件

[root@dong ssl]# vim ca-config.json{  "signing": {    "default": {      "expiry": "87600h"    },    "profiles": {      "kubernetes": {        "usages": [            "signing",            "key encipherment",            "server auth",            "client auth"        ],        "expiry": "87600h"      }    }  }}

字段说明:

ca-config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;

signing:表示该证书可以签名其他证书;生成的ca.pem证书中 CA=TRUE;

server auth:表示client可以用该 CA 对server提供的证书进行验证;

client auth:表示server可以用该CA对client提供的证书进行验证

expiry:过期时间

创建CA证书签名请求文件

[root@dong ssl]# vim ca-csr.json{  "CN": "kubernetes",  "key": {    "algo": "rsa",    "size": 2048  },  "names": [    {      "C": "CN",      "ST": "BeiJing",      "L": "BeiJing",      "O": "k8s",      "OU": "System"    }  ],    "ca": {       "expiry": "87600h"    }}

字段说明:

"CN":Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name);浏览器使用该字段验证网站是否合法;

"O":Organization,kube-apiserver 从证书中提取该字段作为请求用户所属的组 (Group);

生成CA证书和私钥

[root@dong ssl]# cfssl gencert -initca ca-csr.json | cfssljson -bare ca[root@dong ssl]# ls | grep caca-config.jsonca.csrca-csr.jsonca-key.pemca.pem

其中ca-key.pem是ca的私钥,ca.csr是一个签署请求,ca.pem是CA证书,是后面kubernetes组件会用到的RootCA。

创建kubernetes证书

创建kubernetes证书签名请求文件 kubernetes-csr.json

[root@dong ssl]# vim kubernetes-csr.json{    "CN": "kubernetes",    "hosts": [      "127.0.0.1",      "192.168.214.88",      "192.168.214.89",      "192.168.214.90",      "192.168.214.200",      "192.168.214.201",      "192.168.214.202",      "10.254.0.1",      "192.168.214.210",      "192.168.214.1/24",      "kubernetes",      "kube-api.wangdong.com",      "kubernetes.default",      "kubernetes.default.svc",      "kubernetes.default.svc.cluster",      "kubernetes.default.svc.cluster.local"    ],    "key": {        "algo": "rsa",        "size": 2048    },    "names": [        {            "C": "CN",            "ST": "BeiJing",            "L": "BeiJing",            "O": "k8s",            "OU": "System"        }    ]}

字段说明:

如果 hosts 字段不为空则需要指定授权使用该证书的 IP 或域名列表。

由于该证书后续被 etcd 集群和 kubernetes master使用,将etcd、master节点的IP都填上,同时还有service网络的首IP。(一般是 kube-apiserver 指定的 service-cluster-ip-range 网段的第一个IP,如 10.254.0.1)

我这里的设置包括一个私有镜像仓库,三个etcd,三个master,以上物理节点的IP也可以更换为主机名。

生成kubernetes证书和私钥

[root@dong ssl]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes[root@dong ssl]# ls |grep kuberneteskubernetes.csrkubernetes-csr.jsonkubernetes-key.pemkubernetes.pem

创建admin证书

创建admin证书签名请求文件admin-csr.json

[root@dong ssl]# admin-csr.json{  "CN": "admin",  "hosts": [],  "key": {    "algo": "rsa",    "size": 2048  },  "names": [    {      "C": "CN",      "ST": "BeiJing",      "L": "BeiJing",      "O": "system:masters",      "OU": "System"    }  ]}

说明:

后续 kube-apiserver 使用 RBAC 对客户端(如 kubelet、kube-proxy、Pod)请求进行授权;

kube-apiserver 预定义了一些 RBAC 使用的 RoleBindings,如 cluster-admin 将 Group system:masters 与 Role cluster-admin 绑定,该 Role 授予了调用kube-apiserver 的所有 API的权限;

O指定该证书的 Group 为 system:masters,kubelet 使用该证书访问 kube-apiserver 时 ,由于证书被 CA 签名,所以认证通过,同时由于证书用户组为经过预授权的 system:masters,所以被授予访问所有 API 的权限;

注:这个admin 证书,是将来生成管理员用的kube config 配置文件用的,现在我们一般建议使用RBAC 来对kubernetes 进行角色权限控制, kubernetes 将证书中的CN 字段 作为User, O 字段作为 Group

生成admin证书和私钥

[root@dong ssl]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin[root@dong ssl]# ls | grep adminadmin.csradmin-csr.jsonadmin-key.pemadmin.pem

创建kube-proxy证书

创建 kube-proxy 证书签名请求文件 kube-proxy-csr.json

[root@dong ssl]# vim kube-proxy-csr.json{  "CN": "system:kube-proxy",  "hosts": [],  "key": {    "algo": "rsa",    "size": 2048  },  "names": [    {      "C": "CN",      "ST": "BeiJing",      "L": "BeiJing",      "O": "k8s",      "OU": "System"    }  ]}

说明:

CN 指定该证书的 User 为 system:kube-proxy;

kube-apiserver 预定义的 RoleBinding system:node-proxier 将User system:kube-proxy 与 Role system:node-proxier 绑定,该 Role 授予了调用 kube-apiserver Proxy 相关 API 的权限;

生成kube-proxy证书和私钥

[root@dong ssl]# cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes  kube-proxy-csr.json | cfssljson -bare kube-proxy[root@dong ssl]# ls |grep kube-proxykube-proxy.csrkube-proxy-csr.jsonkube-proxy-key.pemkube-proxy.pem

经过上述操作,我们会用到如下文件:

[root@dong ssl]# ls | grep pemadmin-key.pemadmin.pemca-key.pemca.pemkube-proxy-key.pemkube-proxy.pemkubernetes-key.pemkubernetes.pem

查看证书信息

[root@master1 ssl]# cfssl-certinfo -cert kubernetes.pem{  "subject": {    "common_name": "kubernetes",    "country": "CN",    "organization": "k8s",    "organizational_unit": "System",    "locality": "BeiJing",    "province": "BeiJing",    "names": [      "CN",      "BeiJing",      "BeiJing",      "k8s",      "System",      "kubernetes"    ]  },  "issuer": {    "common_name": "kubernetes",    "country": "CN",    "organization": "k8s",    "organizational_unit": "System",    "locality": "BeiJing",    "province": "BeiJing",    "names": [      "CN",      "BeiJing",      "BeiJing",      "k8s",      "System",      "kubernetes"    ]  },  "serial_number": "321233745860282370502438768971300435157761820875",  "sans": [    "192.168.214.1/24",    "kubernetes",    "kube-api.wangdong.com",    "kubernetes.default",    "kubernetes.default.svc",    "kubernetes.default.svc.cluster",    "kubernetes.default.svc.cluster.local",    "127.0.0.1",    "192.168.214.88",    "192.168.214.89",    "192.168.214.90",    "192.168.214.200",    "192.168.214.201",    "192.168.214.202",    "10.254.0.1",    "192.168.214.210"  ],  "not_before": "2019-03-12T11:26:00Z",  "not_after": "2029-03-09T11:26:00Z",  "sigalg": "SHA256WithRSA",  "authority_key_id": "CB:34:54:33:1F:F4:37:E:E5:94:B7:F5:8A:3D:F4:A4:43:43:E2:7F",  "subject_key_id": "EC:31:D8:5F:4:E3:6F:C2:7F:DA:A8:F0:BD:A:B9:1F:56:7B:9A:DF",  "pem": "-----BEGIN CERTIFICATE-----\nMIIExjCCA66gAwIBAgIUOESejeFvtUe1qwPcXOQdC9a6iMswDQYJKoZIhvcNAQEL\nBQAwZTELMAkGA1UEBhMCQ04xEDAOBgNVBAgTB0JlaUppbmcxEDAOBgNVBAcTB0Jl\naUppbmcxDDAKBgNVBAoTA2s4czEPMA0GA1UECxMGU3lzdGVtMRMwEQYDVQQDEwpr\ndWJlcm5ldGVzMB4XDTE5MDMxMjExMjYwMFoXDTI5MDMwOTExMjYwMFowZTELMAkG\nA1UEBhMCQ04xEDAOBgNVBAgTB0JlaUppbmcxEDAOBgNVBAcTB0JlaUppbmcxDDAK\nBgNVBAoTA2s4czEPMA0GA1UECxMGU3lzdGVtMRMwEQYDVQQDEwprdWJlcm5ldGVz\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAteZIJbL5G2ZHEKajyVe7\nv4E1F9K9RzLTxghStRo808QOpVclOkFRHCi2qplrFrQmW4d/5AhJmofdoBuwIe/T\n3UgrhlPj1rWC5DhaG8J7+wOIp62yURslnXE+A+EsXQLXxeKxrbrodNwTmGJHXdGl\nv2pi0lyAgewdnhJHcYTvQbrDvbxpqYOHqKzJ3sqm1TSjnWSI9C1Hk/iF9xmjA4CG\nLDHocnxzNv+T/qSofv0yyGgA/HovlNxP+jSIwaWJu3QHhOxV3k2Bj7i0jSJoq3n9\nDl4co22Ge4SLiI2zPZayt9whzSyUoc5eloYJ1w7INcmfz2gOYl7L3godLg/gI5Eh\nNQIDAQABo4IBbDCCAWgwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUF\nBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMB0GA1UdDgQWBBTsMdhfBONvwn/a\nqPC9CrkfVnua3zAfBgNVHSMEGDAWgBTLNFQzH/Q3DuWUt/WKPfSkQ0PifzCB6AYD\nVR0RBIHgMIHdghAxOTIuMTY4LjIxNC4xLzI0ggprdWJlcm5ldGVzghVrdWJlLWFw\naS53YW5nZG9uZy5jb22CEmt1YmVybmV0ZXMuZGVmYXVsdIIWa3ViZXJuZXRlcy5k\nZWZhdWx0LnN2Y4Iea3ViZXJuZXRlcy5kZWZhdWx0LnN2Yy5jbHVzdGVygiRrdWJl\ncm5ldGVzLmRlZmF1bHQuc3ZjLmNsdXN0ZXIubG9jYWyHBH8AAAGHBMCo1liHBMCo\n1lmHBMCo1lqHBMCo1siHBMCo1smHBMCo1sqHBAr+AAGHBMCo1tIwDQYJKoZIhvcN\nAQELBQADggEBADtxejgpSQy913K9YyVLcS2k9bs41mZZbuokyrZiJeJ/CKZKzCo+\ngnF7P9/35IjkNlnYhlpUTTIJbnlQY8mDyKx1AaZOkzr+2djYRpg2vL3E7+CdRldQ\nUpNANSITolInKqboXev8SlLF9Mc/dWqgZzoifezuEkZ+c5KM6MY6MpMDVjVKNBxy\nJTd3bZNaPopop8IWxLAel5IQbzUhooswtzUxUslwKnYYC9tsKc5AgiXdehCnbGNf\nIr6wkK2OJBJStNPqarnpH6FZ6JxJ+qt59SdNhLixOT84HBR7ews/ZCYhQuPaJTy2\nwIb0XOtxILF3JMBNW/n21IyhF0vXsMdLg+o=\n-----END CERTIFICATE-----\n"}

在搭建k8s集群的时候,将这些文件分发到至此集群中其他节点机器中即可。至此,TLS证书创建完毕

证书 服务 字段 文件 节点 生成 验证 不同 权限 认证 用户 集群 制作 地址 客户 客户端 时候 相同 安全 这样一来 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 什么是软件开发模块化过程 成都专业软件开发定做 嘉定区工商软件开发值多少钱 samba服务器进程 培养信息网络安全意识 visio软件开发模版 dz 数据库安全过滤 阴阳师 服务器进不去 数据库只能让本地登录吗 易语言写个查数据库 mc屠龙之后服务器 河南掌上登记服务器错误咋回事 如何解决数据库引擎找不到对象 花园战争2怎样切换服务器 广州为联互联网科技有限公司 贵州时代网络技术分类设计 简述软件开发的一般过程. 东莞定制软件开发解决方案 数据库怎么存储日历 安防监控需要连接服务器吗 腾讯云服务器端口安全设置 中国网络安全监测 网络安全管理员面试有哪些问题 上海万户网络技术有限公司浦东 军队人员网络安全问题 数据库未命名 网络安全事件处理情况反馈 滁州oa管理软件开发多少钱 乡镇网络安全教育培训制度 上海网络技术开发价格
0