新消息:在TwitterMastodon取得專案更新

保護 NGINX-ingress

本教學將詳細說明如何使用 NGINX 安裝並保護叢集的入口。

步驟 1 - 安裝 Helm

如果已安裝 helm,請跳過此節。

安裝 cert-manager 最簡單的方式是使用 Helm,這是一種 Kubernetes 資源的範本化和部署工具。

首先,請依照 Helm 安裝指示,確保 Helm 用戶端已安裝。

例如,在 MacOS 上

brew install kubernetes-helm

步驟 2 - 部署 NGINX Ingress 控制器

Kubernetes ingress 控制器 的設計目的是作為 HTTP 和 HTTPS 流量進入您叢集中執行之軟體的存取點。ingress-nginx-controller 透過雲端供應商的負載平衡器支援的 HTTP Proxy 服務來完成此作業。

您可以從 ingress-nginx 文件中取得關於 ingress-nginx 及其運作方式的詳細資訊。

新增 ingress-nginx 的最新 helm 儲存庫

helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

使用最新的圖表更新 helm 儲存庫

$ helm repo update
Hang tight while we grab the latest from your chart repositories...
...Skip local chart repository
...Successfully got an update from the "stable" chart repository
...Successfully got an update from the "ingress-nginx" chart repository
...Successfully got an update from the "coreos" chart repository
Update Complete. ⎈ Happy Helming!

使用 helm 安裝 NGINX Ingress 控制器

$ helm install quickstart ingress-nginx/ingress-nginx
NAME: quickstart
... lots of output ...

雲端供應商可能需要一到兩分鐘的時間來提供並連結公用 IP 位址。完成後,您可以使用 kubectl 命令來查看外部 IP 位址

$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 13m
quickstart-ingress-nginx-controller LoadBalancer 10.0.114.241 <pending> 80:31635/TCP,443:30062/TCP 8m16s
quickstart-ingress-nginx-controller-admission ClusterIP 10.0.188.24 <none> 443/TCP 8m16s

此命令會顯示您叢集中的所有服務 (在 default 命名空間中),以及它們擁有的任何外部 IP 位址。當您第一次建立控制器時,您的雲端供應商將不會透過 LoadBalancer 指派和配置 IP 位址。在此之前,該服務的外部 IP 位址會列為 <pending>

您的雲端供應商可能有選項可以在建立入口控制器之前保留 IP 位址,並使用該 IP 位址,而不是從集區指派 IP 位址。請詳閱您的雲端供應商的文件,瞭解如何安排。

步驟 3 - 指派 DNS 名稱

分配給入口控制器的外部 IP 是所有傳入流量應路由到的 IP。若要啟用此功能,請將其新增到您控制的 DNS 區域,例如 www.example.com

此快速入門假設您知道如何將 DNS 項目指派給 IP 位址,並將執行此動作。

步驟 4 - 部署範例服務

您的服務可能會有自己的圖表,或者您可能會使用資訊清單直接部署它。此快速入門會使用資訊清單來建立並公開範例服務。範例服務使用 kuard,這是一個示範應用程式。

快速入門範例會使用三個資訊清單來做為範例。前兩個是範例部署和相關聯的服務

apiVersion: apps/v1
kind: Deployment
metadata:
name: kuard
spec:
selector:
matchLabels:
app: kuard
replicas: 1
template:
metadata:
labels:
app: kuard
spec:
containers:
- image: gcr.io/kuar-demo/kuard-amd64:1
imagePullPolicy: Always
name: kuard
ports:
- containerPort: 8080
apiVersion: v1
kind: Service
metadata:
name: kuard
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
selector:
app: kuard

您可以在本機建立下載並參考這些檔案,或者您可以從此文件的 GitHub 原始程式碼儲存庫中參考這些檔案。若要直接從 GitHub 的教學檔案中安裝範例服務,請執行以下動作

kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/deployment.yaml
# expected output: deployment.extensions "kuard" created
kubectl apply -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/service.yaml
# expected output: service "kuard" created

