巧用 CFSSL 管理 Kubernetes 集群证书,


 

熟悉HTTP、HTTPS、SSL、TLS

HTTP 是一个网络协议,是专门用来传输 Web 内容,大部分网站都是通过 HTTP 协议来传输 Web 页面、以及 Web 页面上包含的各种东东(图片、CSS 样式、JS 脚本)。

SSL 是Secure Sockets Layer的缩写,中文叫做“安全套接层”。它是在上世纪90年代中期,由网景公司设计的。(顺便插一句,网景公司不光发明了 SSL,还发明了很多 Web 的基础设施——比如CSS 样式表和JS 脚本),为啥要发明 SSL 这个协议捏?因为原先互联网上使用的 HTTP 协议是明文的,存在很多缺点——比如传输内容会被偷窥(嗅探)和篡改。发明 SSL 协议,就是为了解决这些问题。

TLS是 SSL的 标准化,SSL标准化之后的名称改为 TLS(是Transport Layer Security的缩写),中文叫做传输层安全协议。很多相关的文章都把这两者并列称呼(SSL/TLS),因为这两者可以视作同一个东西的不同阶段。

HTTPS 协议,说白了就是“HTTP 协议”和“SSL/TLS 协议”的组合。你可以把 HTTPS 大致理解为——HTTP over SSL或HTTP over TLS。

CA认证的原理

通过下面介绍信的描述介绍CA的原理

◇ 普通的介绍信

想必大伙儿都听说过介绍信的例子吧?假设 A 公司的张三先生要到 B 公司去拜访,但是 B 公司的所有人都不认识他,他咋办捏?常用的办法是带公司开的一张介绍信,在信中说:兹有张三先生前往贵公司办理业务,请给予接洽......云云。然后在信上敲上A公司的公章。

张三先生到了 B 公司后,把介绍信递给 B 公司的前台李四小姐。李小姐一看介绍信上有 A 公司的公章,而且 A 公司是经常和 B 公司有业务往来的,这位李小姐就相信张先生不是歹人了。

这里,A公司就是CA证书

◇ 引入中介机构的介绍信

好,回到刚才的话题。如果和 B 公司有业务往来的公司很多,每个公司的公章都不同,那前台就要懂得分辨各种公章,非常滴麻烦。所以,有某个中介公司 C,发现了这个商机。C公司专门开设了一项“代理公章”的业务。

今后,A 公司的业务员去 B 公司,需要带2个介绍信:

介绍信1:含有 C 公司的公章及 A 公司的公章。并且特地注明:C 公司信任 A 公司。

介绍信2:仅含有 A 公司的公章,然后写上:兹有张三先生前往贵公司办理业务,请给予接洽......云云。

某些不开窍的同学会问了,这样不是增加麻烦了吗?有啥好处捏?

主要的好处在于,对于接待公司的前台,就不需要记住各个公司的公章分别是啥样子的;他/她只要记住中介公司 C 的公章即可。当他/她拿到两份介绍信之后,先对介绍信1的 C 公章,验明正身;确认无误之后,再比对介绍信1和介绍信2的两个 A 公章是否一致。如果是一样的,那就可以证明介绍信2是可以信任的了。

公钥基础设施PKI

CA(Certification Authority)证书,指的是权威机构给我们颁发的证书。

密钥就是用来加解密用的文件或者字符串。密钥在非对称加密的领域里,指的是私钥和公钥,他们总是成对出现,其主要作用是加密和解密。常用的加密强度是2048bit。

RSA即非对称加密算法。非对称加密有两个不一样的密码,一个叫私钥,另一个叫公钥,用其中一个加密的数据只能用另一个密码解开,用自己的都解不了,也就是说用公钥加密的数据只能由私钥解开。

证书的编码格式

PEM(Privacy Enhanced Mail),通常用于数字证书认证机构(Certificate Authorities,CA),扩展名为.pem, .crt, .cer, 和 .key。内容为Base64编码的ASCII码文件,有类似的头尾标记服务器认证证书。

  1. "-----BEGIN CERTIFICATE-----"  
  2. "-----END CERTIFICATE-----" 

中级认证证书和私钥都可以储存为PEM格式(认证证书其实就是公钥)。Apache 和 Nginx 等类似的服务器使用PEM格式证书。

