使用certManager自动管理https证书

3,440 阅读7分钟

https是什么?

超文本传输协议HTTP协议被用于在Web浏览器和网站服务器之间传递信息,HTTP协议以明文方式发送内容,不提供任何方式的数据加密,如果攻击者截取了Web浏览器和网站服务器之间的传输报文,就可以直接读懂其中的信息,因此,HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

为了解决HTTP协议的这一缺陷,需要使用另一种协议:安全套接字层超文本传输协议HTTPS,为了数据传输的安全,HTTPS在HTTP的基础上加入了SSL协议,SSL依靠证书来验证服务器的身份,并为浏览器和服务器之间的通信加密。http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

certManager是什么?

cert-manager 是一个云原生证书管理开源项目,用于在 kubernetes 集群中提供 HTTPS 证书并自动续期,支持 Let’s Encrypt, HashiCorp Vault 这些免费证书的签发。在Kubernetes集群中,我们可以通过 Kubernetes Ingress 和 Let’s Encrypt 实现外部服务的自动化 HTTPS。

在Kubernetes集群中使用 HTTPS 协议,需要一个证书管理器、一个证书自动签发服务,主要通过 Ingress 来发布 HTTPS 服务,因此需要Ingress Controller并进行配置,启用 HTTPS 及其路由。

如何安装certManager?

环境依赖

  • 集群必须已经装有 Ingress Controller
  • 外部客户端配置hosts,IP 指向 Ingress Controller 对外暴露的地址(如果IP是公网地址并做了域名解析,则无需配置)

开始安装

  • 安装cert-manager

    • 官网:cert-manager.io/docs/instal…
    • 安装:kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.6.1/cert-manager.yaml
  • 查看安装结果

    • kubectl get pods -n cert-manager

      [root@master cert-manager-161]# kubectl get pods -n cert-manager 
      NAME                                      READY   STATUS    RESTARTS   AGE
      cert-manager-55658cdf68-9wbwh             1/1     Running   0          37s
      cert-manager-cainjector-967788869-ddmlv   1/1     Running   0          37s
      cert-manager-webhook-6668fbb57d-gqr7t     1/1     Running   0          37s
      

生成CA证书

  • 安装cfssl

    • 下载最新的可执行文件

      [root@master ssl]# wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl_1.6.1_linux_amd64
      [root@master ssl]# wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssljson_1.6.1_linux_amd64
      [root@master ssl]# wget https://github.com/cloudflare/cfssl/releases/download/v1.6.1/cfssl-certinfo_1.6.1_linux_amd64
      
      [root@master ssl]# mv cfssl_1.6.1_linux_amd64 cfssl
      [root@master ssl]# mv cfssl-certinfo_1.6.1_linux_amd64 certinfo
      [root@master ssl]# mv cfssljson_1.6.1_linux_amd64 cfssljson
      
      [root@master ssl]# chmod +x certinfo 
      [root@master ssl]# chmod +x cfssl
      [root@master ssl]# chmod +x cfssljson
      
    • 复制到/usr/local/bin

      [root@master ssl]# mv cfssl /usr/local/sbin/
      [root@master ssl]# mv certinfo /usr/local/sbin/
      [root@master ssl]# mv cfssljson /usr/local/sbin/
      
  • 生成CA证书

    • 配置证书请求文件
    cfssl print-defaults csr > csr.json
    
    {
        "CN": "kdemo",
        "key": {
            "algo": "rsa",
            "size": 2048
        },
        "names": [
            {
                "C": "CN",
                "ST": "ShenZhen",
                "L": "ShenZhen",
                "O": "k8s",
                "OU": "systemGroup"
            }
        ],
        "ca": {
            "expiry": "87600h"
        }
    }
    

    字段说明: default:默认策略,指定了证书的有效期是一年(8760h) signing:表示该证书可用于签名其它证书;生成的 ca.pem 证书中 CA=TRUE server auth:表示 client 可以用该 CA 对 server 提供的证书进行验证 client auth:表示 server 可以用该 CA 对 client 提供的证书进行验证 expiry:过期时间

  • cfssl gencert -initca csr.json | cfssljson -bare ca

    [root@master ssl]# cfssl gencert -initca csr.json  | cfssljson -bare ca
    2021/12/28 17:25:55 [INFO] generating a new CA key and certificate from CSR
    2021/12/28 17:25:55 [INFO] generate received request
    2021/12/28 17:25:55 [INFO] received CSR
    2021/12/28 17:25:55 [INFO] generating key: rsa-2048
    2021/12/28 17:25:55 [INFO] encoded CSR
    2021/12/28 17:25:55 [INFO] signed certificate with serial number 151317294092143127619036180787140414839328861547
    [root@master ssl]# ls
    ca.csr  ca-key.pem  ca.pem  csr.json
    