Ingress 資源是 Kubernetes 用來在叢集外部公開此範例服務的方式。您需要下載並修改範例資訊清單,以反映您擁有或控制的網域,才能完成此範例。

您可以從以下範例 Ingress 開始

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations: {}
#cert-manager.io/issuer: "letsencrypt-staging"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.example.com
secretName: quickstart-example-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80

您可以從 GitHub 下載範例資訊清單、編輯它,並使用以下命令將資訊清單提交至 Kubernetes。在您的編輯器中編輯該檔案,一旦儲存

kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress.yaml
# expected output: ingress.networking.k8s.io/kuard created

注意:我們在上面顯示的 Ingress 範例中具有 host 定義。ingress-nginx-controller 會在要求的主機名稱符合 Ingress 中的定義時路由流量。您可以部署沒有規則中 host 定義的 Ingress,但該模式不能與 TLS 憑證搭配使用,TLS 憑證需要完整合格的網域名稱。

一旦部署完成,您可以使用命令 kubectl get ingress 來查看 Ingress 的狀態

NAME HOSTS ADDRESS PORTS AGE
kuard * 80, 443 17s

根據您的服務供應商,Ingress 可能需要幾分鐘才能完全建立。當它建立並連結到位時,Ingress 也會顯示位址

NAME HOSTS ADDRESS PORTS AGE
kuard * 203.0.113.2 80 9m

注意:Ingress 上的 IP 位址可能不符合 ingress-nginx-controller 的 IP 位址。這很正常,而且是託管您 Kubernetes 叢集的服務供應商的怪癖/實作細節。由於我們使用的是 ingress-nginx-controller,而不是任何雲端供應商特定的 Ingress 後端,請使用為 quickstart-ingress-nginx-controller LoadBalancer 資源定義和配置的 IP 位址,做為服務的主要存取點。

請確定服務可從您在上方新增的網域名稱連線,例如 http://www.example.com。最簡單的方式是開啟瀏覽器,然後輸入您在 DNS 中設定的名稱,我們剛才為其新增了 Ingress。

您也可以使用 curl 之類的命令列工具來檢查 Ingress。

$ curl -kivL -H 'Host: www.example.com' 'http://203.0.113.2'

此 curl 命令上的選項會提供詳細的輸出、遵循任何重新導向、在輸出中顯示 TLS 標頭,並且不會因不安全的憑證而發生錯誤。使用 ingress-nginx-controller 時,該服務將提供 TLS 憑證,但它會使用 ingress-nginx-controller 預設提供的自我簽署憑證。瀏覽器會顯示警告,指出此為無效憑證。這是預期且正常的,因為我們尚未讓 cert-manager 為我們的網站取得完全信任的憑證。

警告:務必確定您的 Ingress 可用,並在網際網路上正確回應。此快速入門範例會使用 Let's Encrypt 來提供憑證,這會預期並驗證該服務可用,並在頒發憑證的過程中使用該驗證來證明網域的要求屬於對網域具有足夠控制權的使用者。

步驟 5 - 部署 cert-manager

我們需要安裝 cert-manager,才能使用 Kubernetes 要求憑證並回應挑戰以進行驗證。我們可以使用 Helm 或純 Kubernetes 資訊清單來安裝 cert-manager。

由於我們稍早安裝了 Helm,因此我們假設您想要使用 Helm;請遵循Helm 指南。如需其他方法,請閱讀 cert-manager 的安裝文件

cert-manager 主要使用兩種不同的 Kubernetes 自訂資源(稱為CRD)來設定和控制其運作方式,以及儲存狀態。這些資源是簽發者(Issuers)和憑證(Certificates)。

簽發者(Issuers)

簽發者定義 cert-manager 將如何請求 TLS 憑證。簽發者特定於 Kubernetes 中的單一命名空間,但也有一個 ClusterIssuer,它被設計為叢集範圍的版本。

請務必確保您的簽發者與您想要建立的憑證位於相同的命名空間中。您可能需要在 kubectl create 命令中加入 -n my-namespace

