完整集群部署

本篇尝试对之前使用的基础集群进行改造和升级,使其成为一个比较完整的Kubernetes集群。

理解认证授权

为什么要认证

想理解认证,我们得从认证用于解决什么问题、防止什么问题的发生入手?
防止什么问题呢?是防止有人入侵你的集群,root你的机器后我们集群依然安全吗?不是吧,root都到手了,那就为所欲为,防不胜防了。

其实网络安全本身就是为了解决在某些假设成立的条件下如何防范的问题。比如一个非常重要的假设就是两个节点或者ip之间的通讯网络是不可信任的,可能会被第三方窃取,也可能会被第三方篡改。就像我们上学时候给心仪的女孩传纸条,传送的过程可能会被别的同学偷看,甚至内容可能会从我喜欢你修改成我不喜欢你了。当然这种假设不是随便想出来的,而是从网络技术现状和实际发生的问题中发现、总结出来的。kubernetes的认证也是从这个问题出发来实现的。

概念梳理

为了解决上面说的问题,kubernetes并不需要自己想办法,毕竟是网络安全层面的问题,是每个服务都会遇到的问题,业内也有成熟的方案来解决。这里我们一起了解一下业内方案和相关的概念。
(1)对称加密/非对称加密。(2)SSL/TLS。

什么是授权

授权的概念就简单多了,就是什么人具有什么样的权限,一般通过角色作为纽带把他们组合在一起。也就是一个角色一边拥有多种权限,一边拥有多个人。这样就把人和权限建立了一个关系。

kubernetes的认证授权

Kubernetes集群的所有操作基本上都是通过kube-apiserver这个组件进行的,它提供HTTP RESTful形式的API供集群内外客户端调用。需要注意的是,认证授权过程只存在HTTPS形式的API中。也就是说,如果客户端使用HTTP连接到kube-apiserver,此时是不会进行认证授权的。因此开发者可以这样设置,在集群内部组件间通信使用HTTP,集群外部则使用HTTPS,这样既增加了安全性,也不至于太复杂。

对APIServer的访问要经过的三个步骤,前面两个是认证和授权,第三个是 Admission Control,它也能在一定程度上提高安全性,不过更多是资源管理方面的作用。

kubernetes的认证

kubernetes提供了多种认证方式,比如客户端证书、静态token、静态密码文件、ServiceAccountTokens等等。开发者可以同时使用一种或多种认证方式,只要通过任何一种都被认为是认证通过。下面我们就来认识几个常见的认证方式。
(1)客户端证书认证。客户端证书认证(TLS双向认证),也就是服务器客户端互相验证证书的正确性,只有在双方都正确的情况下协调通信加密方案。 为了使用这个方案,api-server需要用--client-ca-file选项来开启。

(2)引导Token。当我们有非常多的node节点时,手动为每个node节点配置TLS认证比较麻烦,这时就可以用到引导token的认证方式,前提是需要在api-server开启experimental-bootstrap-token-auth特性,客户端的token信息与预先定义的token匹配认证通过后,自动为node颁发证书。当然引导token是一种机制,可以用到各种场景中。

(3)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 的文件系统中。

kubernetes的授权

Kubernetes1.6版本中新增角色访问控制机制(Role-Based Access,RBAC),目的是让集群管理员可以针对特定使用者或服务账号的角色,进行更精确的资源访问控制。在RBAC中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。在一个组织中,角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。 目前 Kubernetes 中有一系列的鉴权机制,因为Kubernetes社区的投入和偏好,相对于其它鉴权机制而言,RBAC是更好的选择。具体RBAC是如何体现在kubernetes系统中的我们会在后面的部署中逐步的深入了解。

kubernetes的AdmissionControl

AdmissionControl (准入控制)本质上为一段准入代码,在对kubernetes api的请求过程中,顺序如下:先经过认证和授权,然后执行准入操作,最后对目标对象进行操作。这个准入代码在api-server中,而且必须被编译到二进制文件中才能被执行。 在对集群进行请求时,每个准入控制代码都按照一定顺序执行。如果有一个准入控制拒绝了此次请求,那么整个请求的结果将会立即返回,并提示用户相应的error信息。

