创建TLS证书和秘钥
创建TLS证书和秘钥
如果您不想看认证授权的解释,请直接看 安装 CFSSL
一、理解认证授权
该段理解引用 kubernetes-with-ca
1.1 为什么要认证
想理解认证,我们得从认证解决什么问题、防止什么问题的发生入手。
防止什么问题呢?是防止有人入侵你的集群,root你的机器后让我们集群依然安全吗?不是吧,root都到手了,那就为所欲为,防不胜防了。
其实网络安全本身就是为了解决在某些假设成立的条件下如何防范的问题。比如一个非常重要的假设就是两个节点或者ip之间的通讯网络是不可信任的,可能会被第三方窃取,也可能会被第三方篡改。就像我们上学时候给心仪的女孩传纸条,传送的过程可能会被别的同学偷看,甚至内容可能会从我喜欢你修改成我不喜欢你了。当然这种假设不是随便想出来的,而是从网络技术现状和实际发生的问题中发现、总结出来的。kubernetes的认证也是从这个问题出发来实现的。
1.2 概念梳理
为了解决上面说的问题,kubernetes并不需要自己想办法,毕竟是网络安全层面的问题,是每个服务都会遇到的问题,业内也有成熟的方案来解决。这里我们一起了解一下业内方案和相关的概念。
- 对称加密/非对称加密 这两个概念属于密码学的东西,对于没接触过的同学不太容易理解。可以参考知乎大神的生动讲解:《如何用通俗易懂的话来解释非对称加密》
- SSL/TLS 了解了对称加密和非对称加密后,我们就可以了解一下SSL/TLS了。同样,已经有大神总结了非常好的入门文章:《SSL/TLS协议运行机制的概述》
1.3 什么是授权
授权的概念就简单多了,就是什么人具有什么样的权限,一般通过角色作为纽带把他们组合在一起。也就是一个角色一边拥有多种权限,一边拥有多个人。这样就把人和权限建立了一个关系。
二、kubernetes的认证授权
Kubernetes集群的所有操作基本上都是通过kube-apiserver这个组件进行的,它提供HTTP RESTful形式的API供集群内外客户端调用。需要注意的是:认证授权过程只存在HTTPS形式的API中。也就是说,如果客户端使用HTTP连接到kube-apiserver,那么是不会进行认证授权的。所以说,可以这么设置,在集群内部组件间通信使用HTTP,集群外部就使用HTTPS,这样既增加了安全性,也不至于太复杂。
对APIServer的访问要经过的三个步骤,前面两个是认证和授权,第三个是 Admission Control,它也能在一定程度上提高安全性,不过更多是资源管理方面的作用。
2.1 kubernetes的认证
kubernetes提供了多种认证方式,比如客户端证书、静态token、静态密码文件、ServiceAccountTokens等等。你可以同时使用一种或多种认证方式。只要通过任何一个都被认作是认证通过。下面我们就认识几个常见的认证方式。
- 客户端证书认证 客户端证书认证叫作TLS双向认证,也就是服务器客户端互相验证证书的正确性,在都正确的情况下协调通信加密方案。 为了使用这个方案,api-server需要用--client-ca-file选项来开启。
- 引导Token 当我们有非常多的node节点时,手动为每个node节点配置TLS认证比较麻烦,这时就可以用到引导token的认证方式,前提是需要在api-server开启 experimental-bootstrap-token-auth 特性,客户端的token信息与预先定义的token匹配认证通过后,自动为node颁发证书。当然引导token是一种机制,可以用到各种场景中。
- Service Account Tokens 认证 有些情况下,我们希望在pod内部访问api-server,获取集群的信息,甚至对集群进行改动。针对这种情况,kubernetes提供了一种特殊的认证方式:Service Account。 Service Account 和 pod、service、deployment 一样是 kubernetes 集群中的一种资源,用户也可以创建自己的 Service Account。 ServiceAccount 主要包含了三个内容:namespace、Token 和 CA。namespace 指定了 pod 所在的 namespace,CA 用于验证 apiserver 的证书,token 用作身份验证。它们都通过 mount 的方式保存在 pod 的文件系统中。
2.2 kubernetes的授权
在Kubernetes1.6版本中新增角色访问控制机制(Role-Based Access,RBAC)让集群管理员可以针对特定使用者或服务账号的角色,进行更精确的资源访问控制。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。 目前 Kubernetes 中有一系列的鉴权机制,因为Kubernetes社区的投入和偏好,相对于其它鉴权机制而言,RBAC是更好的选择。具体RBAC是如何体现在kubernetes系统中的我们会在后面的部署中逐步的深入了解。
2.3 kubernetes的AdmissionControl
AdmissionControl - 准入控制本质上为一段准入代码,在对kubernetes api的请求过程中,顺序为:先经过认证 & 授权,然后执行准入操作,最后对目标对象进行操作。这个准入代码在api-server中,而且必须被编译到二进制文件中才能被执行。 在对集群进行请求时,每个准入控制代码都按照一定顺序执行。如果有一个准入控制拒绝了此次请求,那么整个请求的结果将会立即返回,并提示用户相应的error信息。 常用组件(控制代码)如下:
- AlwaysAdmit:允许所有请求
- AlwaysDeny:禁止所有请求,多用于测试环境
- ServiceAccount:它将serviceAccounts实现了自动化,它会辅助serviceAccount做一些事情,比如如果pod没有serviceAccount属性,它会自动添加一个default,并确保pod的serviceAccount始终存在
- LimitRanger:他会观察所有的请求,确保没有违反已经定义好的约束条件,这些条件定义在namespace中LimitRange对象中。如果在kubernetes中使用LimitRange对象,则必须使用这个插件。
- NamespaceExists:它会观察所有的请求,如果请求尝试创建一个不存在的namespace,则这个请求被拒绝。
三、安装 CFSSL
需要准备的证书:
- ca-key.pem
- ca.pem
- etcd-key.pem
- etcd.pem
- server-key.pem
- server.pem
- admin.pem
- admin-key.pem
- kube-proxy-key.pem
- kube-proxy.pem
使用证书的组件如下:
- etcd:使用 ca.pem、server-key.pem、server.pem
- kube-apiserver:使用 ca.pem、server-key.pem、server.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/ca目录下的证书拷贝到新节点上即可。
cfssl是非常好用的CA工具,我们用它来生成证书和秘钥文件,直接使用二进制源码包安装:
#下载
$ wget -q --show-progress --https-only --timestamping \
https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 \
https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
#修改为可执行权限
$ chmod +x cfssl_linux-amd64 cfssljson_linux-amd64
#移动到bin目录
$ mv cfssl_linux-amd64 /usr/local/bin/cfssl
$ mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
#验证
$ cfssl version
证书位置
#所有证书相关的东西都放在这, 后面所有的证书都放在该目录下, 你可以自定义
mkdir -p /etc/kubernetes/ca
四、创建 CA (根证书)
4.1 创建 CA 配置文件
cd /etc/kubernetes/ca
# 创建如下的ca-config.json文件(* 也可以不执行该命令,直接创建下面👇的文件)
cfssl print-defaults config > ca-config.json
# 修改 ca-config.json 文件,如下:
vim ca-config.json
# 过期时间设置成了 87600h
{
"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提供的证书进行验证;
4.2 创建 CA 证书签名请求
# 创建如下的ca-csr.json文件
cfssl print-defaults csr > ca-csr.json
# 修改 ca-csr.json 文件,如下:
vim ca-csr.json
# ca-csr.josn 文件内容如下
{
"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);
4.3 生成 CA 证书和私钥
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
# 生成完成后会有以下文件(我们最终想要的就是ca-key.pem和ca.pem,一个秘钥,一个证书)
> ls
> ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem
五、创建 ETCD 证书
5.1 生成 etcd 证书配置
# etcd证书放在这
mkdir -p /etc/kubernetes/ca/etcd
cd /etc/kubernetes/ca/etcd
vim etcd-csr.json
# 文件内容如下
{
"CN": "etcd",
"hosts": [
"127.0.0.1",
"192.168.10.102"
],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "Beijing",
"L": "XS",
"O": "k8s",
"OU": "System"
}
]
}
字段说明
hosts
:指定授权使用该证书的 IP 或域名列表,如果有部署多个 etcd,那么就需要填入其他 etcd 的 IP 或域名列表,我这里只部署一台所以就写一个☝️
提示
注:上述文件hosts字段中IP为所有etcd节点的集群内部通信IP,一个都不能少!为了方便后期扩容可以多写几个预留的IP。
5.2 使用根证书(ca.pem)签发etcd证书
cfssl gencert \
-ca=/etc/kubernetes/ca/ca.pem \
-ca-key=/etc/kubernetes/ca/ca-key.pem \
-config=/etc/kubernetes/ca/ca-config.json \
-profile=kubernetes etcd-csr.json | cfssljson -bare etcd
# 跟之前类似生成三个文件etcd.csr是个中间证书请求文件,我们最终要的是etcd-key.pem和etcd.pem
> ls
> etcd.csr etcd-csr.json etcd-key.pem etcd.pem
六、创建 Api-server 证书
- controller-manager: 一般与api-server在同一台机器上,所以可以使用非安全端口与api-server通讯,不需要生成证书和私钥
- scheduler: 一般与apiserver在同一台机器上,所以可以使用非安全端口与apiserver通讯。不需要生成证书和私钥。
6.1 生成 Api-server 证书配置
# api-server证书放在这
mkdir -p /etc/kubernetes/ca/server
cd /etc/kubernetes/ca/server
vim server-csr.json
# 内容如下
{
"CN": "kubernetes",
"hosts": [
"127.0.0.1",
"10.0.0.1",
"192.168.10.101",
"192.168.10.102",
"192.168.10.103",
"kubernetes",
"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": "XS",
"O": "k8s",
"OU": "System"
}
]
}
kubernetes
服务的服务 IP(一般是kube-apiserver
指定的service-cluster-ip-range
网段的第一个IP,如 10.0.0.1)
6.2 使用根证书(ca.pem)签发 apiserver 证书
cfssl gencert \
-ca=/etc/kubernetes/ca/ca.pem \
-ca-key=/etc/kubernetes/ca/ca-key.pem \
-config=/etc/kubernetes/ca/ca-config.json \
-profile=kubernetes server-csr.json | cfssljson -bare server
# 跟之前类似生成三个文件server.csr是个中间证书请求文件,我们最终要的是server-key.pem和server.pem
> ls
> server-csr.json server.csr server.pem server-key.pem
七、创建 Admin 证书
7.1 生成 Admin 证书配置
# kubectl证书放在这,由于kubectl相当于系统管理员,我们使用admin命名
mkdir -p /etc/kubernetes/ca/admin
cd /etc/kubernetes/ca/admin
vim admin-csr.json
# 内容如下
{
"CN": "admin",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "system:masters",
"OU": "System"
}
]
}
7.2 使用根证书(ca.pem)签发admin证书
cfssl gencert \
-ca=/etc/kubernetes/ca/ca.pem \
-ca-key=/etc/kubernetes/ca/ca-key.pem \
-config=/etc/kubernetes/ca/ca-config.json \
-profile=kubernetes admin-csr.json | cfssljson -bare admin
# 我们最终要的是admin-key.pem和admin.pem
> ls
> admin.csr admin-csr.json admin-key.pem admin.pem
八、创建 kube-proxy 证书
8.1 生成 kube-proxy 证书配置
# proxy证书放在这
mkdir -p /etc/kubernetes/ca/kube-proxy
cd /etc/kubernetes/ca/kube-proxy
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
预定义的 RoleBindingsystem:node-proxy
将Usersystem:kube-proxy
与 Rolesystem:node-proxier
绑定,授予了调用kube-api-server
proxy的相关 API 的权限
8.2 使用根证书(ca.pem)签发proxy证书
cfssl gencert \
-ca=/etc/kubernetes/ca/ca.pem \
-ca-key=/etc/kubernetes/ca/ca-key.pem \
-config=/etc/kubernetes/ca/ca-config.json \
-profile=kubernetes kube-proxy-csr.json | cfssljson -bare kube-proxy
# 我们最终要的是kube-proxy-key.pem和kube-proxy.pem
> ls
> kube-proxy.csr kube-proxy-csr.json kube-proxy-key.pem kube-proxy.pem
九、分发证书
将生成的证书和秘钥文件(后缀名为.pem
)拷贝到所有机器的 /etc/kubernetes/ca
目录下备用;
# 最后查看生成的证书目录
> ls /etc/kubernetes/ca
> admin ca-config.json ca.csr ca-csr.json ca-key.pem ca.pem etcd kube-proxy apiserver
# 分发证书
scp -r /etc/kubernetes/ca root@其他节点ip:/etc/kubernetes/
十、启用 TLS Bootstrapping 机制
TLS Bootstraping:Master apiserver启用TLS认证后,Node节点kubelet和kube-proxy要与kube-apiserver进行通信,必须使用CA签发的有效证书才可以,当Node节点很多时,这种客户端证书颁发需要大量工作,同样也会增加集群扩展复杂度。为了简化流程,Kubernetes引入了TLS bootstraping机制来自动颁发客户端证书,kubelet会以一个低权限用户自动向apiserver申请证书,kubelet的证书由apiserver动态签署。所以强烈建议在Node上使用这种方式,目前主要用于kubelet,kube-proxy还是由我们统一颁发一个证书。
TLS bootstraping 工作流程:
10.1 生成token认证文件
# 生成随机token
head -c 16 /dev/urandom | od -An -t x | tr -d ' '
# 按照固定格式写入token.csv,注意替换token内容
echo "734883758a7159caba1d9501c22f1408,kubelet-bootstrap,10001,\"system:kubelet-bootstrap\"" > /etc/kubernetes/ca/server/token.csv