Kubernetes 作为一个分布式集群的管理工具,保证集群的安全性是其一个重要的任务。API Server 是所有服务访问统一入口,所有的组件都只和APIServer交互,除此之外并不两两交互,因此API Server 是集群内部各个组件通信的中介,也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。
Kubernetes 使用了认证(Authentication)、鉴权(Authorization)、准入控制(Admission
**Control)**三步来保证 API Server 的安全
k8s 采用的就是 HTTPS
的双向认证方式:
需要认证的组件分两种类型:
端口访问说明:
kubeconfig 是一个文件类型,文件包含集群参数(CA证书、API Server地址),客户端参数(为某个用户生成的证书和私钥),集群 context 信息(集群名称、用户名),可以理解为一个认证函,里面包含了怎么访问服务的信息以及认证信息。Kubenetes 组件(CM、Scheduler、kubectl)通过启动时指定一个 kubeconfig 文件来确定操作哪一个集群以及操作权限,以及访问API Server的证书等。
查看主节点下的 ~/.kube/config
的文件:
$ ls ~/.kube
cache
config:kubeconfig文件
http-cache
项目中通常有多个k8s集群,也就是环境/上下文:dev、testing、staging、prod,kubectl在多个环境中切换,操作Pod等资源对象。
Service Account
用来访问 Kubernetes API
,由 Kubernetes
自动创建,并且会自动挂载到 Pod
的 /run/secrets/kubernetes.io/serviceaccount
目录中。并不是所有的Pod都能访问Kubernetes API,只有拥有Service Account的Pod才能访问。
# 1. 随便找一个需要访问 Kubernetes API 的 Pod
$ kubectl get pod -n kube-system
NAME READY STATUS RESTARTS AGE
kube-proxy-2pqkk 1/1 Running 6 40d
# 2. 查看该 Pod 中 /run/secrets/kubernetes.io/serviceaccount 目录下的文件
$ kubectl exec kube-proxy-2pqkk -n kube-system -it -- ls /run/secrets/kubernetes.io/serviceaccount
ca.crt:访问 API Service 时的证书
namespace:名称空间
token:认证的密钥信息
ServiceAccount 中包含三个部分:
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
默认情况下,每个 namespace 都会有一个 ServiceAccount,如果 Pod 在创建时没有指定 ServiceAccount,就会使用 Pod 所属的 namespace 的 ServiceAccount。
序号 | 证书作用 | 类型 |
---|---|---|
1 | etcd节点间通讯的证书 | 服务器和客户端证书(因节点间互相访问) |
2 | etcd向外提供服务使用 | 服务器证书(因被访问) |
3 | apiserver访问etcd使用 | 客户端证书 |
4 | apiserver对外提供服务使用 | 服务器证书 |
5 | kube-controller-manager访问apiserver使用 | 客户端证书 |
6 | kube-scheduler访问 apiserver使用 | 客户端证书 |
7 | kube-proxy访问apiserver使用 | 客户端证书 |
8 | kubelet访问apiserver使用 | 客户端证书 |
9 | kubectl访问apiserver使用 | 客户端证书 |
10 | kubelet对外提供服务使用 | 服务器证书 |
11 | apiserver访问kubelet使用 | 客户端证书 |
12 | kube-controller-manager生成和验证service-accout token的证书 | 并不需要证书,实际上使用的是公钥和私钥,k8s为server accout 生成JWT token,secret将此token加载到pod上,公钥分配到apiserver上用于验证,私钥分配到pod上用于数字签名 |
互联网上的证书需要由权威CA机构签发,同时还要缴纳一笔不菲的费用,但由于Kubernetes目的是要在集群内建立信任体系,因此使用自签CA就足够了。Kubernetes需要一个根CA,集群中的证书(除了kubelet的服务端证书)都需要由该根CA或者基于该CA的中间CA签发。使用kubeadm init
创建控制平面时,kubeadm
会为我们生成根CA,以及相关证书。kubeadm
创建的集群的默认证书存放路径为/etc/kubernetes/pki
:
在**/etc/kubernetes/pki**文件夹下,保存了服务端认证证书的相关文件:
├── admin.conf
├── controller-manager.conf
├── kubelet.conf
├── manifests
│ ├── etcd.yaml
│ ├── kube-apiserver.yaml
│ ├── kube-controller-manager.yaml
├── pki
│ ├── apiserver.crt //apiServer对外提供服务,server证书
│ ├── apiserver.key
│ ├── apiserver-etcd-client.crt //apiServer请求etcd服务,client证书
│ ├── apiserver-etcd-client.key
│ ├── apiserver-kubelet-client.crt //apiServer请求kubelet,client证书
│ ├── apiserver-kubelet-client.key
│ ├── ca.crt //根证书
│ ├── ca.key //根证书私钥
│ ├── etcd
│ │ ├── ca.crt //etcd根证书
│ │ ├── ca.key
│ │ ├── healthcheck-client.crt
│ │ ├── healthcheck-client.key
│ │ ├── peer.crt //etcd各节点通信peer证书,server/client证书
│ │ ├── peer.key
│ │ ├── server.crt //etcd对外提供服务,server证书
│ │ └── server.key
│ ├── front-proxy-ca.crt //用于前端代理证书
│ ├── front-proxy-ca.key
│ ├── front-proxy-client.crt
│ ├── front-proxy-client.key
│ ├── sa.key //用来生成sa的私钥和公钥,并不需要证书
│ └── sa.pub
├── scheduler.conf
└── tmp [error opening dir]
根CA需要在集群中所有的节点上都保存一份,因为集群的各组件都需要使用该CA证书来验证证书签名。
当然,除了这些证书外,还有kublet、 kube-proxy、 kube-controller-manager、kube-scheduler、kubectl访问apiserver的证书。
(1)kubelet
访问kube-apiserver
时需要带上客户端证书(TLS双向校验),证书的默认保存路径为/var/lib/kubelet/pki
:
[root@master-1 ~]# ls -lh /var/lib/kubelet/pki
总用量 12K
-rw-------. 1 root root 2.7K 9月 8 22:59 kubelet-client-2022-08-08-22-59-01.pem
lrwxrwxrwx. 1 root root 59 9月 8 22:59 kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2022-08-08-22-59-01.pem
-rw-r--r--. 1 root root 2.2K 9月 8 22:58 kubelet.crt
-rw-------. 1 root root 1.7K 9月 8 22:58 kubelet.key
其中kubelet-client-2022-08-08-22-59-01.pem
表示的是客户端证书,kubelet-client-current.pem
是证书的一个软链接。证书之所以带日期是因为kubelet
的证书快过期时会自动更新,因此带上时间方便区分新旧证书。查看一下证书信息:
[root@master-1 ~]# openssl x509 -noout -text -in /var/lib/kubelet/pki/kubelet-client-current.pem
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 7265397798501666783 (0x64d3e0cdd398cfdf)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=kubernetes
Validity
Not Before: Sep 8 14:58:50 2021 GMT
Not After : Sep 8 14:58:55 2022 GMT
Subject: O=system:nodes, CN=system:node:master-1 # O表示Organization, CN表示Common Name
Subject Public Key Info:
...
可以看到kubelet
的用户组是system:nodes
, 用户名为system:node:master-1
。有了这些信息,kube-apiserver
就可以基于Node Authorizer来限制kubelet
只能读取和修改本节点上的资源。
(2)类似的,kube-apiserver
调用kubelet
接口时(执行exec/logs命令),kubelet
也会要求校验kube-apiserver
的客户端证书,该证书保存路径为/etc/kubernetes/pki/apiserver-kubelet-client.crt
。查看一下证书信息:
[root@master-1 ~]# openssl x509 -noout -text -in /etc/kubernetes/pki/apiserver-kubelet-client.crt
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 5903840273946896753 (0x51eea773033fe971)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=kubernetes
Validity
Not Before: Sep 8 14:58:50 2021 GMT
Not After : Oct 5 12:36:44 2022 GMT
Subject: O=system:masters, CN=kube-apiserver-kubelet-client
....
该证书的用户组是system:masters
,这是Kubernetes内置的用户组,Kubernetes会自动为该用户组绑定集群管理员权限。
# ClusterRole/cluster-admin 包含了所有操作权限,当kube-apiserver启动时,会自动将该权限绑定给system:masters用户组。
[root@master-1 ~]# kubectl get clusterRoleBinding cluster-admin -owide
NAME ROLE AGE USERS GROUPS SERVICEACCOUNTS
cluster-admin ClusterRole/cluster-admin 27d system:masters
kube-controller-manager
和kube-scheduler
访问kube-apiserver
时也需要带上客户端证书,它们的客户端证书都保存在各自的kubeconfig
凭证中。
[root@master-1 ~]# ls -ls /etc/kubernetes/controller-manager.conf /etc/kubernetes/scheduler.conf
8 -rw-------. 1 root root 5486 10月 5 20:36 /etc/kubernetes/controller-manager.conf
8 -rw-------. 1 root root 5438 10月 5 20:36 /etc/kubernetes/scheduler.conf
查看证书内容,会发现kube-controller-manager
的用户名为system:kube-controller-manager
,kube-scheduler
的用户名为system:scheduler
。即使是内部组件,基于最小权限原则,Kubernetes依然会为这两个用户只绑定必要的权限。
#生成 kube-controller-manager.kubeconfig 文件
##查看,文件里会有密钥,这里忽略,server: 地址就是k8s master 地址
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: =
server: https://192.168.100.170:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kube-scheduler
namespace: default
current-context: default
kind: Config
preferences: {}
users:
- name: kube-scheduler
user:
client-certificate-data:
client-key-data: =
👉 可以看看二进制部署K8S中的kube-scheduler:5、二进制安装K8s 之 部署kube-scheduler - 小兔几白又白 - 博客园 (cnblogs.com)
kube-proxy默认使用的是admin集群证书,类似,也是保存在在kubeconfig中。当kube-proxy启动的时候就会运行该配置:/etc/kubernetes/kube-proxy.kubeconfig。(我也不知道对不对,没有具体实验)
也可以为kube-proxy手动创建一个kubeconfig:修复kube-proxy证书权限过大问题 - 掘金 (juejin.cn)
apiVersion: v1
clusters:
- cluster:
certificate-authority: ssl/ca.pem
server: https://192.168.1.71:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kube-proxy
namespace: default
current-context: default
kind: Config
preferences: {}
users:
- name: kube-proxy
user:
as-user-extra: {}
client-certificate: ssl/kube-proxy-1-71.pem
client-key: ssl/kube-proxy-1-71.key
kubectl的证书比较特别,当我们使用kubectl
访问kube-apiserver
时,也要提供客户端证书。kubectl
使用的客户端证书存放在kubeconfig
中:
[root@master-1 ~]# cat ~/.kube/config
apiVersion: v1
clusters:
- cluster:
certificate-authority-data: <表示CA证书,很长的一段base64编码> ①
server: https://192.168.33.220:6443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: kubernetes-admin
name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
user:
client-certificate-data: <表示客户端证书,很长的一段base64编码> ②
client-key-data: <表示客户端证书私钥,很长的一段base64编码>
由于是自签CA,所以kubeconfig
里也要保存根CA的证书(certificate-authority-data
),用于校验kube-apiserver
的服务端证书;
客户端证书使用base64编码后保存在client-certificate-data
字段中。查看一下客户端证书部分:
[root@master-1 ~]# grep "client-certificate-data" ~/.kube/config \
| sed 's/\s*client-certificate-data:\s*//' \
| base64 -d | openssl x509 -noout -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 368716738867724927 (0x51df1eba2f3827f)
Signature Algorithm: sha256WithRSAEncryption
Issuer: CN=kubernetes
Validity
Not Before: Sep 8 14:58:50 2021 GMT
Not After : Sep 8 14:58:54 2022 GMT
Subject: O=system:masters, CN=kubernetes-admin # O表示Organization, CN表示Common Name
....
可以看到,该kubeconfig
的用户名为kubernetes-admin
,用户组为system:masters
,即拥有所有权限。示例中的kubeconfig
是kubeadm
默认创建的集群管理员凭证,集群管理员可以通过签发任意的用户组和用户名的证书,制作成kubeconfig
,结合RBAC权限管理来控制权限。
查看SA\CA证书到日期:
openssl x509 -in apiserver.crt -text -noout
openssl x509 -in ca.crt -text -noout
可以看到根证书的有效时间是10年,apiserver证书是1年。
在前面,我们说过,使用kubeadm init
创建控制平面时,kubeadm
会为我们生成根CA,以及相关证书,因此证书时间修改也就四步:
kubeadm是基于go语言编写的,因此要先安装go环境。
(1)go 环境部署
wget https://dl.google.com/go/go1.12.7.linux-amd64.tar.gz
tar -zxvf go1.12.1.linux-amd64.tar.gz -C /usr/local
vi /etc/profile
export PATH=$PATH:/usr/local/go/bin
source /etc/profile
go version
(2)下载源码
cd /data && git clone https://github.com/kubernetes/kubernetes.git
git checkout -b remotes/origin/release-1.15.1 v1.15.1
(3)修改 Kubeadm 源码更新证书策略
vim staging/src/k8s.io/client-go/util/cert/cert.go # kubeadm 1.14 版本之前
vim cmd/kubeadm/app/util/pkiutil/pki_helpers.go # kubeadm 1.14 至今 const duration365d = time.Hour * 24 * 365 * 10 NotAfter:time.Now().Add(duration365d).UTC(),
(4)编译并替换旧的文件
# 保存退出后编译
make WHAT=cmd/kubeadm GOFLAGS=-v
# 备份一下旧的并使用新的
cp output/bin/kubeadm /root/
cp /usr/bin/kubeadm /usr/bin/kubeadm.old
cp /root/kubeadm /usr/bin/
chmod a+X /usr/bin/kubeadm
# 备份一下旧的pki
cd /etc/kubernetes/
cp -r pki/ pki.old
(5)生成所有证书
# 重新生成所有证书文件
kubeadm alpha certs renew all --config=/usr/local/install-k8s/core/kubeadm-config.yaml
(6)查看证书
# 重新查看证书时间
cd /etc/kubernetes/pki
openssl x509 -in apiserver.crt -text -noout # 十年
(7)HA集群其余 mater 节点证书更新
#!/bin/bash
masterNode="192.168.66.20 192.168.66.21"
#for host in ${masterNode}; do
# scp /etc/kubernetes/pki/{ca.crt,ca.key,sa.key,sa.pub,front-proxy-ca.crt,front-proxy-ca.key}
"${USER}"@$host:/etc/kubernetes/pki/
# scp /etc/kubernetes/pki/etcd/{ca.crt,ca.key} "root"@$host:/etc/kubernetes/pki/etcd
# scp /etc/kubernetes/admin.conf "root"@$host:/etc/kubernetes/
#done
for host in ${CONTROL_PLANE_IPS}; do
scp /etc/kubernetes/pki/{ca.crt,ca.key,sa.key,sa.pub,front-proxy-ca.crt,front-proxy-ca.key}
"${USER}"@$host:/root/pki/
scp /etc/kubernetes/pki/etcd/{ca.crt,ca.key} "root"@$host:/root/etcd
scp /etc/kubernetes/admin.conf "root"@$host:/root/kubernetes/
done
上面认证过程,只是确认通信的双方都确认了对方是可信的,可以相互通信。而鉴权是确定请求方有哪些资源的权限。API Server 目前支持以下几种授权策略 (通过 API Server 的启动参数 “–authorization-mode” 设置):
RBAC(Role-Based Access Control)基于角色的访问控制,在 Kubernetes 1.5 中引入,现行版本成为默认标准。相对其它访问控制方式,拥有以下优势:
RBAC 引入了 4 个新的顶级资源对象:Role、ClusterRole、RoleBinding、ClusterRoleBinding,4 种对象类型均可以通过 kubectl 与 API 操作。
需要注意的是 Kubenetes
并不会提供用户管理,那么 User
、Group
、ServiceAccount
指定的用户又是从哪里来的呢? Kubenetes 组件(kubectl、kube-proxy)或是其他自定义的用户在向 CA 申请证书时,需要提供一个json文件:
{
"CN": "admin", # Common Name(CN),公用名,一般是主机名+网站域名
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN", # Country Code(C):国家,只能是两个字母的国家码
"ST": "HangZhou", # State or Province(S),省名或者州名
"L": "XS", # Locality(L),城市名
"O": "system:masters", # Organization Name(O),单位名称
"OU": "System" # Organization Unit(OU),部门
}
]
}
这个json文件会用于生成证书,API Server 会把客户端证书的 CN 字段作为 User,把 names.O 字段作为 Group;
kubelet 使用 TLS Bootstaping 认证时,API Server 可以使用 Bootstrap Tokens 或者 Token authentication file 验证 =token,无论哪一种,Kubenetes 都会为 token 绑定一个默认的 User 和 Group;
Pod 使用 ServiceAccount 认证时,service-account-token 中的 JWT 会保存 User 信息。
有了用户信息,再创建一对 角色/角色绑定(集群角色/集群角色绑定)资源对象,就可以完成权限绑定了。
在 RBAC API 中,Role 表示一组规则权限,权限只会增加(累加权限),不存在一个资源一开始就有很多权限而通过
RBAC 对其进行减少的操作;Role 可以定义在一个 namespace 中,如果想要跨 namespace 则可以创建 ClusterRole
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
namespace: default # 名称空间
name: pod-reader
rules:
- apiGroups: [""] # api组,"" 为空代表的是 core 核心组
resources: ["pods"] # 资源对象
verbs: ["get", "watch", "list"] # 操作动作
ClusterRole 具有与 Role 相同的权限角色控制能力,不同的是 ClusterRole 是集群级别的,ClusterRole 可以用
于:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: secret-reader
rules:
- apiGroups: [""] # api 组
resources: ["secrets"] # 资源对象
verbs: ["get", "watch", "list"] # 操作动作
Kubernetes 集群内一些资源一般以其名称字符串来表示,这些字符串一般会在 API 的 URL 地址中出现;同时某些资源也会包含子资源,例如 logs 资源就属于 pods 的子资源,API 中 URL 样例如下:
GET /api/v1/namespaces/{namespace}/pods/{name}/log
如果要在 RBAC 授权模型中控制这些子资源的访问权限,可以通过 / 分隔符来实现,以下是一个定义 pods 资源 logs 访问权限的 Role 定义样例
kind: Role
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
namespace: default
name: pod-and-pod-logs-reader
rules:
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
RoloBinding 可以将角色中定义的权限授予用户或用户组,RoleBinding 包含一组权限列表(subjects),权限列表中包含有不同形式的待授予权限资源类型(users, groups, SA);RoloBinding 同样包含对被 Bind 的 Role 引用;RoleBinding 适用于某个命名空间内授权,而 ClusterRoleBinding 适用于集群范围内的授权。
将 default 命名空间的 pod-reader Role 授予 jane 用户,此后 jane 用户在 default 命名空间中将具有 pod-reader 的权限:
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-pods
namespace: default # 名称空间
subjects: # 权限列表
- kind: User # User 类型
name: jane # 用户名
apiGroup: rbac.authorization.k8s.io # api 组
roleRef: # 角色
kind: Role # 类型
name: pod-reader # Role 名字
apiGroup: rbac.authorization.k8s.io # api组
RoleBinding 同样可以引用 ClusterRole 来对当前 namespace 内用户、用户组或 ServiceAccount 进行授权,这种操作允许集群管理员在整个集群内定义一些通用的 ClusterRole,然后在不同的 namespace 中使用 RoleBinding 来引用
例如,以下 RoleBinding 引用了一个 ClusterRole,这个 ClusterRole 具有整个集群内对 secrets 的访问权限;但是其授权用户 dave 只能访问 development 空间中的 secrets(因为 RoleBinding 定义在 development 命名空间):
kind: RoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-secrets
namespace: development # 名称空间,只授予 development 名称空间内的权限
subjects:
- kind: User
name: dave
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: secret-reader
apiGroup: rbac.authorization.k8s.io
使用 ClusterRoleBinding
可以对整个集群中的所有命名空间资源权限进行授权;以下 ClusterRoleBinding
样例展示了授权 manager
组内所有用户在全部命名空间中对 secrets
进行访问:
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: read-secrets-global
subjects:
- kind: Group # 绑定给一个组
name: manager # 组名
apiGroup: rbac.authorization.k8s.io # api接口
roleRef:
kind: ClusterRole # ClusterRole
name: secret-reader # 名称
apiGroup: rbac.authorization.k8s.io # api接口
RoleBinding 和 ClusterRoleBinding 可以将 Role 绑定到 Subjects;Subjects 可以是 groups、users 或者 service accounts。
Subjects 中 Users 使用字符串表示,它可以是一个普通的名字字符串,如 “alice”;也可以是 email 格式的邮箱地址,如 “xxx@163.com”;甚至是一组字符串形式的数字 ID 。但是 Users 的前缀 system: 是系统保留的,集群管理员应该确保普通用户不会使用这个前缀格式。(比如kubelet就是属于system:node组,名字可以是system.node:master-1)
Groups 书写格式与 Users 相同,都为一个字符串,并且没有特定的格式要求;同样 system: 前缀为系统保留。
准入控制是 API Server 的插件集合,通过添加不同的插件,实现额外的准入控制规则。甚至于 API Server 的一些主要的功能都需要通过 Admission Controllers 实现,比如 ServiceAccount。
官方文档上有一份针对不同版本的准入控制器推荐列表,其中最新的 1.16 的推荐列表是:
NamespaceLifecycle, LimitRanger, ServiceAccount, TaintNodesByCondition, Priority, DefaultTolerationSeconds,
DefaultStorageClass, StorageObjectInUseProtection, PersistentVolumeClaimResize, MutatingAdmissionWebhook,
ValidatingAdmissionWebhook, RuntimeClass, ResourceQuota
列举几个插件的功能:
操作:
启用 NamespaceLifecycle 和 LimitRanger 准入控制插件:
kube-apiserver --enable-admission-plugins=NamespaceLifecycle,LimitRanger
禁用插件:
kube-apiserver --disable-admission-plugins=PodNodeSelector,AlwaysDeny ...
查看默认启用的插件:
kube-apiserver -h | grep enable-admission-plugins
主要就是两步:
useradd devuser
passwd devuser
(1)创建一个证书请求json文件:
$ vim /home/userdev/cert/devuser-csr.json
{
"CN": "devuser",
"hosts": [],
"key": {
"algo": "rsa",
"size": 2048
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s", # 组名
"OU": "System"
}]
}
names
:一些其它的属性:
(2)生成该用户的证书和私钥(使用cfssl工具):
# 1. 下载证书生成工具
wget https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
mv cfssl_linux-amd64 /usr/local/bin/cfssl
wget https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
mv cfssljson_linux-amd64 /usr/local/bin/cfssljson
wget https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
mv cfssl-certinfo_linux-amd64 /usr/local/bin/cfssl-certinfo
chmod a+x /usr/local/bin/cfssl*
# 2. 生成证书
$ cd /etc/kubernetes/pki
$ cfssl gencert -ca=ca.crt -ca-key=ca.key -profile=kubernetes /home/devuser/cert/devuser-csr.json | cfssljson -bare devuser
# 查看生成的证书
$ ll dev*
-rw-r--r-- 1 root root 997 11月 17 19:53 devuser.csr
-rw------- 1 root root 1679 11月 17 19:53 devuser-key.pem
-rw-r--r-- 1 root root 1237 11月 17 19:53 devuser.pem
cfssl gencert
: 生成新的 key (密钥)和签名证书
-ca
:指明 ca 的证书-ca-key
:指明 ca 的私钥文件-profile
:根据 config 中的 profile 段来生成证书的相关信息-bare
:指定文件名ca.crt和ca.key证书是服务器的根证书和私钥,使用kubeadm init
创建控制平面时,kubeadm
会为我们生成根CA,以及相关证书,保存在 /etc/kubernetes/pki文件夹下。
生成了三个文件,分别是:证书、私钥、证书的pem格式。
(1)在 devuser home目录中创建 .kube
目录(config
文件一般是放在 ~/.kube
目录中的)
mkdir /home/devuser/.kube
cd /home/devuser/.kube
(2)设置集群参数:
export KUBE_APISERVER="https://192.168.66.10:6443"
kubectl config set-cluster kubernetes \
--certificate-authority=/etc/kubernetes/pki/ca.crt \
--embed-certs=true \
--server=${KUBE_APISERVER} \
--kubeconfig=config
(3)设置客户端认证参数:
kubectl config set-credentials devuser \
--client-certificate=/etc/kubernetes/pki/devuser.pem \
--client-key=/etc/kubernetes/pki/devuser-key.pem \
--embed-certs=true \
--kubeconfig=config
devuser
:证书的用户名--client-certificate
:指定客户端证书--client-key
:指定客户端私钥--embed-certs
:是否开启证书认证--kubeconfig
:写入的文件,与上面相同,写入同一个文件(4)设置上下文参数:
# 1. 创建 dev 的名称空间
kubectl create namespace dev
# 2. 设置上下文参数
kubectl config set-context kubernetes \
--cluster=kubernetes \
--user=devuser \
--namespace=dev \
--kubeconfig=config
kubernetes
:Context 的名字--cluster
:指定集群名称--user
:指定用户名--namespace
:绑定到某个名称空间--kubeconfig
:写入的文件,与上面相同,写入同一个文件(5)更改 config 文件所属的用户和组(都是devuser):
chown devuser:devuser /home/devuser/.kube/config
(6)查看 config 文件:
apiVersion: v1
clusters: # 配置kubernetes集群
- cluster:
certificate-authority-data: ...
server: https://192.168.66.10:6443
name: kubernetes
contexts: # 配置访问kubernetes集群的具体上下文环境
- context:
cluster: kubernetes
namespace: dev
user: devuser
name: kubernetes
current-context: "" # 配置当前使用的上下文环境
kind: Config
preferences: {}
users: # 配置访问的用户信息,用户名以及证书信息
- name: devuser
user:
client-certificate-data: ...
client-key-data: ...
创建 RoleBinding
给 devuser
赋予权限:
kubectl create rolebinding devuser-admin-binding --clusterrole=admin --user=devuser --namespace=dev
切换上下文也就是让 kubectl
读取到 config
中的配置信息:
kubectl config use-context kubernetes --kubeconfig=config
current-context
为 kubernetes
--kubeconfig
:指定 kubeconfig
文件以springboot为例:
(1)注入依赖:
<dependency>
<groupId>io.fabric8groupId>
<artifactId>kubernetes-clientartifactId>
<version>4.0.0version>
dependency>
(2)配置yml文件,指明根证书、客户端证书、客户端私钥:
(3)K8S初始化:
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.ConfigBuilder;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* k8s初始化
*/
@Component
public class K8sInit {
/**
* 连接地址
*/
@Value("${k8s.server}")
private String apiHttps;
/**
* 安全证书相关
*/
@Value("${k8s.certificate-authority-data}")
private String caCert;
@Value("${k8s.client-certificate-data}")
private String clientCert;
@Value("${k8s.client-key-data}")
private String clientKey;
/**
*
* k8s初始化
* @return
*/
public KubernetesClient getFabric8Connection() {
Config config = new ConfigBuilder().withMasterUrl(apiHttps).withTrustCerts(true)
.withCaCertData(caCert)
.withClientCertData(clientCert)
.withClientKeyData(clientKey)
.build();
KubernetesClient kubernetesClient = new DefaultKubernetesClient(config);
return kubernetesClient;
}
}
(4)具体操作
import io.fabric8.kubernetes.api.model.PodList;
/**
* pod服务
*/
public interface PodService {
/**
* nameSpace不为空,获取指定命名空间下pod列表;nameSpace为空,获取所有
* @param nameSpace
* @return
*/
public PodList getPodListByNamespace(String nameSpace);
}
import io.fabric8.kubernetes.api.model.PodList;
import io.fabric8.kubernetes.client.KubernetesClient;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* pod服务实现
*/
@Service
public class PodServiceImpl implements PodService {
@Autowired
private K8sInit k8sInit;
/**
* nameSpace不为空,获取指定命名空间下pod列表;nameSpace为空,获取所有
*
* @param nameSpace
* @return
*/
@Override
public PodList getPodListByNamespace(String nameSpace) {
KubernetesClient kubernetesClient = k8sInit.getFabric8Connection();
PodList podList = new PodList();
if(StringUtils.isNotBlank(nameSpace)){
podList = kubernetesClient.pods().inNamespace(nameSpace).list();
}else {
podList = kubernetesClient.pods().list();
}
return podList;
}
}