DER(Distinguished Encoding Rules),与 PEM 不同之处在于其使用二进制而不是 Base64 编码的 ASCII。扩展名为.der,但也经常使用.cer用作扩展名,所有类型的认证证书和私钥都可以存储为 DER 格式。Java 使其典型使用平台。

证书签名请求 CSR

CSR(Certificate Signing Request),它是向 CA 机构申请数字 ××× 书时使用的请求文件。在生成请求文件前,我们需要准备一对对称密钥。私钥信息自己保存,请求中会附上公钥信息以及国家,城市,域名,Email 等信息,CSR 中还会附上签名信息。当我们准备好 CSR 文件后就可以提交给CA机构,等待他们给我们签名,签好名后我们会收到 crt 文件,即证书。

注意:CSR 并不是证书。而是向权威证书颁发机构获得签名证书的申请。

把 CSR 交给权威证书颁发机构,权威证书颁发机构对此进行签名,完成。保留好CSR,当权威证书颁发机构颁发的证书过期的时候,你还可以用同样的CSR来申请新的证书, Key 保持不变.

数字签名

数字签名就是"非对称加密+摘要算法",其目的不是为了加密,而是用来防止他人篡改数据。

其核心思想是:比如A要给B发送数据,A先用摘要算法得到数据的指纹,然后用A的私钥加密指纹,加密后的指纹就是A的签名,B收到数据和A的签名后,也用同样的摘要算法计算指纹,然后用A公开的公钥解密签名,比较两个指纹,如果相同,说明数据没有被篡改,确实是A发过来的数据。假设C想改A发给B的数据来欺骗B,因为篡改数据后指纹会变,要想跟A的签名里面的指纹一致,就得改签名,但由于没有A的私钥,所以改不了,如果C用自己的私钥生成一个新的签名,B收到数据后用A的公钥根本就解不开。

常用的摘要算法有MD5、SHA1、SHA256。

使用私钥对需要传输的文本的摘要进行加密,得到的密文即被称为该次传输过程的签名。

数字证书和公钥

数字证书则是由证书认证机构(CA)对证书申请者真实身份验证之后,用CA的根证书对申请人的一些基本信息以及申请人的公钥进行签名(相当于加盖发证书机 构的公章)后形成的一个数字文件。实际上,数字证书就是经过CA认证过的公钥,除了公钥,还有其他的信息,比如Email,国家,城市,域名等。

CFSSL安装及基础知识

cfssl是CloudFlare开源的一款PKI/TLS工具。CFSSL 包含一个命令行工具和一个用于签名、验证并且捆绑TLS证书的HTTP API 服务。使用Go语言编写。

CFSSL包括:

  •   一组用于生成自定义 TLS PKI 的工具
  •  cfssl程序,是cfssl的命令行工具
  •  multirootca程序是可以使用多个签名密钥的证书颁发机构服务器
  •  mkbundle程序用于构建证书池
  •  cfssljson程序,从cfssl和multirootca程序获取JSON输出,并将证书,密钥,CSR和bundle写入磁盘

PKI借助数字证书和公钥加密技术提供可信任的网络身份。通常,证书就是一个包含如下身份信息的文件:

  •  证书所有组织的信息
  •  公钥
  •  证书颁发组织的信息
  •  证书颁发组织授予的权限,如证书有效期、适用的主机名、用途等
  •  使用证书颁发组织私钥创建的数字签名

安装 cfssl

这里我们只用到cfssl工具和cfssljson工具

  1. # curl -L https://pkg.cfssl.org/R1.2/cfssl_linux-amd64 -o /usr/local/bin/cfssl  
  2. # curl -L https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64 -o /usr/local/bin/cfssljson  
  3. # curl -L https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64 -o /usr/local/bin/cfssl-certinfo  
  4. # chmod +x /usr/local/bin/cfssl* 