使用certManager管理证书

使用本地证书来创建

  • 将签名密钥对保存为Secret

    • kubectl create secret tls ca-key-pair --cert=ca.crt --key=ca.key --namespace=kdemo

      [root@master ssl]# kubectl create secret tls ca-key-pair --cert=ca.pem --key=ca-key.pem --namespace=kdemo
      secret/ca-key-pair created
      [root@master ssl]# kubectl get se
      secrets                             serviceaccounts                     serviceentries.networking.istio.io  services
      [root@master ssl]# kubectl get secrets -n kdemo
      NAME                  TYPE                                  DATA   AGE
      ca-key-pair           kubernetes.io/tls                     2      16s
      default-token-n7xwn   kubernetes.io/service-account-token   3      90s
      
  • 创建一个签发机构

    我们需要先创建一个签发机构,cert-manager 给我们提供了 Issuer 和 ClusterIssuer 这两种用于创建签发机构的自定义资源对象,Issuer 只能用来签发自己所在 namespace 下的证书,ClusterIssuer 可以签发任意 namespace 下的证书,这里以 Issuer 为例创建一个签发机构

    • vim kdemo-issuer.yaml
    apiVersion: cert-manager.io/v1
    kind: Issuer
    metadata:
      name: kdemo-issuer
      namespace: kdemo
    spec:
      ca:
        secretName: ca-key-pair
    
    • kubectl apply -f kdemo-issuer.yaml
    [root@master ssl]# kubectl apply -f kdemo-issuer.yaml 
    issuer.cert-manager.io/kdemo-issuer created
    [root@master ssl]# kubectl get issuers.cert-manager.io -n kdemo 
    NAME           READY   AGE
    kdemo-issuer   True    25s
    
  • 创建一个免费证书Certificate

    • vim kdemo-certificate.yaml
    apiVersion: cert-manager.io/v1
    kind: Certificate
    metadata:
      name: kdemo-tls
      namespace: kdemo
    spec:
      secretName: kdemo-tls
      issuerRef:
        name: kdemo-issuer
        kind: Issuer
      commonName: kdemo.com
      dnsNames:
      - kdemo.com
    
    • kubectl apply -f kdemo-certificate.yaml
    [root@master ssl]# kubectl apply -f kdemo-certificate.yaml 
    certificate.cert-manager.io/kdemo-tls created
    [root@master ssl]# kubectl get certificate -n kdemo 
    NAME        READY   SECRET      AGE
    kdemo-tls   True    kdemo-tls   21s
    
    • kubectl get secrets -n kdemo 查看secrets

      [root@master ssl]# kubectl get secrets -n kdemo 
      NAME                  TYPE                                  DATA   AGE
      ca-key-pair           kubernetes.io/tls                     2      61m
      default-token-n7xwn   kubernetes.io/service-account-token   3      62m
      kdemo-tls             kubernetes.io/tls                     3      63s
      
    • kubectl describe -n kdemo secrets kdemo-tls 查看详细信息

      [root@master ssl]# kubectl describe -n kdemo secrets kdemo-tls 
      Name:         kdemo-tls
      Namespace:    kdemo
      Labels:       <none>
      Annotations:  cert-manager.io/alt-names: kdemo.com
                    cert-manager.io/certificate-name: kdemo-tls
                    cert-manager.io/common-name: kdemo.com
                    cert-manager.io/ip-sans: 
                    cert-manager.io/issuer-group: 
                    cert-manager.io/issuer-kind: Issuer
                    cert-manager.io/issuer-name: kdemo-issuer
                    cert-manager.io/uri-sans: 
      
      Type:  kubernetes.io/tls
      
      Data
      ====
      ca.crt:   1314 bytes
      tls.crt:  1224 bytes
      tls.key:  1679 bytes
      
  • 创建服务进行测试

    • vim kdemo-nginx.yaml

      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: kdemo
        namespace: kdemo
        labels:
          app: kdemo
      spec:
        replicas: 1
        template:
          metadata:
            name: kdemo
            labels:
              app: kdemo
          spec:
            containers:
              - name: nginx
                image: nginx:1.20.2-alpine
                imagePullPolicy: IfNotPresent
            restartPolicy: Always
        selector:
          matchLabels:
            app: kdemo
      
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: kdemo
        namespace: kdemo
      spec:
        selector:
          app: kdemo
        ports:
          - port: 80
        type: ClusterIP
      
      ---
      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: kdemo
        namespace: kdemo
      spec:
        ingressClassName: nginx
        rules:
          - host: kdemo.com
            http:
              paths:
                - backend:
                    service:
                      name: kdemo
                      port:
                        number: 80
                  path: /
                  pathType: Prefix
        tls:
          - hosts:
              - kdemo.com
            secretName: kdemo-tls
      status:
        loadBalancer: {}
      
    • kubectl apply -f kdemo-nginx.yaml

      [root@master ssl]# kubectl apply -f kdemo-nginx.yaml 
      deployment.apps/kdemo created
      service/kdemo created
      ingress.networking.k8s.io/kdemo created
      
  • 访问测试