常用组件(控制代码)如下:
(1)AlwaysAdmit:允许所有请求。
(2)AlwaysDeny:禁止所有请求,多用于测试环境。
(3)ServiceAccount:它将serviceAccounts实现了自动化,它会辅助serviceAccount做一些事情,比如如果pod没有serviceAccount属性,它会自动添加一个default,并确保pod的serviceAccount始终存在。
(4)LimitRanger:它会观察所有的请求,以确保没有违反已经定义好的约束条件,这些条件定义在namespace中LimitRange对象中。如果在kubernetes中使用LimitRange对象,则必须使用这个插件。
(5)NamespaceExists:它会观察所有的请求,如果请求尝试创建一个不存在的namespace,则这个请求被拒绝。

环境准备

停止原有kubernetes相关服务

在开始之前,我们需要先将基础版本的集群停掉,包括service,deployments,pods以及运行的所有kubernetes组件,使用的命令如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#删除master节点上自己创建的各种组件
#删除services
$ kubectl delete services kubernetes-bootcamp
$ kubectl delete services nginx-service
#删除deployments
$ kubectl delete deploy kubernetes-bootcamp
$ kubectl delete deploy nginx-deployment
#删除pods
$ kubectl delete pod nginx

#停掉worker节点的服务
$ service kubelet stop && rm -fr /var/lib/kubelet/*
$ service kube-proxy stop && rm -fr /var/lib/kube-proxy/*
$ service kube-calico stop

#停掉master节点的服务
$ service kube-calico stop
$ service kube-scheduler stop
$ service kube-controller-manager stop
$ service kube-apiserver stop
$ service etcd stop && rm -fr /var/lib/etcd/*

生成配置(所有节点)

和基础环境搭建一样,我们需要生成kubernetes-with-ca的所有相关配置文件。进入到/home/envy/kubernetes-starter目录,修改其中的config.properties配置文件为如下所示,其实也就是将ETCD_ENDPOINTS配置项中的http修改为了https,其他都没有变化:

1
2
3
4
5
6
7
8
9
10
11
12
13
#kubernetes二进制文件目录,eg: /home/envy/bin
BIN_PATH=/home/envy/bin

#当前节点ip, eg: 192.168.1.102
NODE_IP=192.168.51.122

#etcd服务集群列表, eg: http://192.168.1.102:2379
#如果已有etcd集群可以填写现有的。没有的话填写:http://${MASTER_IP}:2379 (MASTER_IP自行替换成自己的主节点ip)
##如果用了证书,就要填写https://${MASTER_IP}:2379 (MASTER_IP自行替换成自己的主节点ip)
ETCD_ENDPOINTS=https://192.168.51.122:2379

#kubernetes主节点ip地址, eg: 192.168.1.102
MASTER_IP=192.168.51.122

之后在该文件目录下执行如下命令来生成对应的配置信息:

1
$ ./gen-config.sh with-ca

生成的文件依旧是在target目录中,它会覆盖之前target目录中的文件。

安装cfssl(所有节点)

cfssl是非常好用的CA工具,我们用它来生成证书和秘钥文件。它安装过程比较简单,使用的命令如下所示:

1
2
3
4
5
6
7
8
9
10
11
# 安装wget工具
$ yum install -y wget
#下载
$ wget 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

生成根证书(主节点)

根证书是证书信任链的根,各个组件通讯的前提是有一份大家都信任的证书(根证书),每个人使用的证书都是由这个根证书签发的。

1
2
3
4
5
6
7
8
9
10
11
#所有证书相关的东西都放在这
$ mkdir -p /etc/kubernetes/ca
#准备生成证书的配置文件
$ cp /home/envy/kubernetes-starter/target/ca/ca-config.json /etc/kubernetes/ca
$ cp /home/envy/kubernetes-starter/target/ca/ca-csr.json /etc/kubernetes/ca
#生成证书和秘钥
$ cd /etc/kubernetes/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(主节点执行)

准备证书

etcd节点需要提供给其他服务访问,就要验证其他服务的身份,所以需要一个标识自己监听服务的server证书,当有多个etcd节点时,也需要client证书与etcd集群的其他节点交互,当然client和server也可以使用同一个证书,因为它们本质上没有区别。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#etcd证书放在这
$ mkdir -p /etc/kubernetes/ca/etcd
#准备etcd证书配置
$ cp /home/envy/kubernetes-starter/target/ca/etcd/etcd-csr.json /etc/kubernetes/ca/etcd/
$ cd /etc/kubernetes/ca/etcd/
#使用根证书(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

改造etcd服务

先比较一下增加认证的etcd配置与原有配置的区别,这样可以做到心中有数,可使用的比较命令为:

1
2
3
4
# 安装vim
$ yum install -y vim
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/master-node/etcd.service kubernetes-with-ca/master-node/etcd.service

可以看到之前的listen-client-urlsadvertise-client-urls现在都变成了https,同时新增了如下新的配置项:

1
2
3
4
5
6
7
8
--listen-peer-urls=https://{{NODE_IP}}:2380
--initial-advertise-peer-urls=https://{{NODE_IP}}:2380
--cert-file=/etc/kubernetes/ca/etcd/etcd.pem
--key-file=/etc/kubernetes/ca/etcd/etcd-key.pem
--peer-cert-file=/etc/kubernetes/ca/etcd/etcd.pem
--peer-key-file=/etc/kubernetes/ca/etcd/etcd-key.pem
--trusted-ca-file=/etc/kubernetes/ca/ca.pem
--peer-trusted-ca-file=/etc/kubernetes/ca/ca.pem

更新etcd服务

更新etcd服务使用的命令如下所示:

1
2
3
4
5
6
7
8
9
10
$ cp /home/envy/kubernetes-starter/target/master-node/etcd.service /lib/systemd/system/
$ systemctl daemon-reload
$ service etcd start
#验证etcd服务(endpoints自行替换)
$ ETCDCTL_API=3 etcdctl \
--endpoints=https://192.168.51.122:2379 \
--cacert=/etc/kubernetes/ca/ca.pem \
--cert=/etc/kubernetes/ca/etcd/etcd.pem \
--key=/etc/kubernetes/ca/etcd/etcd-key.pem \
endpoint health

这样etcd我们就成功的改造完了,接下来我们继续改造其他的组件。

改造api-server(主节点执行)

准备证书

首先我们需要使用如下命令来创建证书存放位置和生成证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#定义api-server证书存放位置,由于api-server是核心,因此这里文件夹名为kubernetes,也可以叫apiserver,只是对应地方需要修改
$ mkdir -p /etc/kubernetes/ca/kubernetes
#准备apiserver证书配置
$ cp /home/envy/kubernetes-starter/target/ca/kubernetes/kubernetes-csr.json /etc/kubernetes/ca/kubernetes/
$ cd /etc/kubernetes/ca/kubernetes/
#使用根证书(ca.pem)签发kubernetes证书
$ 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 kubernetes-csr.json | cfssljson -bare kubernetes

#和之前类似,生成了三个文件,其中kubernetes.csr是个中间证书请求文件,我们最终要的是kubernetes-key.pem和kubernetes.pem
$ ls
kubernetes.csr kubernetes-csr.json kubernetes-key.pem kubernetes.pem

改造api-server服务

先比较一下增加认证的api-server配置与原有配置的区别,这样可以做到心中有数,可使用的比较命令为:

1
2
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/master-node/kube-apiserver.service kubernetes-with-ca/master-node/kube-apiserver.service

可以看到这个admission-control选项多了一个ServiceAccount值(认证授权会使用到),同时insecure-bind-address参数值由0.0.0.0变成了127.0.0.1(不安全地址之前是所有IP都可以访问,现在只有本机才可以访问)以及kubelet-https参数值为true。同时新增了如下新的配置项,这些都是与认证和授权相关的内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
--bind-address={{NODE_IP}}
--authorization-mode=Node,RBAC # 授权模式RBAC
--runtime-config=rbac.authorization.k8s.io/v1
--enable-bootstrap-token-auth
--token-auth-file=/etc/kubernetes/ca/kubernetes/token.csv # 指定token-auth-file的地址,我们需要生成这个文件
--tls-cert-file=/etc/kubernetes/ca/kubernetes/kubernetes.pem
--tls-private-key-file=/etc/kubernetes/ca/kubernetes/kubernetes-key.pem
--client-ca-file=/etc/kubernetes/ca/ca.pem
--service-account-key-file=/etc/kubernetes/ca/ca-key.pem
--etcd-cafile=/etc/kubernetes/ca/ca.pem
--etcd-certfile=/etc/kubernetes/ca/kubernetes/kubernetes.pem
--etcd-keyfile=/etc/kubernetes/ca/kubernetes/kubernetes-key.pem
--service-cluster-ip-range=10.68.0.0/16
--service-cluster-ip-range=10.68.0.0/16
--service-node-port-range=20000-40000
--service-node-port-range=20000-40000
--etcd-servers={{ETCD_ENDPOINTS}}
--etcd-servers={{ETCD_ENDPOINTS}}
--enable-swagger-ui=true
--enable-swagger-ui=true
--allow-privileged=true
--allow-privileged=true
--audit-log-maxage=30
--audit-log-maxage=30

注意,这里面有一个bootstrap-token-auth验证,而我们指定了token-auth-file的存储位置,因此将下来就是生成这个名为token.csv的文件。

1
2
3
4
5
6
#生成随机token
$ head -c 16 /dev/urandom | od -An -t x | tr -d ' '
49dd2bb99bc687e21dfa34e78fe098b1

#按照固定格式写入token.csv,注意替换token内容
$ echo "49dd2bb99bc687e21dfa34e78fe098b1,kubelet-bootstrap,10001,\"system:kubelet-bootstrap\"" > /etc/kubernetes/ca/kubernetes/token.csv

更新api-server服务

更新api-server服务使用的命令如下所示:

1
2
3
4
5
6
$ cp /home/envy/kubernetes-starter/target/master-node/kube-apiserver.service /lib/systemd/system/
$ systemctl daemon-reload
$ service kube-apiserver start

#检查日志
$ journalctl -f -u kube-apiserver

改造controller-manager(主节点执行)

由于controller-manager一般与api-server在同一台机器上,因此可使用非安全端口与api-server进行通讯,故不需要生成证书和私钥。

查看diff内容

先比较一下增加认证的controller-manager配置与原有配置的区别,这样可以做到心中有数,可使用的比较命令为:

1
2
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/master-node/kube-controller-manager.service kubernetes-with-ca/master-node/kube-controller-manager.service

可以看到这个cluster-signing-cert-filecluster-signing-key-file这两个配置项的值都从空字符串变成了我们设置的ca证书的文件和私钥。这里你可能会有疑问,它里面设置的master参数就是127.0.0.10:8080这不就是本地么,这里为什么还需要ca证书呢?原因在于这些证书并不是在访问api-server时才使用的,而是当签名为tls/bootstrap时的证书和私钥。同时新增了如下新的配置项:

1
2
--service-account-private-key-file=/etc/kubernetes/ca/ca-key.pem
--root-ca-file=/etc/kubernetes/ca/ca.pem

更新controller-manager服务

更新controller-manager服务使用的命令如下所示:

1
2
3
4
5
6
$ cp /home/envy/kubernetes-starter/target/master-node/kube-controller-manager.service /lib/systemd/system/
$ systemctl daemon-reload
$ service kube-controller-manager start

#检查日志
$ journalctl -f -u kube-controller-manager

改造scheduler(主节点执行)

由于scheduler一般与api-server在同一台机器上,因此可使用非安全端口与api-server进行通讯,故不需要生成证书和私钥。

查看diff内容

先比较一下增加认证的scheduler配置与原有配置的区别,这样可以做到心中有数,可使用的比较命令为:

1
2
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/master-node/kube-scheduler.service kubernetes-with-ca/master-node/kube-scheduler.service

可以发现这个文件前后没有任何变化,因此不需要进行改造。

启动scheduler服务

1
2
3
$ service kube-scheduler start
#检查日志
$ journalctl -f -u kube-scheduler

改造kubectl(任意节点)

由于前面我们将kubectl安装在了主节点上,其实我们是不需要对kubectl进行改造的。但是如果你的kubectl不是安装在了主节点,那么就需要进行改造。当然了就算kubectl安装在了主节点,我们还是可以对kubectl进行改造。

准备证书

首先我们需要使用如下命令来创建证书存放位置和生成证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#kubectl证书放在这,由于kubectl相当于系统管理员,因此这里使用admin命名
$ mkdir -p /etc/kubernetes/ca/admin
#准备admin证书配置,由于kubectl只需客户端证书,因此证书请求中的 hosts 字段可以为空
$ cp /home/envy/kubernetes-starter/target/ca/admin/admin-csr.json /etc/kubernetes/ca/admin/
$ cd /etc/kubernetes/ca/admin/
#使用根证书(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

配置kubectl

接下来使用如下命令来对kubectl进行设置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#指定apiserver的地址和证书位置(ip自行修改)
$ kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ca/ca.pem \
--embed-certs=true \
--server=https://192.168.51.122:6443
#设置客户端认证参数,指定admin证书和秘钥
$ kubectl config set-credentials admin \
--client-certificate=/etc/kubernetes/ca/admin/admin.pem \
--embed-certs=true \
--client-key=/etc/kubernetes/ca/admin/admin-key.pem
#关联用户和集群
$ kubectl config set-context kubernetes \
--cluster=kubernetes --user=admin
#设置当前上下文
$ kubectl config use-context kubernetes

#设置结果就是一个配置文件,可以看看内容,此处的~其实就是/root
$ cat ~/.kube/config

~/.kube/config文件里面多了很多配置信息,这里面就是上面配置的各种项。然后运行如下命令:

1
2
[root@server02 admin]# kubectl get pods
No resources found.

出现上述结构,则说明kubectl可通过https来访问apiserver了。

验证主节点

回到主节点,我们使用刚刚配置好的kubectl来查看一下组件的状态,如下所示:

1
2
3
4
5
[root@server02 admin]# kubectl get componentstatus
NAME STATUS MESSAGE ERROR
controller-manager Healthy ok
scheduler Healthy ok
etcd-0 Healthy {"health": "true"}

改造calico-node(所有节点执行)

准备证书(只在主节点上执行)

后面你就会知道,calico证书会用在如下四个地方:
(1)calico/node,docker容器运行时访问etcd时,使用证书;
(2)cni 配置文件中,cni 插件需要访问etcd时,使用证书;
(3)calicoctl 操作集群网络访问etcd时, 使用证书;
(4)calico/kube-controllers 同步集群网络策略访问etcd时,使用证书。

首先我们需要使用如下命令来创建证书存放位置和生成证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#定义calico证书存放目录
$ mkdir -p /etc/kubernetes/ca/calico
#准备calico证书配置,由于calico只需客户端证书,因此证书请求中 hosts 字段可以为空
$ cp /home/envy/kubernetes-starter/target/ca/calico/calico-csr.json /etc/kubernetes/ca/calico/
$ cd /etc/kubernetes/ca/calico/
#使用根证书(ca.pem)签发calico证书
$ 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 calico-csr.json | cfssljson -bare calico
#最终需要的是calico-key.pem和calico.pem
$ ls
calico.csr calico-csr.json calico-key.pem calico.pem

改造calico服务(所有节点执行)

查看diff内容

先比较一下增加认证的calico配置与原有配置的区别,这样可以做到心中有数,可使用的比较命令为:

1
2
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/all-node/kube-calico.service kubernetes-with-ca/all-node/kube-calico.service

通过对比可以看到,calico服务相比于之前多了一些与认证相关的文件:

1
2
3
-e ETCD_CA_CERT_FILE=/etc/kubernetes/ca/ca.pem
-e ETCD_CERT_FILE=/etc/kubernetes/ca/calico/calico.pem
-e ETCD_KEY_FILE=/etc/kubernetes/ca/calico/calico-key.pem

由于calico服务是所有节点都需要安装的,因此需要将上述三个对应目录下的证书文件拷贝到每个节点的/etc/kubernetes/目录下,可使用如下命令:

1
scp -r /etc/kubernetes/ca root@其他节点ip:/etc/kubernetes/
更新calico服务

接着我们依次执行如下命令来更新calico服务:

1
2
3
$ cp /home/envy/kubernetes-starter/target/all-node/kube-calico.service /lib/systemd/system/
$ systemctl daemon-reload
$ service kube-calico start

之后使用如下命令来验证calico,如果能看到其他节点的列表,这就说明calico更新是成功的:

1
2
3
4
5
6
7
8
9
10
[root@server02 ~]# calicoctl node status
Calico process is running.

IPv4 BGP status
+----------------+-------------------+-------+----------+-------------+
| PEER ADDRESS | PEER TYPE | STATE | SINCE | INFO |
+----------------+-------------------+-------+----------+-------------+
| 192.168.51.123 | node-to-node mesh | up | 01:32:56 | Established |
| 192.168.51.121 | node-to-node mesh | up | 01:42:58 | Established |
+----------------+-------------------+-------+----------+-------------+```

改造kubelet(所有节点执行)

这里我们让kubelet采用引导token的方式认证,所以认证方式跟之前的组件不同,它的证书不是手动生成,而是由工作节点TLS BootStrap 向api-server请求,由主节点的controller-manager 自动签发。首先需要使用service kubelet stop命令来停止各个节点上kubelet的运行。

创建角色绑定(只在主节点上执行)

引导token的方式要求客户端向api-server发起请求时,告诉它你的用户名和token,并且这个用户是具有一个特定的角色system:node-bootstrapper,因此需要先将 bootstrap token 文件中的kubelet-bootstrap用户赋予这个特定角色,然后 kubelet 才有权限发起创建认证请求。

开发者需要在主节点执行如下命令:

1
2
3
4
5
6
7
8
9
10
#可以通过下面命令查询clusterrole列表
$ kubectl -n kube-system get clusterrole

#查看一下token文件的内容
$ cat /etc/kubernetes/ca/kubernetes/token.csv
49dd2bb99bc687e21dfa34e78fe098b1,kubelet-bootstrap,10001,"system:kubelet-bootstrap"

#创建角色绑定(即将用户kubelet-bootstrap与角色system:node-bootstrapper进行绑定)
$ kubectl create clusterrolebinding kubelet-bootstrap \
--clusterrole=system:node-bootstrapper --user=kubelet-bootstrap

创建bootstrap.kubeconfig(所有工作节点执行)

此配置用于完成bootstrap token认证,里面保存了用户、token等重要认证信息,注意这个文件可以借助kubectl命令生成,也可以由开发者自己通过书写配置文件生成:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#设置集群参数(注意替换ip)
$ kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ca/ca.pem \
--embed-certs=true \
--server=https://192.168.51.122:6443 \
--kubeconfig=bootstrap.kubeconfig
#设置客户端认证参数(注意替换token)
$ kubectl config set-credentials kubelet-bootstrap \
--token=49dd2bb99bc687e21dfa34e78fe098b1 \
--kubeconfig=bootstrap.kubeconfig
#设置上下文
$ kubectl config set-context default \
--cluster=kubernetes \
--user=kubelet-bootstrap \
--kubeconfig=bootstrap.kubeconfig
#选择上下文
$ kubectl config use-context default --kubeconfig=bootstrap.kubeconfig
#将刚生成的文件移动到合适的位置
$ mv bootstrap.kubeconfig /etc/kubernetes/

准备cni配置(所有工作节点执行)

查看diff内容
1
2
3
$ yum install vim -y
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/worker-node/10-calico.conf kubernetes-with-ca/worker-node/10-calico.conf

通过对比可以看到,相比于之前多了一些与认证相关的文件:

1
2
3
"etcd_key_file": "/etc/kubernetes/ca/calico/calico-key.pem"
"etcd_cert_file": "/etc/kubernetes/ca/calico/calico.pem",
"etcd_ca_cert_file": "/etc/kubernetes/ca/ca.pem",

同时k8s_api_root这一选项变成了kubeconfig这一选项的值,配置文件就是/etc/kubernetes/kubelet.kubeconfig

覆盖之前配置信息

接下来我们使用如下命令来覆盖之前的配置信息:

1
$ cp /home/envy/kubernetes-starter/target/worker-node/10-calico.conf /etc/cni/net.d/

改造kubelet服务(所有工作节点执行)

查看diff内容
1
2
$ cd /home/envy/kubernetes-starter
$ vimdiff kubernetes-simple/worker-node/kubelet.service kubernetes-with-ca/worker-node/kubelet.service

通过对比可以看到,相比于之前多了一些配置信息:

1
2
3
--experimental-bootstrap-kubeconfig=/etc/kubernetes/bootstrap.kubeconfig \                             
--cert-dir=/etc/kubernetes/ca \
--hairpin-mode hairpin-veth \
更新服务

在所有工作节点上执行如下命令:

1
2
3
$ cp /home/envy/kubernetes-starter/target/worker-node/kubelet.service /lib/systemd/system/
$ systemctl daemon-reload
$ service kubelet start

之后使用journalctl -f -u kubelet命令来检查日志,以确保kubelet已经成功启动,接着回到主节点,执行如下命令看一下前一个工作节点是否向主节点发送了添加集群的请求:

1
2
3
[root@server02 ~]# kubectl get csr
NAME AGE REQUESTOR CONDITION
node-csr-zM7Em4BCVTGhDVJqlsY5P37zmbwImAMPWta67SHaaqE 33s kubelet-bootstrap Pending

然后执行如下命令来允许worker加入(批准worker的tls证书请求):

1
2
[root@server02 ~]# kubectl get csr|grep 'Pending' | awk '{print $1}'| xargs kubectl certificate approve
certificatesigningrequest "node-csr-zM7Em4BCVTGhDVJqlsY5P37zmbwImAMPWta67SHaaqE" approved

最后再在主节点上确认其他两个节点都已经加入到集群中:

1
2
3
4
[root@server02 ~]# kubectl get csr
NAME AGE REQUESTOR CONDITION
node-csr-52ZQYhjSU70AqZJahaD52YDdeSKFDRjJ2eGOSVIkMlw 1m kubelet-bootstrap Approved,Issued
node-csr-zM7Em4BCVTGhDVJqlsY5P37zmbwImAMPWta67SHaaqE 1h kubelet-bootstrap Approved,Issued

改造kube-proxy(工作节点执行)

准备证书

首先我们需要使用如下命令来创建证书存放位置和生成证书:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#定义proxy证书的存放位置
$ mkdir -p /etc/kubernetes/ca/kube-proxy

#准备proxy证书配置,由于proxy只需客户端证书,因此证书请求中 hosts 字段可以为空。
#CN 指定该证书的 User 为 system:kube-proxy,预定义的 ClusterRoleBinding为system:node-proxy,即将User用户system:kube-proxy 与 Role角色system:node-proxier进行绑定,授予了调用 kube-api-server proxy的相关 API 的权限
$ cp /home/envy/kubernetes-starter/target/ca/kube-proxy/kube-proxy-csr.json /etc/kubernetes/ca/kube-proxy/
$ cd /etc/kubernetes/ca/kube-proxy/

#使用根证书(ca.pem)签发kube-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

创建kube-proxy.kubeconfig配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#设置集群参数(注意替换ip)
$ kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/ca/ca.pem \
--embed-certs=true \
--server=https://192.168.51.122:6443 \
--kubeconfig=kube-proxy.kubeconfig
#置客户端认证参数
$ kubectl config set-credentials kube-proxy \
--client-certificate=/etc/kubernetes/ca/kube-proxy/kube-proxy.pem \
--client-key=/etc/kubernetes/ca/kube-proxy/kube-proxy-key.pem \
--embed-certs=true \
--kubeconfig=kube-proxy.kubeconfig
#设置上下文参数
$ kubectl config set-context default \
--cluster=kubernetes \
--user=kube-proxy \
--kubeconfig=kube-proxy.kubeconfig
#选择上下文
$ kubectl config use-context default --kubeconfig=kube-proxy.kubeconfig
#将刚生成的文件移动到合适的位置
$ mv kube-proxy.kubeconfig /etc/kubernetes/kube-proxy.kubeconfig

改造kube-proxy服务

查看diff内容
1
2
$ cd /home/envy/kubernetes-starter/
$ vimdiff kubernetes-simple/worker-node/kube-proxy.service kubernetes-with-ca/worker-node/kube-proxy.service

从diff结果中可以看出,kube-proxy.service文件前后没有发生任何变化。

启动服务
1
2
3
4
5
6
7
8
9
10
11
#复制配置文件
$ cp /home/envy/kubernetes-starter/target/worker-node/kube-proxy.service /lib/systemd/system/
$ systemctl daemon-reload

#安装依赖软件
$ yum install conntrack -y

#启动服务
$ service kube-proxy start
#查看日志
$ journalctl -f -u kube-proxy

改造kube-dns(app)

简介

kube-dns有些特别,因为它是以kubernetes应用的形式,运行在kubernetes集群中,因此它的认证授权方式和之前的组件都不一样,需要用到service account认证和RBAC授权。
(1)service account认证:每个service account都会自动生成自己的secret,用于包含一个ca,token和secret,用于跟api-server认证。
(2)RBAC授权:权限、角色和角色绑定都是kubernetes自动创建好的,开发者只需要创建一个名为kube-dns的ServiceAccount即可,官方现有的配置已经将它包含进去了。

准备配置文件

我们只需在官方的基础上,通过更改或者添加变量,然后就能生成适合我们集群的配置:

1
2
$ cd /home/envy/kubernetes-starter
$ vimdiff kubernetes-simple/services/kube-dns.yaml kubernetes-with-ca/services/kube-dns.yaml

通过对比可以知道,新的配置文件中去掉了kube-master-url=http://{{MASTER_IP}}:8080这一项,这是用于访问kube-apiserver的地址。你可能有一个疑问,不设置api-server的地址,那它是怎么知道每个服务的CLUSTER_IP和pod的ENDPOINTS的呢?这是因为Kubernetes在启动每个服务Service时,会以环境变量的方式将所有服务的ip、端口等信息注入进来。

创建kube-dns

1
2
3
$ kubectl create -f /home/envy/kubernetes-starter/target/services/kube-dns.yaml
#看看启动是否成功
$ kubectl -n kube-system get pods

如果出现如下所示的信息,则说明kube-dns已经改造成功了:

1
2
3
[root@server02 ~]# kubectl -n kube-system get pods
NAME READY STATUS RESTARTS AGE
kube-dns-795f5f6f9c-fn5kp 3/3 Running 3 2m

那么这样安全版的Kubernetes集群我们就部署完成了,接下来我们就是学习如何使用它,以及如何在里面部署我们的微服务。