cfssl 常用子命令介绍

  1. bundle: 创建包含客户端证书的证书包  
  2. genkey: 生成一个key(私钥)和CSR(证书签名请求)  
  3. scan: 扫描主机问题  
  4. revoke: 吊销证书  
  5. certinfo: 输出给定证书的证书信息, 跟cfssl-certinfo 工具作用一样  
  6. gencrl: 生成新的证书吊销列表  
  7. selfsign: 生成一个新的自签名密钥和 签名证书  
  8. print-defaults: 打印默认配置,这个默认配置可以用作模板  
  9. serve: 启动一个HTTP API服务  
  10. gencert: 生成新的key(密钥)和签名证书  
  11.  -ca:指明ca的证书  
  12.  -ca-key:指明ca的私钥文件  
  13.  -config:指明请求证书的json文件  
  14.  -profile:与-config中的profile对应,是指根据config中的profile段来生成证书的相关信息  
  15. ocspdump: 从cert db 中的所有 OCSP 响应中生成一系列连贯的 OCSP 响应,供 ocspserve 使用  
  16. ocspsign: 为给定的CA、Cert和状态签署OCSP响应。返回一个base64编码的OCSP响应  
  17. info: 获取有关远程签名者的信息  
  18. sign: 签名一个客户端证书,通过给定的CA和CA密钥,和主机名  
  19. ocsprefresh: 用所有已知未过期证书的新OCSP响应刷新ocsp_responses表。  
  20. ocspserve: 设置一个HTTP服务器,处理来自文件或直接来自数据库的OCSP请求(见RFC 5019)。 

常用命令

  1. $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca ## 初始化ca  
  2. $ cfssl gencert -initca -ca-key key.pem ca-csr.json | cfssljson -bare ca ## 使用现有私钥, 重新生成  
  3. $ cfssl certinfo -cert ca.pem  
  4. $ cfssl certinfo -csr ca.csr 

使用 CFSSL 创建 CA 认证步骤

创建认证中心(CA)

cfssl 可以创建一个获取和操作证书的内部认证中心。运行认证中心需要一个 CA 证书和相应的 CA 私钥。任何知道私钥的人都可以充当CA来颁发证书。因此,私钥的保护至关重要,这里我们以 k8s 所需的证书来实践一下:

  1. $ cfssl print-defaults config > config.json # 默认证书策略配置模板  
  2. $ cfssl print-defaults csr > csr.json #默认csr请求模板 

