二十、K8s集群设置2- HTTPS-CFSSL

一、什么是TLS

数字证书允许在其他不受信任的网络上安全交换公共加密密钥。运输加密技术,如运输层安全(Transport Layer Security)或TLS,使用这些数字证书来促进公共网络上的安全交流。如下是两个系统想要建立一个受TLS保护的加密会话的过程:

  1. 首先,客户端向服务器发送一个请求,要求服务器启动一个安全会话。这个请求包括一个客户端所支持的密码套件(Cipher suites) 的列表。现在,重要的是要理解,TLS只是使用其他加密算法的协议。TLS本身不是一种加密算法,因此我们不能用TLS来加密什么。我们可以使用TLS来应用其他加密算法。客户端发送至服务器的密码套件列表是一份加密算法、哈希函数和其他客户理解的加密细节的详细列表。通过选择一个弱的或不安全的密码套件,有可能以不安全的方式使用TLS。
    二十、K8s集群设置2- HTTPS-CFSSL_第1张图片

  2. 一旦服务器收到来自客户端的请求,它将分析客户端提出的密码套件列表,并将其与服务器支持的算法列表进行比较。然后,它向客户发送一个带有两个信息的消息。首先,服务器告诉客户,它想在通信中使用哪种密码套件。其次,服务器向客户端发送服务器的数字证书,其中包含服务器的公共加密密钥。二十、K8s集群设置2- HTTPS-CFSSL_第2张图片

  3. 当客户端收到服务器的数字证书时,它会检查哪个证书机构颁发了该证书,并使用CA的公钥来验证证书上的数字签名。它还会验证证书上的服务器名称是否与服务器的DNS名称相匹配,以及该证书是否已经过期或被撤销。如果所有这些东西都检查无误,客户就知道它有正确的服务器的公钥。
    二十、K8s集群设置2- HTTPS-CFSSL_第3张图片

  4. 一旦客户端对服务器的身份感到满意,客户端就会创建一个随机的加密密钥,称为会话密钥(Seesion key)。这是一个对称的加密密钥,将用于客户端和服务器之间的这个通信会话。然后,客户端使用服务器的公钥来加密会话密钥,并将加密后的密钥发送给服务器。当服务器收到加密的密钥时,它使用自己的私钥来解密该会话密钥。然后,这两个系统可以使用会话密钥进行通信,只要他们愿意。一旦他们关闭连接,会话密钥就会被销毁,TLS握手就会在两个系统希望进行通信时重新开始。注意,会话密钥也被称为ephemeral key。
    二十、K8s集群设置2- HTTPS-CFSSL_第4张图片
    我们可能还听说过一种被称为SSL的加密技术,SSL是TLS的前身,它的工作方式非常相似。然而,SSL存在着已知的安全缺陷,所以它不应再被使用。但是,现在许多人在真正谈论TLS时,将SSL作为一个通用术语。

二、实验环境

二十、K8s集群设置2- HTTPS-CFSSL_第5张图片

底层系统为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的方式发布Web应用

Ingress 公开了从集群外部到集群内服务的 HTTP 和 HTTPS 路由。 流量路由由 Ingress 资源上定义的规则控制。下面是一个将所有流量都发送到同一 Service 的简单 Ingress 示例:
二十、K8s集群设置2- HTTPS-CFSSL_第6张图片
可以将 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的方式完成。

四、设置自签名证书的HTTPS访问

1.默认证书
首先需要知道,入口控制器(ingress-nginx-controller)自己携带证书,所以我们可以在client上直接在浏览器中用https访问www.ck8s.com。证书由于不是权威CA颁发,所有有风险提示。
二十、K8s集群设置2- HTTPS-CFSSL_第7张图片
点击查看详细证书,可以看到是k8s颁发的:
二十、K8s集群设置2- HTTPS-CFSSL_第8张图片
现在除了这个证书是由非权威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上访问,查看证书是否修改。
二十、K8s集群设置2- HTTPS-CFSSL_第9张图片
如上图,已经修改成功。或者在client上使用如下命令:

curl -kv https://www.ck8s.com

整理资料来源:
《老段CKS课程》
K8s官网:https://kubernetes.io/zh/docs/concepts/services-networking/ingress/

你可能感兴趣的:(云计算,K8s,CFSSL,https,TLS)