您的另一個選擇是用 ClusterIssuers 取代 IssuersClusterIssuer 資源適用於您叢集中的所有 Ingress 資源。如果使用 ClusterIssuer,請記得將 Ingress 註解 cert-manager.io/issuer 更新為 cert-manager.io/cluster-issuer

如果您發現簽發者有問題,請遵循簽發 ACME 憑證的疑難排解指南。

有關 IssuersClusterIssuers 之間的差異的更多資訊(包括您可能選擇使用每個選項的時間)可以在簽發者概念中找到。

憑證(Certificates)

憑證資源允許您指定要請求的憑證的詳細資訊。它們會參考一個簽發者來定義它們將如何被簽發。

更多資訊,請參閱憑證概念

步驟 6 - 設定 Let's Encrypt 簽發者

在這個範例中,我們將為 Let's Encrypt 設定兩個簽發者:staging 和 production。

Let's Encrypt production 簽發者有非常嚴格的速率限制。當您在實驗和學習時,很容易就會達到這些限制。由於這種風險,我們將從 Let's Encrypt staging 簽發者開始,一旦我們對其運作感到滿意,我們就會切換到 production 簽發者。

請注意,您會看到來自 staging 簽發者關於不受信任憑證的警告,但這是完全預期的。

在本機建立此定義並將電子郵件地址更新為您自己的。此電子郵件是 Let's Encrypt 所必需的,用於通知您憑證到期和更新。

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-staging
spec:
acme:
# The ACME server URL
server: https://acme-staging-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-staging
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
ingressClassName: nginx

編輯完成後,套用自訂資源

kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/staging-issuer.yaml
# expected output: issuer.cert-manager.io "letsencrypt-staging" created

同時建立一個 production 簽發者並部署它。與 staging 簽發者一樣,您需要更新此範例並加入您自己的電子郵件地址。

apiVersion: cert-manager.io/v1
kind: Issuer
metadata:
name: letsencrypt-prod
spec:
acme:
# The ACME server URL
server: https://acme-v02.api.letsencrypt.org/directory
# Email address used for ACME registration
email: user@example.com
# Name of a secret used to store the ACME account private key
privateKeySecretRef:
name: letsencrypt-prod
# Enable the HTTP-01 challenge provider
solvers:
- http01:
ingress:
ingressClassName: nginx
kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/production-issuer.yaml
# expected output: issuer.cert-manager.io "letsencrypt-prod" created

這兩個簽發者都設定為使用 HTTP01 挑戰提供者。

在建立簽發者後檢查其狀態

$ kubectl describe issuer letsencrypt-staging
Name: letsencrypt-staging
Namespace: default
Labels: <none>
Annotations: kubectl.kubernetes.io/last-applied-configuration={"apiVersion":"cert-manager.io/v1","kind":"Issuer","metadata":{"annotations":{},"name":"letsencrypt-staging","namespace":"default"},(...)}
API Version: cert-manager.io/v1
Kind: Issuer
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T18:03:54Z
Generation: 0
Resource Version: 9092
Self Link: /apis/cert-manager.io/v1/namespaces/default/issuers/letsencrypt-staging
UID: 25b7ae77-ea93-11e8-82f8-42010a8a00b5
Spec:
Acme:
Email: email@example.com
Private Key Secret Ref:
Key:
Name: letsencrypt-staging
Server: https://acme-staging-v02.api.letsencrypt.org/directory
Solvers:
Http 01:
Ingress:
Class: nginx
Status:
Acme:
Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7374163
Conditions:
Last Transition Time: 2018-11-17T18:04:00Z
Message: The ACME account was registered with the ACME server
Reason: ACMEAccountRegistered
Status: True
Type: Ready
Events: <none>

您應該看到已註冊帳戶的簽發者。

步驟 7 - 部署 TLS Ingress 資源

在完成所有必要設定後,我們現在可以進行請求 TLS 憑證的步驟。主要有兩種方法可以做到這一點:在 ingress 上使用註解搭配 ingress-shim,或直接建立憑證資源。