结合自身的要求,修改证书请求文件csr.json,证书10年

  1. {  
  2.   "CN": "kubernetes",  
  3.   "key": {  
  4.     "algo": "rsa",  
  5.     "size": 2048  
  6.   },  
  7.   "names": [  
  8.     {  
  9.       "C": "CN",  
  10.       "ST": "BeiJing",  
  11.       "L": "BeiJing",  
  12.       "O": "k8s",  
  13.       "OU": "System"  
  14.     }  
  15.    ],  
  16.    "ca": {  
  17.     "expiry": "87600h"  
  18.   }  

知识点 :

  •  "CN":Common Name,kube-apiserver 从证书中提取该字段作为请求的用户名 (User Name)
  •  "O":Organization,kube-apiserver从证书中提取该字段作为请求用户所属的组 (Group)
  •  C: Country, 国家
  •  L: Locality,地区,城市
  •  O: Organization Name,组织名称,公司名称
  •  OU: Organization Unit Name,组织单位名称,公司部门
  •  ST: State,州,省

证书配置模板文件ca-config.json

  1. {  
  2.   "signing": {  
  3.       "default": {  
  4.         "expiry": "87600h"  
  5.    },  
  6.   "profiles": {  
  7.     "kubernetes": {  
  8.       "usages": [  
  9.         "signing",  
  10.         "key encipherment",  
  11.         "server auth",  
  12.         "client auth"  
  13.       ],  
  14.       "expiry": "87600h"  
  15.     }  
  16.    }  
  17.   }  

知识点:

  •  config.json:可以定义多个 profiles,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;此实例只有一个kubernetes模板。
  •  signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中CA=TRUE
  •  server auth:表示client可以用该 CA 对server提供的证书进行验证;
  •  client auth:表示server可以用该CA对client提供的证书进行验证;
  •  注意标点符号,最后一个字段一般是没有逗号的。

初始化创建CA认证中心,将会生成ca-key.pem(私钥)和ca.pem(公钥)

  1. $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca 

创建 Kubernetes 证书

创建kubernetes-csr.json证书请求文件

  1. {  
  2.     "CN": "kubernetes",  
  3.     "hosts": [  
  4.         "127.0.0.1",  
  5.         "10.1.20.129",  
  6.         "10.1.20.128",  
  7.         "10.1.20.126",  
  8.         "10.1.20.127",  
  9.         "10.254.0.1",  
  10.         "*.kubernetes.master",  
  11.         "localhost",  
  12.         "kubernetes",  
  13.         "kubernetes.default",  
  14.         "kubernetes.default.svc",  
  15.         "kubernetes.default.svc.cluster",  
  16.         "kubernetes.default.svc.cluster.local" 
  17.     ],  
  18.     "key": {  
  19.         "algo": "rsa",  
  20.         "size": 2048  
  21.     },  
  22.     "names": [  
  23.         {  
  24.             "C": "CN",  
  25.             "ST": "BeiJing",  
  26.             "L": "BeiJing",  
  27.             "O": "k8s",  
  28.             "OU": "System"  
  29.         }  
  30.     ]  

知识点:

  •  这个证书目前专属于 apiserver,加了一个 *.kubernetes.master域名以便内部私有 DNS 解析使用(可删除);至于很多人问过 kubernetes 这几个能不能删掉,答案是不可以的;因为当集群创建好后,default namespace 下会创建一个叫 kubenretes 的svc,有一些组件会直接连接这个 svc 来跟 api 通信的,证书如果不包含可能会出现无法连接的情况;其他几个 kubernetes 开头的域名作用相同
  •  hosts包含的是授权范围,不在此范围的的节点或者服务使用此证书就会报证书不匹配错误。10.254.0.1是指kube-apiserver 指定的 service-cluster-ip-range 网段的第一个IP。

生成 Kubernetes 证书和私钥

  1. $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes kubernetes-csr.json | cfssljson -bare kubernetes 

知识点:

  •  -config 引用的是模板中的默认配置文件,
  •  -profiles是指定特定的使用场景,比如config.json中的kubernetes区域

创建 admin 证书

创建 admin 证书请求文件admin-csr.json

  1.  {  
  2.     "CN": "admin",  
  3.     "hosts": [],  
  4.     "key": {  
  5.     "algo": "rsa",  
  6.     "size": 2048  
  7.     },  
  8.     "names": [  
  9.     {  
  10.         "C": "CN",  
  11.         "ST": "BeiJing",  
  12.         "L": "BeiJing",  
  13.         "O": "system:masters",  
  14.         "OU": "System"  
  15.     }  
  16.     ]  

生成 admin 证书和私钥

  1. $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=kubernetes admin-csr.json | cfssljson -bare admin 

知识点: 这个admin 证书,是将来生成管理员用的kubeconfig 配置文件用的,现在我们一般建议使用RBAC 来对kubernetes 进行角色权限控制, kubernetes 将证书中的CN字段作为User, O 字段作为 Group。

同样,我们也可以按照同样的方式来创建 Kubernetes 中 etcd 集群的证书

创建 etcd 集群证书

  1.  证书签署请求文件ca-csr.json

  1. {  
  2.     "CN": "etcd CA",  
  3.     "key": {  
  4.         "algo": "rsa",  
  5.         "size": 2048  
  6.     },  
  7.     "names": [  
  8.         {  
  9.             "C": "CN",  
  10.             "L": "Beijing",  
  11.             "ST": "Beijing"  
  12.         }  
  13.     ]  

  2.  为节点创建服务证书请求文件,指定授权的主机节点etcd-server-csr.json

  1. {  
  2.     "CN": "etcd",  
  3.     "hosts": [  
  4.         "10.1.20.129",  
  5.         "10.1.20.126",  
  6.         "10.1.20.128"  
  7.         ],  
  8.     "key": {  
  9.         "algo": "rsa", 
  10.         "size": 2048 
  11.     },  
  12.     "names": [  
  13.         {  
  14.             "C": "CN",  
  15.             "L": "BeiJing",  
  16.             "ST": "BeiJing"  
  17.         }  
  18.     ]  

  3.  证书配置模板文件ca-config.json

  1. {  
  2.   "signing": {  
  3.     "default": {  
  4.       "expiry": "87600h"  
  5.     },  
  6.     "profiles": {  
  7.       "etcd": {  
  8.          "expiry": "87600h",  
  9.          "usages": [  
  10.             "signing",  
  11.             "key encipherment",  
  12.             "server auth",  
  13.             "client auth"  
  14.         ]  
  15.       }  
  16.     }  
  17.   }  

  4.  生成 etcd 集群所需的证书与私钥

  1. $ cfssl gencert -initca ca-csr.json | cfssljson -bare ca -  
  2. $ cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=etcd etcd-server-csr.json | cfssljson -bare server 

这样就完成 etcd 所需证书的申请,同时了解了 cfssl 工具的强大,写到这里,本次的实验就结束了。

相关内容