保護 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 updateHang 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 repositoryUpdate Complete. ⎈ Happy Helming!⎈
使用 helm
安裝 NGINX Ingress 控制器
$ helm install quickstart ingress-nginx/ingress-nginxNAME: quickstart... lots of output ...
雲端供應商可能需要一到兩分鐘的時間來提供並連結公用 IP 位址。完成後,您可以使用 kubectl
命令來查看外部 IP 位址
$ kubectl get svcNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGEkubernetes ClusterIP 10.0.0.1 <none> 443/TCP 13mquickstart-ingress-nginx-controller LoadBalancer 10.0.114.241 <pending> 80:31635/TCP,443:30062/TCP 8m16squickstart-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/v1kind: Deploymentmetadata:name: kuardspec:selector:matchLabels:app: kuardreplicas: 1template:metadata:labels:app: kuardspec:containers:- image: gcr.io/kuar-demo/kuard-amd64:1imagePullPolicy: Alwaysname: kuardports:- containerPort: 8080
apiVersion: v1kind: Servicemetadata:name: kuardspec:ports:- port: 80targetPort: 8080protocol: TCPselector: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" createdkubectl 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/v1kind: Ingressmetadata:name: kuardannotations: {}#cert-manager.io/issuer: "letsencrypt-staging"spec:ingressClassName: nginxtls:- hosts:- example.example.comsecretName: quickstart-example-tlsrules:- host: example.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport: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 AGEkuard * 80, 443 17s
根據您的服務供應商,Ingress 可能需要幾分鐘才能完全建立。當它建立並連結到位時,Ingress 也會顯示位址
NAME HOSTS ADDRESS PORTS AGEkuard * 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
取代 Issuers
;ClusterIssuer
資源適用於您叢集中的所有 Ingress 資源。如果使用 ClusterIssuer
,請記得將 Ingress 註解 cert-manager.io/issuer
更新為 cert-manager.io/cluster-issuer
。
如果您發現簽發者有問題,請遵循簽發 ACME 憑證的疑難排解指南。
有關 Issuers
和 ClusterIssuers
之間的差異的更多資訊(包括您可能選擇使用每個選項的時間)可以在簽發者概念中找到。
憑證(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/v1kind: Issuermetadata:name: letsencrypt-stagingspec:acme:# The ACME server URLserver: https://acme-staging-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: user@example.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-staging# Enable the HTTP-01 challenge providersolvers:- 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/v1kind: Issuermetadata:name: letsencrypt-prodspec:acme:# The ACME server URLserver: https://acme-v02.api.letsencrypt.org/directory# Email address used for ACME registrationemail: user@example.com# Name of a secret used to store the ACME account private keyprivateKeySecretRef:name: letsencrypt-prod# Enable the HTTP-01 challenge providersolvers:- 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-stagingName: letsencrypt-stagingNamespace: defaultLabels: <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/v1Kind: IssuerMetadata:Cluster Name:Creation Timestamp: 2018-11-17T18:03:54ZGeneration: 0Resource Version: 9092Self Link: /apis/cert-manager.io/v1/namespaces/default/issuers/letsencrypt-stagingUID: 25b7ae77-ea93-11e8-82f8-42010a8a00b5Spec:Acme:Email: email@example.comPrivate Key Secret Ref:Key:Name: letsencrypt-stagingServer: https://acme-staging-v02.api.letsencrypt.org/directorySolvers:Http 01:Ingress:Class: nginxStatus:Acme:Uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/7374163Conditions:Last Transition Time: 2018-11-17T18:04:00ZMessage: The ACME account was registered with the ACME serverReason: ACMEAccountRegisteredStatus: TrueType: ReadyEvents: <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/v1kind: Ingressmetadata:name: kuardannotations:cert-manager.io/issuer: "letsencrypt-staging"spec:ingressClassName: nginxtls:- hosts:- example.example.comsecretName: quickstart-example-tlsrules:- host: example.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport: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 certificateNAME READY SECRET AGEquickstart-example-tls True quickstart-example-tls 16m
cert-manager 會在憑證物件中反映每個請求的處理狀態。您可以使用 kubectl describe
命令檢視此資訊
$ kubectl describe certificate quickstart-example-tlsName: quickstart-example-tlsNamespace: defaultLabels: <none>Annotations: <none>API Version: cert-manager.io/v1Kind: CertificateMetadata:Cluster Name:Creation Timestamp: 2018-11-17T17:58:37ZGeneration: 0Owner References:API Version: networking.k8s.io/v1Block Owner Deletion: trueController: trueKind: IngressName: kuardUID: a3e9f935-ea87-11e8-82f8-42010a8a00b5Resource Version: 9295Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tlsUID: 68d43400-ea92-11e8-82f8-42010a8a00b5Spec:Dns Names:www.example.comIssuer Ref:Kind: IssuerName: letsencrypt-stagingSecret Name: quickstart-example-tlsStatus:Acme:Order:URL: https://acme-staging-v02.api.letsencrypt.org/acme/order/7374163/13665676Conditions:Last Transition Time: 2018-11-17T18:05:57ZMessage: Certificate issued successfullyReason: CertIssuedStatus: TrueType: ReadyEvents: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" validationNormal IssueCert 8m cert-manager Issuing certificate...Normal CertObtained 7m cert-manager Obtained certificate from ACME serverNormal CertIssued 7m cert-manager Certificate issued Successfully
與此資源相關聯並列在 describe
結果底部的事件會顯示請求的狀態。在上面的範例中,憑證在幾分鐘內被驗證並簽發。
完成後,cert-manager 將根據 ingress 資源中使用的密鑰建立包含憑證詳細資訊的密鑰。您也可以使用 describe 命令來查看一些詳細資訊
$ kubectl describe secret quickstart-example-tlsName: quickstart-example-tlsNamespace: defaultLabels: cert-manager.io/certificate-name=quickstart-example-tlsAnnotations: cert-manager.io/alt-names=www.example.comcert-manager.io/common-name=www.example.comcert-manager.io/issuer-kind=Issuercert-manager.io/issuer-name=letsencrypt-stagingType: kubernetes.io/tlsData====tls.crt: 3566 bytestls.key: 1675 bytes
現在我們確信一切都已正確設定,您可以更新 ingress 中的註解以指定 production 簽發者
apiVersion: networking.k8s.io/v1kind: Ingressmetadata:name: kuardannotations:cert-manager.io/issuer: "letsencrypt-prod"spec:ingressClassName: nginxtls:- hosts:- example.example.comsecretName: quickstart-example-tlsrules:- host: example.example.comhttp:paths:- path: /pathType: Prefixbackend:service:name: kuardport:number: 80
$ kubectl create --edit -f https://raw.githubusercontent.com/cert-manager/website/master/content/docs/tutorials/acme/example/ingress-tls-final.yamlingress.networking.k8s.io/kuard configured
您還需要刪除現有的密鑰,cert-manager 正在監視該密鑰,這將導致它使用更新後的簽發者重新處理請求。
$ kubectl delete secret quickstart-example-tlssecret "quickstart-example-tls" deleted
這將啟動取得新憑證的程序,並且您可以使用 describe 來查看狀態。一旦 production 憑證已更新,您應該會在您的網域上看到範例 KUARD 正在運行,並且具有簽署的 TLS 憑證。
$ kubectl describe certificate quickstart-example-tlsName: quickstart-example-tlsNamespace: defaultLabels: <none>Annotations: <none>API Version: cert-manager.io/v1Kind: CertificateMetadata:Cluster Name:Creation Timestamp: 2018-11-17T18:36:48ZGeneration: 0Owner References:API Version: networking.k8s.io/v1Block Owner Deletion: trueController: trueKind: IngressName: kuardUID: a3e9f935-ea87-11e8-82f8-42010a8a00b5Resource Version: 283686Self Link: /apis/cert-manager.io/v1/namespaces/default/certificates/quickstart-example-tlsUID: bdd93b32-ea97-11e8-82f8-42010a8a00b5Spec:Dns Names:www.example.comIssuer Ref:Kind: IssuerName: letsencrypt-prodSecret Name: quickstart-example-tlsStatus:Conditions:Last Transition Time: 2019-01-09T13:52:05ZMessage: Certificate does not existReason: NotFoundStatus: FalseType: ReadyEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Generated 18s cert-manager Generated new private keyNormal 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: trueProcessing: trueReason: Waiting for http-01 challenge propagationState: pendingEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Started 15s cert-manager Challenge scheduled for processingNormal 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: falseProcessing: falseReason: Successfully authorized domainState: validEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Started 71s cert-manager Challenge scheduled for processingNormal Presented 70s cert-manager Presented challenge using http-01 challenge mechanismNormal 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-tlsStatus:Conditions:Last Transition Time: 2019-01-09T13:57:52ZMessage: Certificate is up to date and has not expiredReason: ReadyStatus: TrueType: ReadyNot After: 2019-04-09T12:57:50ZEvents:Type Reason Age From Message---- ------ ---- ---- -------Normal Generated 11m cert-manager Generated new private keyNormal OrderCreated 11m cert-manager Created Order resource "quickstart-example-tls-889745041"Normal OrderComplete 10m cert-manager Order "quickstart-example-tls-889745041" completed successfully