在這個範例中,我們將在 ingress 中加入註解,並利用 ingress-shim 代表我們建立憑證資源。建立憑證後,cert-manager 將更新或建立 ingress 資源,並使用該資源來驗證網域。驗證和簽發後,cert-manager 將建立或更新在憑證中定義的密鑰。

注意:ingress 中使用的密鑰應與憑證中定義的密鑰相符。沒有任何明確的檢查,因此輸入錯誤會導致 ingress-nginx-controller 回退到其自我簽署的憑證。在我們的範例中,我們正在 ingress 上使用註解(和 ingress-shim),這將代表您建立正確的密鑰。

編輯 ingress 以加入我們在較早範例中註解掉的註解

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations:
cert-manager.io/issuer: "letsencrypt-staging"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.example.com
secretName: quickstart-example-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80

並套用它

kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls.yaml
# expected output: ingress.networking.k8s.io/kuard configured

cert-manager 將讀取這些註解並使用它們來建立憑證,您可以請求並查看該憑證

$ kubectl get certificate
NAME READY SECRET AGE
quickstart-example-tls True quickstart-example-tls 16m

cert-manager 會在憑證物件中反映每個請求的處理狀態。您可以使用 kubectl describe 命令檢視此資訊

$ kubectl describe certificate quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T17:58:37Z
Generation: 0
Owner References:
API Version: networking.k8s.io/v1
Block Owner Deletion: true
Controller: true
Kind: Ingress
Name: kuard
UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
Resource Version: 9295
Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tls
UID: 68d43400-ea92-11e8-82f8-42010a8a00b5
Spec:
Dns Names:
www.example.com
Issuer Ref:
Kind: Issuer
Name: letsencrypt-staging
Secret Name: quickstart-example-tls
Status:
Acme:
Order:
URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/7374163/13665676
Conditions:
Last Transition Time: 2018-11-17T18:05:57Z
Message: Certificate issued successfully
Reason: CertIssued
Status: True
Type: Ready
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal CreateOrder 9m cert-manager Created new ACME order, attempting validation...
Normal DomainVerified 8m cert-manager Domain "www.example.com" verified with "http-01" validation
Normal IssueCert 8m cert-manager Issuing certificate...
Normal CertObtained 7m cert-manager Obtained certificate from ACME server
Normal CertIssued 7m cert-manager Certificate issued Successfully

與此資源相關聯並列在 describe 結果底部的事件會顯示請求的狀態。在上面的範例中,憑證在幾分鐘內被驗證並簽發。

完成後,cert-manager 將根據 ingress 資源中使用的密鑰建立包含憑證詳細資訊的密鑰。您也可以使用 describe 命令來查看一些詳細資訊

$ kubectl describe secret quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: cert-manager.io/certificate-name=quickstart-example-tls
Annotations: cert-manager.io/alt-names=www.example.com
cert-manager.io/common-name=www.example.com
cert-manager.io/issuer-kind=Issuer
cert-manager.io/issuer-name=letsencrypt-staging
Type: kubernetes.io/tls
Data
====
tls.crt: 3566 bytes
tls.key: 1675 bytes

現在我們確信一切都已正確設定,您可以更新 ingress 中的註解以指定 production 簽發者

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: kuard
annotations:
cert-manager.io/issuer: "letsencrypt-prod"
spec:
ingressClassName: nginx
tls:
- hosts:
- example.example.com
secretName: quickstart-example-tls
rules:
- host: example.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: kuard
port:
number: 80
$ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls-final.yaml
ingress.networking.k8s.io/kuard configured

您還需要刪除現有的密鑰,cert-manager 正在監視該密鑰,這將導致它使用更新後的簽發者重新處理請求。

$ kubectl delete secret quickstart-example-tls
secret "quickstart-example-tls" deleted

這將啟動取得新憑證的程序,並且您可以使用 describe 來查看狀態。一旦 production 憑證已更新,您應該會在您的網域上看到範例 KUARD 正在運行,並且具有簽署的 TLS 憑證。

