数字证书允许在其他不受信任的网络上安全交换公共加密密钥。运输加密技术,如运输层安全(Transport Layer Security)或TLS,使用这些数字证书来促进公共网络上的安全交流。如下是两个系统想要建立一个受TLS保护的加密会话的过程:
首先,客户端向服务器发送一个请求,要求服务器启动一个安全会话。这个请求包括一个客户端所支持的密码套件(Cipher suites) 的列表。现在,重要的是要理解,TLS只是使用其他加密算法的协议。TLS本身不是一种加密算法,因此我们不能用TLS来加密什么。我们可以使用TLS来应用其他加密算法。客户端发送至服务器的密码套件列表是一份加密算法、哈希函数和其他客户理解的加密细节的详细列表。通过选择一个弱的或不安全的密码套件,有可能以不安全的方式使用TLS。
一旦服务器收到来自客户端的请求,它将分析客户端提出的密码套件列表,并将其与服务器支持的算法列表进行比较。然后,它向客户发送一个带有两个信息的消息。首先,服务器告诉客户,它想在通信中使用哪种密码套件。其次,服务器向客户端发送服务器的数字证书,其中包含服务器的公共加密密钥。
当客户端收到服务器的数字证书时,它会检查哪个证书机构颁发了该证书,并使用CA的公钥来验证证书上的数字签名。它还会验证证书上的服务器名称是否与服务器的DNS名称相匹配,以及该证书是否已经过期或被撤销。如果所有这些东西都检查无误,客户就知道它有正确的服务器的公钥。
一旦客户端对服务器的身份感到满意,客户端就会创建一个随机的加密密钥,称为会话密钥(Seesion key)。这是一个对称的加密密钥,将用于客户端和服务器之间的这个通信会话。然后,客户端使用服务器的公钥来加密会话密钥,并将加密后的密钥发送给服务器。当服务器收到加密的密钥时,它使用自己的私钥来解密该会话密钥。然后,这两个系统可以使用会话密钥进行通信,只要他们愿意。一旦他们关闭连接,会话密钥就会被销毁,TLS握手就会在两个系统希望进行通信时重新开始。注意,会话密钥也被称为ephemeral key。
我们可能还听说过一种被称为SSL的加密技术,SSL是TLS的前身,它的工作方式非常相似。然而,SSL存在着已知的安全缺陷,所以它不应再被使用。但是,现在许多人在真正谈论TLS时,将SSL作为一个通用术语。
底层系统为ubuntu18.04,然后在每个node上安装k8s,并构建集群。Master node的IP地址为192.168.26.71/24,两个Worker node的IP地址为192.168.26.72/24、192.168.26.73/24。
在后续的实验步骤中,我们将在K8s中部署一个Web的应用,并且使用TLS对其进行加密,采用https的方式来访问部署的Web应用。
Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。下面是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:
可以将 Ingress 配置为服务提供外部可访问的 URL、负载均衡流量、终止 SSL/TLS,以及提供基于名称的虚拟主机等能力。 Ingress 控制器 通常负责通过负载均衡器来实现 Ingress,尽管它也可以配置边缘路由器或其他前端来帮助处理流量。
Ingress 不会公开任意端口或协议。 将 HTTP 和 HTTPS 以外的服务公开到 Internet 时,通常使用 Service.Type=NodePort 或 Service.Type=LoadBalancer 类型的服务。
在创建ingress前在K8s环境中必须有Ingress控制器,下载链接如下:https://kubernetes.io/zh/docs/concepts/services-networking/ingress-controllers/。在这里,我们选择ingress-nginx控制。下载完ingress控制器后,在K8s上创建对应容器(master设备上),可以查看其运行的pod。
root@vms71:~# kubectl get pods -n ingress-nginx
NAME READY STATUS RESTARTS AGE
ingress-nginx-admission-create--1-frcqs 0/1 Completed 0 30m
ingress-nginx-admission-patch--1-glh9b 0/1 Completed 1 30m
ingress-nginx-controller-744d4fc6b7-mt95p 1/1 Running 0 30m
接着在在K8s环境中创建一个nginx的容器pod1,yaml文件如下:
apiVersion: v1
kind: Pod
metadata:
creationTimestamp: null
labels:
run: pod1
name: pod1
spec:
terminationGracePeriodSeconds: 0
containers:
- image: nginx
imagePullPolicy: IfNotPresent
name: pod1
resources: {}
dnsPolicy: ClusterFirst
restartPolicy: Always
status: {}
修改nginx主页为‘11111’,方便实验。
kubectl exec -it pod1 -- sh -c "echo 11111 > /usr/share/nginx/html/index.html"
为nginx的容器创建一个svc,名叫svc1:
kubectl expose --name=svc1 pod pod1 --port=80
为svc1创建一个ingress,yaml文件如下,可以使用域名www.cks8.com进行访问:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
rules:
- host: www.ck8s.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc1
port:
number: 80
查看ingress创建是否完成:
root@vms71:~# kubectl apply -f ing.yaml
ingress.networking.k8s.io/minimal-ingress created
root@vms71:~# kubectl get ingress
NAME CLASS HOSTS ADDRESS PORTS AGE
minimal-ingress <none> www.ck8s.com 10.104.95.7 80 9m54s
找到www.ck8s.com所对应控制器的IP地址:192.168.26.72
root@vms71:~# kubectl get pods -owide -n ingress-nginx
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
ingress-nginx-admission-create--1-frcqs 0/1 Completed 0 50m 10.244.5.194 vms72.rhce.cc <none> <none>
ingress-nginx-admission-patch--1-glh9b 0/1 Completed 1 50m 10.244.5.193 vms72.rhce.cc <none> <none>
ingress-nginx-controller-744d4fc6b7-mt95p 1/1 Running 0 50m 192.168.26.72 vms72.rhce.cc <none> <none>
在同一网段内随便选择一台设备作为client访问www.ck8s.com进行测试。首先是在client中修改/etc/hosts文件,添加对应关系:
192.168.26.72 www.ck8s.com www
然后再client上访问www.ck8s.com这个域名,可以看到我们修改后的信息:
[root@localhost ~]# curl www.ck8s.com
11111
但是目前访问的方式是http的方式,并不安全。所以我们需要将其修改为https的方式完成。
1.默认证书
首先需要知道,入口控制器(ingress-nginx-controller)自己携带证书,所以我们可以在client上直接在浏览器中用https访问www.ck8s.com。证书由于不是权威CA颁发,所有有风险提示。
点击查看详细证书,可以看到是k8s颁发的:
现在除了这个证书是由非权威CA颁发的之外,还会给此ingress下所有的pod(站点)都发布一样的证书。这里我们想要给pod1的站点单独颁发一个证书,不想和其他pod共同一个证书,所以现在需要做的就是替换到当前的K8s的默认证书。
2.替换为自己的自签名证书
生成证书有2种方式,分别是CFSSL自己生成证书和使用cert-manager来申请权威证书。本次实验先使用CFSSL自己生产证书,后续笔记再使用cert-manager来申请权威的证书。
CFSSL下载地址如下:三个地址都要分别下载。
https://pkg.cfssl.org/R1.2/cfssl_linux-amd64
https://pkg.cfssl.org/R1.2/cfssljson_linux-amd64
https://pkg.cfssl.org/R1.2/cfssl-certinfo_linux-amd64
然后给下载的三个文件设置可执行权限:
chmod +x *
接下来创建自己K8s集群内的CA机构。首先需要设置CA的配置文件,在master上生产CA配置文件:
cfssl print-defaults config > ca-config.json
查看ca-config,json文件:
root@vms71:~/tls# cat ca-config.json
{
"signing": {
"default": {
"expiry": "168h"
},
"profiles": {
"www": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
},
"client": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"client auth"
]
}
}
}
}
其中字段的具体含义:
ca-config.json:可以定义多个 profiles,为不同的机构颁发证书,分别指定不同的过期时间、使用场景等参数;后续在签名证书时使用某个 profile;
signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE;
server auth:表示client可以用该 CA 对server提供的证书进行验证;
client auth:表示server可以用该CA对client提供的证书进行验证;当client和server互相需要认证时,被称为mTLS。
CN: Common Name,浏览器使用该字段验证网站是否合法,一般写的是域名。
C: Country, 国家
L: Locality,地区,城市
O: Organization Name,组织名称,公司名称
OU: Organization Unit Name,组织单位名称,公司部门
ST: State,州,省
这里我们修改CA的配置文件为如下的内容并保存:
{
"signing": {
"default": {
"expiry": "1680h"
},
"profiles": {
"www": {
"expiry": "8760h",
"usages": [
"signing",
"key encipherment",
"server auth"
]
}
}
}
}
接着为CA生成证书请求文件:
cfssl print-defaults csr > ca-csr.json
修改ca-csr.json内容如下:
{
"CN": "ck8s.com",
"key": {
"algo": "ecdsa",
"size": 256
},
"names": [
{
"C": "CN",
"ST": "Jiangsu",
"L": "Xuzhou",
"O": "Lduan",
"OU": "cks"
}
]
}
使用cfssl生成CA的自签名证书(CA用自己的私钥给自己的证书签名):
cfssl gencert -initca ca-csr.json | cfssljson -bare ca
完成后我们可以在目录下看到ca-key.pem,表示CA的私钥;ca.pem则是CA的证书。完成这一步后,CA的配置已经完成。接下来我们需要给pod1申请证书,首先创建pod1申请证书的请求文件。
cfssl print-defaults csr >admin-csr.json
修改文件的内容如下,hosts表示的需要使用证书的站点域名。可以指定具体的域名,也可以使用通配符来完成,例如*.ck8s.com,可以表示www1.ck8s.com、www2.ck8s.com等。如果为hosts空的话,表示所有站点都能够使用。
{
"CN": "ck8s.com",
"key": {
"algo": "ecdsa",
"size": 256
},
"hosts": [
"www.ck8s.com"
],
"names": [
{
"C": "CN",
"ST": "Jiangsu",
"L": "Xuzhou",
"O": "Lduan",
"OU": "cks"
}
]
}
申请并审批用户证书,其中使用的profile为CA的www:
cfssl gencert -ca=ca.pem -ca-key=ca-key.pem -config=ca-config.json -profile=www admin-csr.json | cfssljson -bare admin
最终生成的pod1都证书前缀为admin。其中admin-key.pem为pod1的私钥,amin.pem是CA为pod1颁发的证书。接下来我们需要替换到k8s ingress控制器自带的证书。
首先我们需要创建一个tls类型的secret,里面包含了pod1的私钥和证书。
kubectl create secret tls mytlssec --cert=admin.pem --key=admin-key.pem
修改现有的ingress,yaml文件如下,指定使用的secret(包含了自己的证书),同时也指定了tls保护的站点(站点之外的访问依然使用K8s提供的证书):
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: minimal-ingress
annotations:
kubernetes.io/ingress.class: "nginx"
spec:
tls:
- hosts:
- www.ck8s.com
secretName: mytlssec
rules:
- host: www.ck8s.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: svc1
port:
number: 80
应用修改后的ingress的yaml文件,并重新在client上访问,查看证书是否修改。
如上图,已经修改成功。或者在client上使用如下命令:
curl -kv https://www.ck8s.com
整理资料来源:
《老段CKS课程》
K8s官网:https://kubernetes.io/zh/docs/concepts/services-networking/ingress/