Ingress TLS Easy setup

在上一篇文章中,我們介紹了 Kubernetes Ingress 與 Nginx Ingress Controller 的基本使用方法。本篇文章將進一步說明如何為 Ingress 配置 TLS(HTTPS),讓服務可以透過加密的 HTTPS 協議安全地提供外部訪問。

目錄


1. Ingress TLS 簡介

當 Kubernetes Ingress 需要支援 HTTPS,我們必須配置 TLS 憑證。通常有兩種方式:

  1. 使用真實 CA(Certificate Authority)簽發的證書

  2. 使用自簽證書(Self-Signed Certificate)(適用於本地測試環境)

這篇文章會使用 自簽證書 來演示如何啟用 TLS,並將其綁定到 AP 服務(app.caster.com)MySQL 服務(mysql.caster.com)


2. 建立與生成自簽證書(Local 測試)

我們將使用 openssl 生成自簽證書,並設定 域名 caster.com

步驟 1:生成私鑰與證書

執行以下指令來生成一個 2048-bit RSA 私鑰:

openssl req -x509 -nodes -days 365 -keyout caster_com.key -out caster_com.crt -config ssl.conf
// ssl.conf
[req]
default_bits       = 2048
default_keyfile    = privkey.pem
distinguished_name = req
x509_extensions    = v3_ca
prompt = no
utf8 = yes

[dn]
C = TW
ST = Taiwan
L = Taipei
O = Caster Inc.
OU = IT Department
emailAddress = service@caster.com

[ req_distinguished_name ]
CN = *.caster.com

[v3_req]
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.caster.com

步驟 2:驗證憑證

確認 caster_com.keycaster_com.crt 是否成功生成:

ls -l caster_com.*

3. 建立 Kubernetes Secret

現在我們需要將 憑證私鑰 轉換為 Kubernetes Secret,讓 Ingress Controller 可以使用它們。

執行以下命令來創建 Secret(名稱為 caster-tls

kubectl create secret tls caster-tls --key caster_com.key --cert caster_com.crt

檢查 Secret 是否成功建立:

kubectl get secret caster-tls

輸出應該類似:

NAME         TYPE                DATA   AGE
caster-tls   kubernetes.io/tls   2      5s

4. 更新 Ingress 資源,啟用 TLS

接下來,我們需要修改 Ingress 配置,新增 TLS 設定,並綁定剛剛創建的 Secret。 記得先把之前的 ingress.yml 停用,建立新的 tls-ingress.yaml

編輯 tls-ingress.yaml

# tls-ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
    name: caster-ingress
    namespace: default
    labels:
        app.kubernetes.io/name: caster-ingress
    annotations:
        nginx.ingress.kubernetes.io/rewrite-target: /
spec:
    ingressClassName: nginx
    tls:
        -   hosts:
                - "app.caster.com"
#                - "mysql.caster.com" # 我目前也不知道這樣是否會生效....
            secretName: caster-tls
    rules:
        -   host: app.caster.com  # 替換為你的域名
            http:
                paths:
                    -   path: /
                        pathType: Prefix
                        backend:
                            service:
                                # 你要提供服務的 k8s Service 名稱以及他的 port
                                name: normal-project-service
                                port:
                                    number: 9000
        -   host: mysql.caster.com  # 替換為你的域名
            http:
                paths:
                    -   path: /
                        pathType: Prefix
                        backend:
                            service:
                                # 你要提供服務的 k8s Service 名稱以及他的 port
                                name: mysql-service
                                port:
                                    number: 3309

套用 Ingress 配置:

kubectl apply -f ingress.yaml

5. 測試 HTTPS 訪問

步驟 1:應用新的 Ingress

kubectl apply -f tls-ingress.yaml

步驟 2:修改 /etc/hosts

因為 app.caster.com 不是一個真實域名,我們需要手動將其解析到 Ingress Controller 的 IP: windows 位置: C:\Windows\System32\drivers\etc\hosts

# 為了方便後續測試,我是有先把會用到的域名都先補上。
172.20.61.17 app.caster.com
172.20.61.17 mysql.caster.com
172.20.61.17 redis.caster.com
172.20.61.17 zookeeper.caster.com

步驟 3:使用 curl 測試 HTTPS

curl -k https://app.caster.com/common/healthy

-k 參數 允許 curl 忽略自簽證書的安全警告。

如果一切正常,應該能夠看到來自 normal-project 的回應。

C:\Users\caster>curl -k https://app.caster.com/common/healthy
{"appVersion":"V1.1.2","podIp":"10.1.0.132","time":"2025-02-04T07:26:53.39806","podId":"0d429a0d-d11d-45ee-9dff-f86b6ff47817"}

※額外測試 mysql.caste.com 連線至DB (這部分測試僅限再本機環境才會達成)

🚀 問題分析

  1. 你透過 Ingress 設定 mysql.caster.com,但 Ingress 只處理 HTTP/HTTPS,並不適用於 MySQL(TCP 服務)

    • Ingress Controller(如 ingress-nginx)主要負責 HTTP 流量,不支援 MySQL 這類 TCP 服務的轉發

    • 你的 MySQL 服務跑在 TCP 3309,所以 Ingress Controller 根本不會處理這個請求。

  2. Service Type 設定影響 MySQL 的可達性

    • NodePort 模式:

      • 你應該直接連接 NodeIP:NodePort(而不是 mysql.caster.com:3309)。

      • NodePort 會在每個 Kubernetes 節點上開一個高位元的 Port(例如 32023)。

      • 但 Ingress 不會轉發 TCP 連線到 NodePort,所以你的 mysql.caster.com:3309 連線失敗。

    • LoadBalancer 模式:

      • 如果你在 雲端環境(AWS, GCP, Azure),Kubernetes 會為 MySQL 申請一個外部 LoadBalancer IP,讓 mysql.caster.com:3309 直接連到 MySQL。

      • 在本機(如 Minikube, Kind),LoadBalancer 會自動綁定 localhost,讓 mysql.caster.com:3309 連線成功

🚨 重要結論

  • Ingress 不能處理 MySQL(TCP)流量,不能靠它轉發 MySQL 服務!

  • 如果用 NodePort,請連 NodeIP:NodePort,而不是 mysql.caster.com:3309

  • 如果用 LoadBalancer,可以直接連 mysql.caster.com:3309(但本機環境可能不支援真正的 LoadBalancer)

所以我使用 Intellij database tool 連線成功,完全是亂用這個機制,也是因為我的 hosts 檔案修改才會有這樣的結果,當然本機環境本來就是拿來測試使用的,就...亂用...

使用域名去連線K8S MySQL 但不確定要怎麼使用SSL 方式去連線...

可以確定這樣的做法,完全不能算是使用SSL連線,上網查了一下,還有一大堆設定要搞,痾.... 我沒有那們多的時間玩這個,這部分就先這樣,後續有時間再搞了...


6. 總結

在本文中,我們介紹了如何在 Kubernetes Nginx Ingress Controller 上啟用 TLS/HTTPS,主要步驟如下:

  1. 使用 openssl 生成 自簽證書(適用於 Local 測試)。

  2. 創建 Kubernetes Secret,存儲憑證和私鑰。

  3. 更新 Ingress 資源,添加 tls 設定並綁定 Secret。

  4. 測試 HTTPS 訪問。

這種方式適合 本地開發和測試環境,如果是 正式環境,建議使用 Let's EncryptCA 簽發的 SSL 憑證 來實現更安全的 HTTPS 部署。


💡 進階閱讀

Last updated