本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

適用於 Kubernetes 服務的強大、簡單 SSL

嗨,我是 Evan Brown (@evandbrown),我在 Google Cloud Platform 的解決方案架構團隊工作。我最近撰寫了一篇文章教學,關於在 Kubernetes 上使用 Jenkins 自動化 Docker 和 GCE 映像檔建置流程。今天我將討論如何使用 Kubernetes 服務和密鑰為 Jenkins 網頁 UI 新增 SSL。閱讀本文後,您將能夠為您的公開 HTTP Kubernetes 服務新增 SSL 終止(和 HTTP->HTTPS 重新導向 + 基本驗證)。

起初

秉持最低可行性的精神,我建置的第一個 Jenkins-on-Kubernetes 版本非常基本但功能齊全

  • Jenkins 領導者只是一個 Pod 中的單一容器,但由複寫控制器管理,因此如果它失敗,它會自動重新產生。
  • Jenkins 領導者公開兩個連接埠 - TCP 8080 用於網頁 UI,TCP 50000 用於建置代理程式註冊 - 這些連接埠以 Kubernetes 服務的形式提供,並具有公用負載平衡器。

以下是第一個版本的視覺呈現

這可以運作,但我對此有一些問題。首先,預設 Jenkins 安裝中未設定驗證。領導者位於公共網際網路上,任何人都可以存取,直到您連線並設定驗證為止。由於沒有加密,因此設定驗證只是一種象徵性的姿態。我們需要 SSL,而且我們現在就需要它!

做您知道的事

在幾毫秒內,我考慮嘗試直接在 Jenkins 上讓 SSL 運作。我以前從未做過,我發現自己在想,它是否會像在 Nginx 上使用 SSL 一樣直接,這是我有經驗的事情。我非常贊成學習新事物,但這似乎是一個不重新發明輪子的好地方:Nginx 上的 SSL 很直接且有完善的文件記錄(其反向 Proxy 功能也是如此),而 Kubernetes 完全是關於透過協調和組合容器來建置功能。讓我們使用 Nginx,並新增一些 Nginx 使其變得簡單的額外功能:HTTP->HTTPS 重新導向和基本存取驗證。

作為 Nginx 服務的 SSL 終止 Proxy

我首先組合了一個 Dockerfile,它繼承自標準 Nginx 映像檔,複製了一些 Nginx 組態檔,並新增了一個自訂進入點 (start.sh)。進入點腳本檢查環境變數 (ENABLE_SSL) 並相應地啟動正確的 Nginx 組態(表示未加密的 HTTP 反向 Proxy 是可能的,但這會破壞目的)。如果啟用了基本存取驗證(ENABLE_BASIC_AUTH 環境變數),腳本也會設定它。

最後,start.sh 評估 SERVICE_HOST_ENV_NAME 和 SERVICE_PORT_ENV_NAME 環境變數。這些變數應設定為您要 Proxy 到的 Kubernetes 服務的環境變數名稱。在此範例中,我們的 Jenkins 領導者的服務巧妙地命名為 jenkins,這表示叢集中的 Pod 將看到名為 JENKINS_SERVICE_HOST 和 JENKINS_SERVICE_PORT_UI 的環境變數(連接埠 8080 對應到 Jenkins 領導者上的連接埠)。SERVICE_HOST_ENV_NAME 和 SERVICE_PORT_ENV_NAME 只是參考用於特定場景的正確服務,允許映像檔在跨部署中通用。

定義控制器和服務

與此範例中的每個其他 Pod 一樣,我們將使用複寫控制器部署 Nginx,允許我們向外或向內擴充,並從容器故障中自動復原。此摘錄來自範例應用程式中的完整描述符,顯示了 Pod 規格的一些相關部分

  spec:

    containers:

      -

        name: "nginx-ssl-proxy"

        image: "gcr.io/cloud-solutions-images/nginx-ssl-proxy:latest"

        env:

          -

            name: "SERVICE\_HOST\_ENV\_NAME"

            value: "JENKINS\_SERVICE\_HOST"

          -

            name: "SERVICE\_PORT\_ENV\_NAME"

            value: "JENKINS\_SERVICE\_PORT\_UI"

          -

            name: "ENABLE\_SSL"

            value: "true"

          -

            name: "ENABLE\_BASIC\_AUTH"

            value: "true"

        ports:

          -

            name: "nginx-ssl-proxy-http"

            containerPort: 80

          -

            name: "nginx-ssl-proxy-https"

            containerPort: 443