$ kubectl describe certificate quickstart-example-tls
Name: quickstart-example-tls
Namespace: default
Labels: <none>
Annotations: <none>
API Version: cert-manager.io/v1
Kind: Certificate
Metadata:
Cluster Name:
Creation Timestamp: 2018-11-17T18:36:48Z
Generation: 0
Owner References:
API Version: networking.k8s.io/v1
Block Owner Deletion: true
Controller: true
Kind: Ingress
Name: kuard
UID: a3e9f935-ea87-11e8-82f8-42010a8a00b5
Resource Version: 283686
Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tls
UID: bdd93b32-ea97-11e8-82f8-42010a8a00b5
Spec:
Dns Names:
www.example.com
Issuer Ref:
Kind: Issuer
Name: letsencrypt-prod
Secret Name: quickstart-example-tls
Status:
Conditions:
Last Transition Time: 2019-01-09T13:52:05Z
Message: Certificate does not exist
Reason: NotFound
Status: False
Type: Ready
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Generated 18s cert-manager Generated new private key
Normal OrderCreated 18s cert-manager Created Order resource "quickstart-example-tls-889745041"

您可以透過在 cert-manager 為您的憑證建立的 Order 資源上執行 kubectl describe,來查看 ACME 訂單的目前狀態

$ kubectl describe order quickstart-example-tls-889745041
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"

在這裡,我們可以看到 cert-manager 已建立 1 個「挑戰」(Challenge)資源來完成訂單。您可以透過在自動建立的 Challenge 資源上執行 kubectl describe,來深入了解目前 ACME 挑戰的狀態

$ kubectl describe challenge quickstart-example-tls-889745041-0
...
Status:
Presented: true
Processing: true
Reason: Waiting for http-01 challenge propagation
State: pending
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 15s cert-manager Challenge scheduled for processing
Normal Presented 14s cert-manager Presented challenge using http-01 challenge mechanism

從上面可以看出,挑戰已被「呈現」,並且 cert-manager 正在等待挑戰記錄傳播到 ingress 控制器。您應該留意挑戰資源上的新事件,因為大約一分鐘後(取決於您的 ingress 控制器更新規則的速度),應該會印出「成功」事件

$ kubectl describe challenge quickstart-example-tls-889745041-0
...
Status:
Presented: false
Processing: false
Reason: Successfully authorized domain
State: valid
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Started 71s cert-manager Challenge scheduled for processing
Normal Presented 70s cert-manager Presented challenge using http-01 challenge mechanism
Normal DomainVerified 2s cert-manager Domain "www.example.com" verified with "http-01" validation

注意:如果您的挑戰沒有變成「有效」並且保持在「待處理」狀態(或進入「失敗」狀態),則很可能存在某種設定錯誤。請閱讀挑戰資源參考文件,以取得有關偵錯失敗挑戰的更多資訊。

一旦完成挑戰,它們相應的挑戰資源將被刪除,並且「訂單」將被更新以反映訂單的新狀態

$ kubectl describe order quickstart-example-tls-889745041
...
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Created 90s cert-manager Created Challenge resource "quickstart-example-tls-889745041-0" for domain "www.example.com"
Normal OrderValid 16s cert-manager Order completed successfully

最後,「憑證」資源將被更新以反映簽發程序的狀態。如果一切順利,您應該能夠「描述」憑證,並看到如下所示的內容

$ kubectl describe certificate quickstart-example-tls
Status:
Conditions:
Last Transition Time: 2019-01-09T13:57:52Z
Message: Certificate is up to date and has not expired
Reason: Ready
Status: True
Type: Ready
Not After: 2019-04-09T12:57:50Z
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Generated 11m cert-manager Generated new private key
Normal OrderCreated 11m cert-manager Created Order resource "quickstart-example-tls-889745041"
Normal OrderComplete 10m cert-manager Order "quickstart-example-tls-889745041" completed successfully