基于证书签名请求快速构建kubeconfig

概述

Kubernetes 提供 certificates.k8s.io API,可让你配置由你控制的证书颁发机构(CA) 签名的 TLS 证书。 你的工作负载可以使用这些 CA 和证书来建立信任。

请求签名流程

CertificateSigningRequest 资源类型允许客户使用它申请发放 X.509 证书。

首先我们需要创建一个CSR证书请求文件,并通过CertificateSigningRequest资源对象的spec.request提交到k8s中。

创建完成的CertificateSigningRequest,要先通过批准,然后才能签名。这里会根据 spec.signerName 字段所选的签名者自动或者人工批准,人工批准的话需要手动执行kube certificate approve命令,本文也是采用的这种方法。同样我们也可以驳回证书签名请求。

对于已批准的证书会通过证书签名控制器自动创建证书并更新到CertificateSigningRequest资源对象的status.certificate 字段中。如果不满足签名条件或者驳回的话,这个字段就会一直为空。

注意:为了减少集群中遗留的过时的 CertificateSigningRequest 资源的数量, 垃圾收集控制器将会周期性地运行。 此垃圾收集器会清除在一段时间内没有改变过状态的 CertificateSigningRequests:

  • 已批准的请求:1小时后自动删除
  • 已拒绝的请求:1小时后自动删除
  • 已失败的请求:1小时后自动删除
  • 挂起的请求:24小时后自动删除
  • 所有请求:在颁发的证书过期后自动删除

具体操作

创建密钥

基于openssl生成PKI私钥和CSR证书请求

1
2
openssl genrsa -out zerchin.key 2048
openssl req -new -key zerchin.key -out zerchin.csr

其中,CN 是用户名,O 是该用户归属的组。如下:

1
2
Organization Name (eg, company) [Default Company Ltd]:rancher
Common Name (eg, your name or your server's hostname) []:zerchin

获取CSR文件的base64编码

1
cat zerchin.csr | base64 | tr -d "\n"

创建CertificateSigningRequest

1
2
3
4
5
6
7
8
9
10
11
12
cat << EOF > certificateSigningRequest.yaml
apiVersion: certificates.k8s.io/v1
kind: CertificateSigningRequest
metadata:
name: zerchin
spec:
request: `cat zerchin.csr | base64 | tr -d "\n"`
signerName: kubernetes.io/kube-apiserver-client
expirationSeconds: 86400 # one day
usages:
- client auth
EOF

其中:

signerName:Kubernetes提供了四种内置的签名者,这里我们使用kubernetes.io/kube-apiserver-client,签名的证书被apiserver视为客户证书。

expirationSeconds:过期时间,这个过期时间指的是签发等待的时间,过了这个时间就不能签发了,可以重新再次发起。该参数在 k8s 1.22+ 版本支持,低于此版本可以去掉这个参数。

usages:必须是client auth

request:是CSR文件内容的base64 编码值。

批准证书签名请求

获取CSR列表

1
2
3
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
zerchin 14s kubernetes.io/kube-apiserver-client user-vmhf2 Pending

获取证书签名请求列表

1
2
3
$ kubectl get certificatesigningrequests.certificates.k8s.io 
NAME AGE SIGNERNAME REQUESTOR CONDITION
zerchin 9s kubernetes.io/kube-apiserver-client user-vmhf2 Pending

批准CSR

1
2
$ kubectl certificate approve zerchin
certificatesigningrequest.certificates.k8s.io/zerchin approved

查看csr和certificate的状态,一定要有ApprovedIssued两个状态

1
2
3
4
5
6
$ kubectl get csr
NAME AGE SIGNERNAME REQUESTOR CONDITION
zerchin 52s kubernetes.io/kube-apiserver-client user-vmhf2 Approved,Issued
$ kubectl get certificatesigningrequests.certificates.k8s.io
NAME AGE SIGNERNAME REQUESTOR CONDITION
zerchin 56s kubernetes.io/kube-apiserver-client user-vmhf2 Approved,Issued

从CertificateSigningRequest中导出颁发的证书

证书的内容使用 base64 编码,存放在字段 status.certificate

1
kubectl get csr zerchin -o jsonpath='{.status.certificate}'| base64 -d > zerchin.crt

构建kubeconfig文件

新建一个kubeconfig文件

1
touch zerchin-kubeconfig

设置k8s集群

1
2
$ kubectl --kubeconfig zerchin-kubeconfig config set-cluster k8s --server=https://192.168.2.12:6443 --certificate-authority=/etc/kubernetes/ssl/kube-ca.pem --embed-certs=true
Cluster "k8s" set.

设置用户

1
2
$ kubectl --kubeconfig zerchin-kubeconfig config set-credentials zerchin --client-key=./zerchin.key --client-certificate=./zerchin.crt --embed-certs=true
User "zerchin" set.

设置context

1
2
$ kubectl --kubeconfig zerchin-kubeconfig config set-context zerchin --cluster=k8s --user=zerchin 
Context "zerchin" created.

切换context

1
2
$ kubectl --kubeconfig zerchin-kubeconfig config use-context zerchin
Switched to context "zerchin".

创建角色并绑定到该用户上

创建role

1
2
$ kubectl create role zerchin-role --verb=create --verb=get --verb=list --verb=update --verb=delete --resource=pods
role.rbac.authorization.k8s.io/zerchin-role created

创建rolebinding

1
2
$ kubectl create rolebinding zerchin-role-binding --role=zerchin-role --user=zerchin
rolebinding.rbac.authorization.k8s.io/zerchin-role-binding created

验证

执行kubectl命令进行验证,首先验证一下pod的权限

1
2
3
4
$ kubectl --kubeconfig zerchin-kubeconfig get pods
NAME READY STATUS RESTARTS AGE
test-776cfb6994-9rhbx 1/1 Running 0 22h
test-776cfb6994-g6xfh 1/1 Running 0 22h

看一下node的权限

1
2
$ kubectl --kubeconfig zerchin-kubeconfig get nodes
Error from server (Forbidden): nodes is forbidden: User "zerchin" cannot list resource "nodes" in API group "" at the cluster scope

可以看到,我们可以正常执行kubectl命令去查看pod,但是没有其他资源的权限,验证成功。

可能遇到的问题

  1. 批准CSR之后,如果无法从CertificateSigningRequest中导出颁发的证书(.status.certificate路径不存在),并且执行kubectl get csr查看只有一个Approved状态,没有Issued状态,那么大概率是controller-manager没有挂载CA证书进来,需要先挂载进来后再次签发。

    Rancher/RKE集群可以参考这个如下配置添加CA证书挂载,编辑cluster.yml文件,在kube-controller下添加此配置参数:

1
2
3
4
5
services:
kube-controller:
extra_args:
cluster-signing-cert-file: "/etc/kubernetes/ssl/kube-ca.pem"
cluster-signing-key-file: "/etc/kubernetes/ssl/kube-ca-key.pem"

参考文档:

https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/certificate-signing-requests/

https://kubernetes.io/zh-cn/docs/tasks/tls/managing-tls-in-a-cluster/