使用aliyun-dns-webhook自动为阿里云域名续期https证书

安装aliyun-dns-webhook插件

  • 使用helm安装

    helm repo add cert-manager-alidns-webhook https://gitee.com/daiminr/cert-manager-alidns-webhook
    helm repo update
    helm install cert-manager-alidns-webhook/alidns-webhook
    
  • 安装结果

    [root@master alidns-webhook]# helm install alidns-webhook cert-manager-alidns-webhook/alidns-webhook -n cert-manager
    NAME: alidns-webhook
    LAST DEPLOYED: Wed Dec  8 16:11:08 2021
    NAMESPACE: cert-manager
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    
  • 查看安装的情况:kubectl get pods,svc -n cert-manager

    [root@master AtarisMio-alidns]# kubectl get pods,svc -n cert-manager
    NAME                                          READY   STATUS    RESTARTS      AGE
    pod/alidns-webhook-6d4d766fd7-chd89           1/1     Running   0             4m20s
    pod/cert-manager-55658cdf68-9wbwh             1/1     Running   2 (14h ago)   2d
    pod/cert-manager-cainjector-967788869-ddmlv   1/1     Running   2 (14h ago)   2d
    pod/cert-manager-webhook-6668fbb57d-gqr7t     1/1     Running   0             2d
    
    NAME                           TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)    AGE
    service/alidns-webhook         ClusterIP   10.1.169.162   <none>        443/TCP    4m20s
    service/cert-manager           ClusterIP   10.1.17.75     <none>        9402/TCP   2d
    service/cert-manager-webhook   ClusterIP   10.1.167.181   <none>        443/TCP    2d
    
  • 添加alidnsSecret配置:vim alidnsSecret.yaml

    apiVersion: v1
    kind: Secret
    metadata:
      name: alidns-secret
      namespace: cert-manager
    data:
      access-key: base64(accessKey)
      secret-key: base64(secretKey)
    type: Opaque
    

