設定祕密存放區 CSI 驅動程式以使用 TLS 啟用 NGINX 輸入控制器
本文將逐步引導您使用 Azure Kubernetes Service (AKS) 叢集和 Azure Key Vault (AKV) 執行個體來保護 NGINX 輸入控制器的流程。 如需詳細資訊,請參閱 Kubernetes 中的 TLS。
您可以使用下列其中一種方法,將輸入 TLS 憑證匯入叢集:
- 應用程式:應用程式部署資訊清單會宣告並掛接提供者磁碟區。 只有當您部署應用程式時,叢集中才會提供憑證。 當您移除應用程式時,也會移除祕密。 此案例適用於負責應用程式安全性基礎結構和其與叢集整合的開發小組。
- 輸入控制器:輸入部署已修改,可宣告和掛接提供者磁碟區。 建立輸入 Pod 時,會匯入祕密。 應用程式的 Pod 無法存取 TLS 憑證。 此案例適用於一個小組 (例如 IT) 管理及建立基礎結構和網路元件 (包括 HTTPS TLS 憑證),而其他小組管理應用程式生命週期的案例。
必要條件
- 如果您沒有 Azure 訂用帳戶,請在開始前建立免費帳戶。
- 開始之前,請確定您的 Azure CLI 版本為 >=
2.30.0
,或安裝最新版本。 - 已設定祕密存放區 CSI 驅動程式的 AKS 叢集 (部分機器翻譯)。
- Azure Key Vault 執行個體 (部分機器翻譯)。
產生 TLS 憑證
使用下列命令產生 TLS 憑證。
export CERT_NAME=aks-ingress-cert openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -out aks-ingress-tls.crt \ -keyout aks-ingress-tls.key \ -subj "/CN=demo.azure.com/O=aks-ingress-tls"
將憑證匯入 AKV
執行下列命令,將憑證匯出至 PFX 檔案。
export AKV_NAME="[YOUR AKV NAME]" openssl pkcs12 -export -in aks-ingress-tls.crt -inkey aks-ingress-tls.key -out $CERT_NAME.pfx # skip Password prompt
使用
az keyvault certificate import
(部分機器翻譯) 命令匯入憑證。az keyvault certificate import --vault-name $AKV_NAME --name $CERT_NAME --file $CERT_NAME.pfx
部署 SecretProviderClass
使用下列命令匯出新的命名空間。
export NAMESPACE=ingress-basic
使用
kubectl create namespace
(部分機器翻譯) 命令建立命名空間。kubectl create namespace $NAMESPACE
選取方法以提供存取身分識別,並據以設定您的 SecretProviderClass YAML。
- 務必使用
objectType=secret
,這是從 AKV 取得私密金鑰和憑證的唯一方式。 - 在
secretObjects
區段中將kubernetes.io/tls
設定為type
。
參閱下列範例,了解您的 SecretProviderClass 可能的樣子:
apiVersion: secrets-store.csi.x-k8s.io/v1 kind: SecretProviderClass metadata: name: azure-tls spec: provider: azure secretObjects: # secretObjects defines the desired state of synced K8s secret objects - secretName: ingress-tls-csi type: kubernetes.io/tls data: - objectName: $CERT_NAME key: tls.key - objectName: $CERT_NAME key: tls.crt parameters: usePodIdentity: "false" useVMManagedIdentity: "true" userAssignedIdentityID: <client id> keyvaultName: $AKV_NAME # the name of the AKV instance objects: | array: - | objectName: $CERT_NAME objectType: secret tenantId: $TENANT_ID # the tenant ID of the AKV instance
- 務必使用
使用
kubectl apply
(部分機器翻譯) 命令,將 SecretProviderClass 套用至您的 Kubernetes 叢集。kubectl apply -f secretProviderClass.yaml -n $NAMESPACE
部屬輸入控制器
新增官方輸入圖表存放庫
使用下列
helm
(部分機器翻譯) 命令,新增官方輸入圖表存放庫。helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx helm repo update
設定和部署 NGINX 輸入
視您的情節而定,您可以選擇將憑證繫結至應用程式或輸入控制器。 根據您的選擇遵循以下指示:
將憑證繫結至應用程式
使用
helm install
(部分機器翻譯) 命令,將憑證繫結至應用程式。 應用程式的部署會參考祕密存放區 CSI 驅動程式的 Azure Key Vault 提供者。helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux
將憑證繫結至輸入控制器
使用
helm install
(部分機器翻譯) 命令,將憑證繫結至輸入控制器。 輸入控制器的部署會參考祕密存放區 CSI 驅動程式的 Azure Key Vault 提供者。注意
如果未使用 Microsoft Entra Pod 受控識別作為存取方法,請移除含有
--set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME
的程式碼行。此外,需要將 SecretProviderClass 繫結至 Pod,祕密存放區 CSI 驅動程式才能掛接它,並產生 Kubernetes 祕密。 請參閱使用 Kubernetes 祕密同步掛接的內容 (部分機器翻譯)。
helm install ingress-nginx/ingress-nginx --generate-name \ --namespace $NAMESPACE \ --set controller.replicaCount=2 \ --set controller.nodeSelector."kubernetes\.io/os"=linux \ --set defaultBackend.nodeSelector."kubernetes\.io/os"=linux \ --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-health-probe-request-path"=/healthz \ --set controller.podLabels.aadpodidbinding=$AAD_POD_IDENTITY_NAME \ -f - <<EOF controller: extraVolumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" extraVolumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true EOF
使用
kubectl get secret
命令,確認已建立 Kubernetes 祕密。kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
部署應用程式
同樣地,指示會根據您的案例而有些微變更。 請遵循與您所選取案例相對應的指示進行操作。
使用應用程式參考部署應用程式
建立名為
aks-helloworld-one.yaml
且具有下列內容的檔案。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
建立名為
aks-helloworld-two.yaml
且含有下列內容的檔案。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "azure-tls" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
使用
kubectl apply
命令,將 YAML 檔案套用至您的叢集。kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
使用
kubectl get secret
命令,確認已建立 Kubernetes 祕密。kubectl get secret -n $NAMESPACE NAME TYPE DATA AGE ingress-tls-csi kubernetes.io/tls 2 1m34s
使用輸入控制器參考部署應用程式
建立名為
aks-helloworld-one.yaml
且具有下列內容的檔案。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-one spec: replicas: 1 selector: matchLabels: app: aks-helloworld-one template: metadata: labels: app: aks-helloworld-one spec: containers: - name: aks-helloworld-one image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "Welcome to Azure Kubernetes Service (AKS)" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-one spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-one
建立名為
aks-helloworld-two.yaml
且含有下列內容的檔案。apiVersion: apps/v1 kind: Deployment metadata: name: aks-helloworld-two spec: replicas: 1 selector: matchLabels: app: aks-helloworld-two template: metadata: labels: app: aks-helloworld-two spec: containers: - name: aks-helloworld-two image: mcr.microsoft.com/azuredocs/aks-helloworld:v1 ports: - containerPort: 80 env: - name: TITLE value: "AKS Ingress Demo" --- apiVersion: v1 kind: Service metadata: name: aks-helloworld-two spec: type: ClusterIP ports: - port: 80 selector: app: aks-helloworld-two
使用
kubectl apply
命令,將 YAML 檔案套用至您的叢集。kubectl apply -f aks-helloworld-one.yaml -n $NAMESPACE kubectl apply -f aks-helloworld-two.yaml -n $NAMESPACE
部署參考祕密的輸入資源
我們現在可以部署參考祕密的 Kubernetes 輸入資源。
建立名為
hello-world-ingress.yaml
且具有下列內容的檔案。apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: ingress-tls annotations: nginx.ingress.kubernetes.io/rewrite-target: /$2 spec: ingressClassName: nginx tls: - hosts: - demo.azure.com secretName: ingress-tls-csi rules: - host: demo.azure.com http: paths: - path: /hello-world-one(/|$)(.*) pathType: Prefix backend: service: name: aks-helloworld-one port: number: 80 - path: /hello-world-two(/|$)(.*) pathType: Prefix backend: service: name: aks-helloworld-two port: number: 80 - path: /(.*) pathType: Prefix backend: service: name: aks-helloworld-one port: number: 80
記下會參考稍早所建立之祕密的
tls
區段,並使用kubectl apply
命令將該檔案套用至您的叢集。kubectl apply -f hello-world-ingress.yaml -n $NAMESPACE
取得輸入控制器的外部 IP 位址
使用
kubectl get service
命令,取得輸入控制器的外部 IP 位址。kubectl get service --namespace $NAMESPACE --selector app.kubernetes.io/name=ingress-nginx NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE nginx-ingress-1588032400-controller LoadBalancer 10.0.255.157 EXTERNAL_IP 80:31293/TCP,443:31265/TCP 19m nginx-ingress-1588032400-default-backend ClusterIP 10.0.223.214 <none> 80/TCP 19m
測試使用 TLS 保護的輸入
使用下列
curl
命令,確認您的輸入已使用 TLS 正確設定。 確定您會使用上一個步驟中的外部 IP。curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com
由於先前並未提供位址的另一個路徑,因此,輸入控制器預設為 / 路由。 此時會傳回第一個示範應用程式,如下列簡要範例輸出所示:
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>Welcome to Azure Kubernetes Service (AKS)</title> [...]
curl
命令中的 -v 參數會輸出詳細資訊,包括所收到的 TLS 憑證。 當您的 curl 輸出進行到一半時,您可以驗證是否已使用自有的 TLS 憑證。 即使我們使用自我簽署的憑證,-k 參數會繼續載入頁面。 下列範例顯示已使用 issuer: CN=demo.azure.com; O=aks-ingress-tls 憑證:[...] * Server certificate: * subject: CN=demo.azure.com; O=aks-ingress-tls * start date: Oct 22 22:13:54 2021 GMT * expire date: Oct 22 22:13:54 2022 GMT * issuer: CN=demo.azure.com; O=aks-ingress-tls * SSL certificate verify result: self signed certificate (18), continuing anyway. [...]
將 /hello-world-two 路徑新增至位址 (例如
https://demo.azure.com/hello-world-two
),並確認已正確設定第二個示範應用程式。curl -v -k --resolve demo.azure.com:443:EXTERNAL_IP https://demo.azure.com/hello-world-two
此時會傳回含有自訂標題的第二個示範應用程式,如下列簡要範例輸出所示:
[...] <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <link rel="stylesheet" type="text/css" href="/static/default.css"> <title>AKS Ingress Demo</title> [...]