Pod 將具有一個服務,將 TCP 80 和 443 公開給公用負載平衡器。以下是服務描述符 (也可在範例應用程式中取得)

  kind: "Service"

  apiVersion: "v1"

  metadata:

    name: "nginx-ssl-proxy"

    labels:

      name: "nginx"

      role: "ssl-proxy"

  spec:

    ports:

      -

        name: "https"

        port: 443

        targetPort: "nginx-ssl-proxy-https"

        protocol: "TCP"

      -

        name: "http"

        port: 80

        targetPort: "nginx-ssl-proxy-http"

        protocol: "TCP"

    selector:

      name: "nginx"

      role: "ssl-proxy"

    type: "LoadBalancer"

以下是安裝 SSL 終止 Proxy 後的概觀。請注意,Jenkins 不再直接公開於公共網際網路

現在,Nginx Pod 如何取得超級機密的 SSL 金鑰/憑證和 htpasswd 檔案(用於基本存取驗證)?

保持機密,保持安全

Kubernetes 具有API 和 Secrets 資源。Secrets「旨在保存敏感資訊,例如密碼、OAuth 權杖和 ssh 金鑰。將此資訊放入 Secret 中比直接將其逐字放入 Pod 定義或 Docker 映像檔中更安全且更靈活。」

您可以在 3 個簡單步驟中在您的叢集中建立 Secret

Base64 編碼您的 Secret 資料(即 SSL 金鑰組或 htpasswd 檔案)

$ cat ssl.key | base64  
   LS0tLS1CRUdJTiBDRVJUS...

建立描述您的 Secret 的 json 文件,並新增 base64 編碼的值

  apiVersion: "v1"

  kind: "Secret"

  metadata:

    name: "ssl-proxy-secret"

    namespace: "default"

  data:

    proxycert: "LS0tLS1CRUd..."

    proxykey: "LS0tLS1CR..."

    htpasswd: "ZXZhb..."

建立 Secrets 資源

$ kubectl create -f secrets.json

若要從容器存取 Secret,請在您的 Pod 規格中將它們指定為磁碟區掛載。以下是我們稍早看到的 Nginx Proxy 範本中的相關摘錄

  spec:

    containers:

      -

        name: "nginx-ssl-proxy"

        image: "gcr.io/cloud-solutions-images/nginx-ssl-proxy:latest"

        env: [...]

        ports: ...[]

        volumeMounts:

          -

            name: "secrets"

            mountPath: "/etc/secrets"

            readOnly: true

    volumes:

      -

        name: "secrets"

        secret:

          secretName: "ssl-proxy-secret"

定義了指向 ssl-proxy-secret Secret 資源的 Secret 類型磁碟區,然後將其掛載到容器中的 /etc/secrets 中。稍早範例中的 Secrets 規格定義了 data.proxycert、data.proxykey 和 data.htpasswd,因此我們將看到這些檔案(base64 解碼)出現在 /etc/secrets/proxycert、/etc/secrets/proxykey 和 /etc/secrets/htpasswd 中,供 Nginx 處理程序存取。

現在一起來

我一直都有「容器和 Kubernetes 很有趣又很酷!」的時刻,可能每天都有。我開始更頻繁地有「容器和 Kubernetes 非常有用且功能強大,並且透過幫助我輕鬆完成重要的事情,為我所做的事情增加價值」的時刻。這個使用 Nginx 的 SSL 終止 Proxy 範例絕對是後者之一。我沒有浪費時間學習使用 SSL 的新方法。我能夠以可重複使用的方式,快速地使用眾所周知的工具解決我的問題(從想法到運作大約花了 2 個小時)。

查看完整的使用 Jenkins、Packer 和 Kubernetes 自動化映像檔建置儲存庫,以了解 SSL 終止 Proxy 如何在真實叢集中使用,或深入研究 nginx-ssl-proxy 儲存庫中的 Proxy 映像檔詳細資訊(包含 Dockerfile 和 Packer 範本,因此您可以自行建置映像檔)。