Skip to content

antony@notes:~/networking$ cat "Cert-manager-with-SelfSigned-Issuers.md"

Cert-manager with SelfSigned Issuers

2024-04-15· networking

Cert-manager with SelfSigned Issuers

實作目標

透過 Cert-manager 產生自簽 CA 憑證,再透過這個自簽的 CA 憑證簽發給 Ingress 用的 TLS 憑證,最後建一個 Nginx 來測試 TLS Ingress 是否符合預期,且憑證到期時間會自動更新。

先備知識

Issuer

Issuers 和 ClusterIssuers 是 Kubernetes 中的資源,代表著憑證授權機構(certificate authorities [CAs]),它們可以通過證書簽名請求 ( certificate signing requests )來生成簽名的證書 ( signed certificates )。

# 建立工作目錄
$ mkdir -p ~/wulin/cert-manager && cd ~/wulin/cert-manager

# 建立 selfsigned Issuer
$ cat <<EOF > default-selfsigned-issuer
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: selfsigned-issuer
  namespace: default
spec:
  selfSigned: {}
EOF

$ kubectl apply -f default-selfsigned-issuer

# 檢查 Issuer 的狀態
$ kubectl get issuers selfsigned-issuer -o wide
NAME                READY   STATUS   AGE
selfsigned-issuer   True             15d

# Bootstrapping CA Issuers
$ cat <<EOF > default-ca.certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: my-selfsigned-ca
  namespace: default
spec:
  isCA: true
  commonName: my-selfsigned-ca
  secretName: root-secret
  subject:
    organizations:
      - Lab
    organizationalUnits:
      - Test
  duration: 2h
  renewBefore: 1h
  privateKey:
    algorithm: ECDSA
    size: 256
  issuerRef:
    name: selfsigned-issuer
    kind: Issuer
    group: cert-manager.io
EOF

$ kubectl apply -f default-ca.certificate.yaml

# 可以看到 root-secret ( CA 憑證 ) 已經被自動生成,並存在 Secret 中
$ kubectl get certificate my-selfsigned-ca -o wide
NAME               READY   SECRET        ISSUER              STATUS                                          AGE
my-selfsigned-ca   True    root-secret   selfsigned-issuer   Certificate is up to date and has not expired   22s

# 檢視 root-secret
$ kubectl get secret root-secret -o yaml
apiVersion: v1
data:
  ca.crt: 
...
  tls.crt: 
...
  tls.key:
...

# 
$ cat <<EOF > default-my-ca-issuer.yaml
apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
  name: my-ca-issuer
  namespace: default
spec:
  ca:
    secretName: root-secret
EOF

$ kubectl apply -f default-my-ca-issuer.yaml

$ kubectl get issuers my-ca-issuer -o wide
NAME           READY   STATUS                AGE
my-ca-issuer   True    Signing CA verified   8m12s

Run Nginx with TLS Ingress

$ kubectl run nginx --image=harbor.example.com/rancher/library-nginx:1.19.2-alpine -l run=nginx

$ kubectl get pods -l run=nginx -o wide
NAME    READY   STATUS    RESTARTS   AGE   IP            NODE   NOMINATED NODE   READINESS GATES
nginx   1/1     Running   0          18s   10.42.44.57   k2w1   <none>           <none>

$ NGINX_PodIP=$(kubectl get pods -l run=nginx -o custom-columns=POD_IP:.status.podIP --no-headers)

$ curl http://$NGINX_PodIP
...
<title>Welcome to nginx!</title>
...

# Create TLS Ingress
$ cat <<EOF > default-tls-nginx-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: tls-nginx-ingress
  namespace: default
  annotations:
    # add an annotation indicating the issuer to use.
    cert-manager.io/issuer: my-ca-issuer
spec:
  ingressClassName: nginx
  tls:
  - hosts:
      - 192.168.11.174.nip.io
    secretName: tls-nginx-ingress
  rules:
  - host: 192.168.11.174.nip.io
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: nginx
            port:
              number: 80
EOF

# 檢視 Ingress 部屬狀態
$ kubectl get ing
NAME                CLASS   HOSTS                   ADDRESS                         PORTS     AGE
tls-nginx-ingress   nginx   192.168.11.174.nip.io   192.168.11.173,192.168.11.174   80, 443   45s

# 測試透過 Ingress 連接網站
$ curl -k https://192.168.11.174.nip.io
...
<title>Welcome to nginx!</title>
...

# 匯出 CA 憑證
$ kubectl get secret root-secret -o jsonpath='{.data.ca\.crt}' | base64 -d >
ing-ca.crt

$ sudo cp ing-ca.crt /etc/pki/ca-trust/source/anchors/ && sudo sudo update-ca-trust

# 這次 curl 就不用加 -k 跳過憑證確認了
$ curl https://192.168.11.174.nip.io
...
<title>Welcome to nginx!</title>
...

# 檢視憑證過期日期
$ echo | openssl s_client -connect 192.168.11.174.nip.io:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Apr 15 03:08:33 2024 GMT
notAfter=Jul 14 03:08:33 2024 GMT

# 下載 Cert-manager 管理工具
$ curl -fsSL -o cmctl.tar.gz https://github.com/cert-manager/cert-manager/releases/latest/download/cmctl-linux-amd64.tar.gz && tar xzf cmctl.tar.gz && sudo mv cmctl /usr/local/bin

# 手動 renew 憑證到期日期
$ cmctl renew tls-nginx-ingress
Manually triggered issuance of Certificate default/tls-nginx-ingress

$ echo | openssl s_client -connect 192.168.11.174.nip.io:443 2>/dev/null | openssl x509 -noout -dates
notBefore=Apr 15 03:32:44 2024 GMT
notAfter=Jul 14 03:32:44 2024 GMT

# 清除環境
$ kubectl delete -f ./ && kubectl delete pod nginx
certificate.cert-manager.io "my-selfsigned-ca" deleted
issuer.cert-manager.io "my-ca-issuer" deleted
issuer.cert-manager.io "selfsigned-issuer" deleted
ingress.networking.k8s.io "tls-nginx-ingress" deleted
pod "nginx" deleted

流程圖解

https://cert-manager.io/docs/usage/ingress/#inner-workings-diagram-for-developers