使用场景
当我们需要进行服务端认证,甚至双向认证时,我们需要生成密钥对和服务信息,并使用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": "kubernetes",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "CN",
"ST": "BeiJing",
"L": "BeiJing",
"O": "k8s",
"OU": "System"
}
]
}
EOF
这里你可以修改文件里的内容,主要是:
- hosts。 服务地址,你可以填入service的域名,service的clusterIP,podIP等等
- CN 。对于 SSL 证书,一般为网站域名;而对于代码签名证书则为申请单位名称;而对于客户端证书则为证书申请者的姓名.k8s会将
CN
的内容视为正式使用者的User Name
- key。加密算法和长度。一般有
ecdsa
算法和rsa
算法,rsa
算法的size一般是2048或1024 - names。证书申请者的信息,比如位置、组织等。k8s的RBAC会将证书中的
O
视为证书使用者所在的Group
这一步生成的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服务配置
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。