共计 2742 个字符,预计需要花费 7 分钟才能阅读完成。
使用场景
当我们需要进行服务端认证,甚至双向认证时,我们需要生成密钥对和服务信息,并使用 ca 对公钥和服务信息进行批准签发,生成一个证书。
我们简单描述下单向认证和双向认证的场景流程
在单向认证场景中:
- 服务端会将自己的证书和公钥告知客户端
- 客户端向 CA 查询该证书的合法性,确认合法后会记录服务端公钥
- 客户端会与服务端明文通信确认加密方式,
- 客户端确认加密方式后,会生成随机码作为对称加密密钥,以服务端的公钥对对称加密密钥进行加密,告知服务端,
- 服务端以自己的私钥解密得到对称加密密钥,
- 之后,客户端与服务端之间使用对称加密密钥进行加密通信。
在双向认证的场景中:
- 服务端会将自己的证书和公钥告知客户端
- 客户端向 CA 查询该证书的合法性,确认合法后会记录服务端公钥
- 客户端会将自己的证书和公钥发给服务端,
- 服务端发现客户端的证书也可以通过 CA 认证,则服务端会记录客户端的公钥
- 然后客户端会与服务端明文通信确认加密方式,
- 但服务端会用客户端的公钥将加密方式进行加密
- 客户端使用自己的私钥解密得到加密方式,会生成随机码作为对称加密密钥,以服务端的公钥对对称加密密钥进行加密,告知服务端,
- 服务端以自己的私钥解密得到对称加密密钥,
- 之后,客户端与服务端之间使用对称加密密钥进行加密通信。
那么,我们如果要开放自己的 https 服务,或者给 kubelet 创建可用的客户端证书,就需要:
- 生成密钥对
- 生成使用方的信息
- 使用 ca 对使用方的公钥和其他信息进行审核,签发,生成一个使用方证书。
这里使用方可以是客户端(kubelet)或服务端(比如一个我们自己开发的 webhook server)
手动签发证书
k8s 集群部署时会自动生成一个 CA(证书认证机构),当然这个 CA 是我们自动生成的,并不具有任何合法性。k8s 还提供了一套 api,用于对用户自主创建的证书进行认证签发。
准备
- 安装 k8s 集群
- 安装 cfssl 工具,从这里下载 cfssl 和 cfssljson
创建你的证书
执行下面的命令,生成 server.csr 和 server-key.pem。
cat <<EOF | cfssl genkey - | cfssljson -bare server
{
"hosts": [
"my-svc.my-namespace.svc.cluster.local",
"my-pod.my-namespace.pod.cluster.local",
"192.0.2.24",
"10.0.34.2"
],
"CN": "my-pod.my-namespace.pod.cluster.local",
"key": {
"algo": "ecdsa",
"size": 256
}
}
EOF
这里你可以修改文件里的内容,主要是:
- hosts。服务地址,你可以填入 service 的域名,service 的 clusterIP,podIP 等等
- CN。对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端证书则为证书申请者的姓名
- key。加密算法和长度。一般有
ecdsa
算法和rsa
算法,rsa
算法的 size 一般是 2048 或 1024
这一步生成的 server-key.pem 是服务端的私钥,而 server.csr 则含有公钥、组织信息、个人信息(域名)。
创建一个 CSR 资源
执行如下脚本:
cat <<EOF | kubectl apply -f -
apiVersion: certificates.k8s.io/v1beta1
kind: CertificateSigningRequest
metadata:
name: my-svc.my-namespace
spec:
request: $(cat server.csr | base64 | tr -d '\n')
usages:
- digital signature
- key encipherment
- server auth
EOF
在 k8s 集群中创建一个 csr 资源。注意要将第一步中创建的 server.csr 内容进行 base64 编码,去掉换行后填入 spec.request
中。spec.usages
中填入我们对证书的要求,包括数字签名、密钥加密、服务器验证。一般填这三个就够了。
之后我们通过kubectl describe csr my-svc.my-namespace
可以看到:
Name: my-svc.my-namespace
Labels: <none>
Annotations: <none>
CreationTimestamp: Tue, 21 Mar 2017 07:03:51 -0700
Requesting User: yourname@example.com
Status: Pending
Subject:
Common Name: my-svc.my-namespace.svc.cluster.local
Serial Number:
Subject Alternative Names:
DNS Names: my-svc.my-namespace.svc.cluster.local
IP Addresses: 192.0.2.24
10.0.34.2
Events: <none>
认证 csr
注意到,csr 的 status 是 pending,说明还没有被 CA 认证。在 k8s 集群中,如果是 node 上 kubelet 创建的 CSR,kube-controller-manager 会自动进行认证,而我们手动创建的证书,需要进行手动认证:kubectl certificate approve
也可以拒绝:kubectl certificate deny
之后我们再检查 csr, 发现已经是 approved 了:
kubectl get csr
NAME AGE REQUESTOR CONDITION
my-svc.my-namespace 10m yourname@example.com Approved,Issued
我们可以通过
kubectl get csr my-svc.my-namespace -o jsonpath='{.status.certificate}' | base64 --decode > server.crt
命令,得到 server 的证书。之后你就可以使用 server.crt 和 server-key.pem 作为你的服务的 https 认证
流程总结
- 编写一个 json 文件,描述 server 的信息,包括域名(或 IP),CN,加密方式
- 执行 cfssl 命令生成 server 的密钥,和认证请求文件 server.csr
- 将 server.csr 内容编码,在 k8s 中创建一个 server 的 CSR 资源
- 手动对该 CSR 资源进行认证签发
- 将 k8s 生成的 server.crt 即服务端证书拷贝下来。
- server.crt 和 server-key.pem 即 server 的 https 服务配置
参考:https://kubernetes.io/docs/ta…