首先什么是 mtls (双向认证)?它是一个过程,在这个过程中,客户机和服务器都通过证书颁发机构彼此验证身份。 相信 tls 大家都比较熟悉,就是 server 端提供一个授信证书,当我们使用 https 协议访问server端时,client 会向 server 端索取证书并认证(浏览器会与自己的授信域匹配或弹出不安全的页面)。 mtls 则是由同一个 root ca 生成两套证书,即客户端证书和服务端证书。客户端使用 https 访问服务端时,双方会交换证书,并进行认证,认证通过方可通信。

证书生成

证书格式类型

证书主要的格式有以下几种

  • .DER .CER,文件是二进制格式,只保存证书,不保存私钥。Java 和 Windows 服务器偏向于使用这种编码格式。
  • .PEM,一般是文本格式,可保存证书,可保存私钥。Privacy Enhanced Mail,一般为文本格式,以 —–BEGIN… 开头,以 —–END… 结尾。中间的内容是 BASE64 编码。这种格式可以保存证书和私钥,有时我们也把PEM 格式的私钥的后缀改为 .key 以区别证书与私钥。具体你可以看文件的内容。这种格式常用于 Apache 和 Nginx 服务器。
  • .CRT,Certificate 的简称,有可能是 PEM 编码格式,也有可能是 DER 编码格式。可以是二进制格式,可以是文本格式,与 .DER 格式相同,不保存私钥。
  • .PFX .P12,二进制格式,同时包含证书和私钥,一般有密码保护。Predecessor of PKCS#12,这种格式是二进制格式,且证书和私钥存在一个 PFX 文件中。一般用于 Windows 上的 IIS 服务器。改格式的文件一般会有一个密码用于保证私钥的安全。
  • .JKS,二进制格式,同时包含证书和私钥,一般有密码保护。Java Key Storage,很容易知道这是 JAVA 的专属格式,利用 JAVA 的一个叫 keytool 的工具可以进行格式转换。一般用于 Tomcat 服务器。

// 生成根证书(ROOT CA)

  • openssl genrsa -out ca.pem 2048
  • 生成根证书的密匙。
  • openssl req -x509 -new -key ca.pem -days 3650 -out ca.crt -subj "/C=CN/ST=SD/L=JN/O=WANGFENGCA/OU=WFCA/CN=wangfeng.live"

// 生成 服务端证书

  • openssl genrsa -out server.pem 2048
  • 生成服务器端的密匙。
  • openssl req -new -key server.pem -out server.csr -subj "/C=CN/ST=SD/L=JN/O=WANGFENG/OU=WF/CN=*.wangfeng.live" 生成服务器端证书的请求文件。请求根证书来签发。
  • openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.pem -CAcreateserial -days 3650 -out server.crt
  • 用根证书来签发服务器端请求文件,生成服务器端证书server.crt。

// 生成 客户端证书

  • openssl genrsa -out client.pem 2048
  • 生成客户端的密匙。
  • openssl req -new -key client.pem -out client.csr -subj "/C=CN/ST=SD/L=JN/O=ALIY/OU=AL/CN=aliyunrenzheng"
  • 生成客户端证书的请求文件。请求根证书来签发。
  • openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.pem -CAcreateserial -days 3650 -out client.crt
  • 用根证书来签发客户端请求文件,生成客户端证书client.crt。
  • openssl pkcs12 -export -in client.crt -inkey client.pem -out client.pkcs12
  • 打包客户端资料为pkcs12格式(client.pkcs12)。需要输入密码,请记住。 密码:wangfeng

keytool

keytool 是个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。它还允许用户储存他们的通信对等者的公钥(以证书形式)。(一下用于java)

  • keytool -importkeystore -srckeystore client.jks -destkeystore client.jks -deststoretype pkcs12
  • 生成客户端keystore(client.jks)。使用keytool的importkeystore指令。pkcs12转jks。需要pkcs12密码和jks密码。
  • keytool -importcert -alias ca -file ca.crt -keystore clienttrust.jks
  • 生成Client端的对外KeyStore。先把根证书放到里面。
  • keytool -importcert -alias clientcert -file client.crt -keystore clienttrust.jks
  • 把Client证书加到对外KeyStore里面。

K8s ingress 配置

首先我们需要在ingress 所在的 namespace 下创建对应的 secret

kubectl create secret generic ca-secret --from-file=ca.crt=ca.crt
kubectl create secret generic tls-secret --from-file=tls.crt=server.crt --from-file=tls.key=server.key

创建ingress:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
annotations:
  kubernetes.io/ingress.class: nginx
   # 开启客户端认证
  nginx.ingress.kubernetes.io/auth-tls-verify-client: "on"
   # 指定root ca 的 secret
  nginx.ingress.kubernetes.io/auth-tls-secret: "default/ca-secret"
   # 指定验证证书链的深度
  nginx.ingress.kubernetes.io/auth-tls-verify-depth: "1"
   # 是否将证书传递给后端的服务
  nginx.ingress.kubernetes.io/auth-tls-pass-certificate-to-upstream: "true"
name: test-server
namespace: default
spec:
rules:
- host: test.wangfeng.live
  http:
    paths:
    - backend:
        serviceName: test-server
        servicePort: 8080
      path: /
tls:
- hosts:
  - test.wangfeng.live
  secretName: tls-secret

验证

这里我们随便起一个 nginx 的服务:

kubectl run my-nginx --image=nginx --replicas=2 --port=80
kubectl expose deployment my-nginx --type=NodePort --port=80 --target-port=80

按照上述配置,创建 secret、ingress。

通过 curl 访问我们的服务 curl -k https://x.x.x.x/,会发现返回了一个 400 的response

[root@my ~]# curl -k https://10.48.51.222/
<html>
<head><title>400 No required SSL certificate was sent</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>No required SSL certificate was sent</center>
<hr><center>openresty/1.15.8.1</center>
</body>
</html>

这就说明服务端认为我们是不可信的,因为没有携带证书。当我们携带证书去访问,

curl -k --cert client.pem --key key.pem https://x.x.x.x

/则会返回正常页面。

参考:https://zhuanlan.zhihu.com/p/140752944?from_voters_page=true

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据