新增ClusterIssuer签发机构

  • 看groupName:kubectl edit pod -n cert-manager alidns-webhook-6d4d766fd7-chd89

  • vim clusterIssuer.yaml

    kind: ClusterIssuer
    metadata:
      name: letsencrypt-alidns
    spec:
      acme:
        # 修改你的邮箱
        email: xxxx@xxxx.cn
        server: https://acme-v02.api.letsencrypt.org/directory
        privateKeySecretRef:
          name: letsencrypt-alidns-key
        solvers:
        - dns01:
            webhook:
              groupName: acme.mycompany.com # 需要和alidns-webhook的group保持一致
              solverName: alidns
              config:
                region: ""
                accessKeyIdSecretRef:
                  name: alidns-secret
                  key: access-key
                accessSecretSecretRef:
                  name: alidns-secret
                  key: secret-key
    
  • 执行:kubectl apply -f clusterIssuer.yaml

    [root@master aliyun-dns-webhook]# kubectl apply -f clusterIssuer.yaml 
    clusterissuer.cert-manager.io/letsencrypt-alidns created
    [root@master aliyun-dns-webhook]#
    

新增一个证书

  • vim certificate-test.yaml

    kind: Certificate
    metadata:
      name: test-xxxx-tls
      namespace: test
    spec:
      secretName: test-xxxx-cn-tls
      commonName: test.xxxx.cn
      dnsNames:
      - test.xxxx.cn
      - "*.test.xxxx.cn"
      issuerRef:
        name: letsencrypt-alidns
        kind: ClusterIssuer
    
  • 安装:kubectl apply -f certificate-test.yaml

    [root@master aliyun-dns-webhook]# kubectl apply -f certificate-test.yaml 
    certificate.cert-manager.io/test-xxxx-tls created
    [root@master aliyun-dns-webhook]# 
    
  • 查看阿里云dns解析记录

  • 查看certificate信息:

    [root@master AtarisMio-alidns]# kubectl get certificate -n test 
    NAME             READY   SECRET              AGE
    test-xxxx-tls   True    test-xxxx-cn-tls   10m
    [root@master AtarisMio-alidns]#
    

配置一个域名试试水

  • 域名:kuboard.xxxx.cn

  • 命名空间:kuboard

  • 添加certificate-kuboard.yaml

    • vim certificate-kuboard.yaml

      apiVersion: cert-manager.io/v1
      kind: Certificate
      metadata:
        name: kuboard-xxxx-tls
        namespace: kuboard
      spec:
        secretName: kuboard-xxxx-cn-tls
        commonName: kuboard.xxxx.cn
        dnsNames:
        - kuboard.xxxx.cn
        issuerRef:
          name: letsencrypt-alidns
          kind: ClusterIssuer
      
    • 执行kubectl apply -f certificate-kuboard.yaml

    • 查看结果kubectl get certificate -n kuboard

      [root@master AtarisMio-alidns]# kubectl get certificate -n kuboard 
      NAME                READY   SECRET                 AGE
      kuboard-xxxx-tls   True    kuboard-xxxx-cn-tls   2d20h
      
    • 新增kuboard-ingress.yaml

      apiVersion: networking.k8s.io/v1
      kind: Ingress
      metadata:
        name: kuboard
        namespace: kuboard
      spec:
        ingressClassName: nginx
        tls: 
        - hosts:
          - kuboard.xxxx.cn
          secretName: kuboard-xxxx-tls
        rules:
        - host: kuboard.xxxx.cn
          http:
            paths:
            - backend:
                service:
                  name: kuboard-v3
                  port:
                    number: 80
              path: /
              pathType: Prefix
      status:
        loadBalancer: {}
      
  • 访问