你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn

将 TLS 用于 Azure Kubernetes 服务 (AKS) 上的入口控制器

传输层安全性 (TLS) 是一种使用证书在通信中提供安全性(例如加密、身份验证和完整性)的协议。 将 TLS 用于 AKS 上的入口控制器可以保护应用程序之间的通信,同时获得入口控制器的优势。

你可以创建自己的证书并将其与机密存储 CSI 驱动程序相集成。 或者,也可以使用 cert-manager 来自动生成和配置 Let's Encrypt 证书。 最后,在 AKS 群集中运行两个应用程序(可通过单个 IP 地址访问其中的每个应用程序)。

注意

Kubernetes 有两个基于 Nginx 的开源入口控制器:一个控制器由 Kubernetes 社区 (kubernetes/ingress-nginx) 维护,另一个由 NGINX, Inc. (nginxinc/kubernetes-ingress) 维护。 本文将使用 Kubernetes 社区入口控制器。

在开始之前

本文还假设已设置入口控制器和应用程序。 如果需要入口控制器或示例应用程序,请参阅创建入口控制器

本文使用 Helm 3支持的 Kubernetes 版本上安装 NGINX 入口控制器。 确保使用最新版本的 Helm,并且有权访问 ingress-nginxjetstack Helm 存储库。 本文中概述的步骤可能与 Helm chart、NGINX 入口控制器或 Kubernetes 的先前版本不兼容。

有关配置和使用 Helm 的详细信息,请参阅在 Azure Kubernetes 服务 (AKS) 中使用 Helm 安装应用程序。 有关升级说明,请参阅 Helm 安装文档

此外,本文假设你有一个包含集成 Azure 容器注册表 (ACR) 的现有 AKS 群集。 有关创建一个包含集成 ACR 的 AKS 群集的详细信息,请参阅使用 Azure 容器注册表从 Azure Kubernetes 服务进行身份验证

本文还要求运行 Azure CLI 2.0.64 或更高版本。 运行 az --version 即可查找版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

通过机密存储 CSI 驱动程序将 TLS 与你自己的证书配合使用

若要通过机密存储 CSI 驱动程序将 TLS 与你自己的证书配合使用,需要一个配置了机密存储 CSI 驱动程序的 AKS 群集,以及一个 Azure 密钥保管库实例。 有关详细信息,请参阅设置机密存储 CSI 驱动程序以启用使用 TLS 的 NGINX 入口控制器

将 TLS 与 Let's Encrypt 证书配合使用

若要将 TLS 与 Let's Encrypt 证书配合使用,需要部署 cert-manager 用于自动生成和配置 Let's Encrypt 证书。

将 Helm 图表使用的 cert-manager 映像导入 ACR

使用 az acr import 将这些映像导入 ACR。

REGISTRY_NAME=<REGISTRY_NAME>
CERT_MANAGER_REGISTRY=quay.io
CERT_MANAGER_TAG=v1.8.0
CERT_MANAGER_IMAGE_CONTROLLER=jetstack/cert-manager-controller
CERT_MANAGER_IMAGE_WEBHOOK=jetstack/cert-manager-webhook
CERT_MANAGER_IMAGE_CAINJECTOR=jetstack/cert-manager-cainjector

az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CONTROLLER:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_WEBHOOK:$CERT_MANAGER_TAG
az acr import --name $REGISTRY_NAME --source $CERT_MANAGER_REGISTRY/$CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG --image $CERT_MANAGER_IMAGE_CAINJECTOR:$CERT_MANAGER_TAG

注意

除了将容器映像导入 ACR 之外,还可以将 Helm 图表导入 ACR。 有关详细信息,请参阅将 Helm 图表推送和拉取到 Azure 容器注册表

入口控制器配置选项

默认情况下,NGINX 入口控制器通过新的公共 IP 地址分配创建。 此公共 IP 地址仅对入口控制器的生命周期而言是静态的,如果删除并重新创建控制器,它将会丢失。

可以选择以下方法之一:

  • 使用动态公共 IP 地址。
  • 使用静态公共 IP 地址。

使用静态公共 IP 地址

常见的配置要求是为 NGINX 入口控制器提供现有的静态公共 IP 地址。 如果删除入口控制器,静态公共 IP 地址仍存在。

以下命令创建一个 IP 地址,如果你删除了 AKS 群集,该 IP 地址会被删除。

首先使用 az aks show 命令获取 AKS 群集的资源组名称:

az aks show --resource-group myResourceGroup --name myAKSCluster --query nodeResourceGroup -o tsv

接下来,使用 az network public-ip create 命令通过静态分配方法创建一个公共 IP 地址。 以下示例在前面的步骤中获取的 AKS 群集资源组中创建名为 myAKSPublicIP 的公共 IP 地址:

az network public-ip create --resource-group MC_myResourceGroup_myAKSCluster_eastus --name myAKSPublicIP --sku Standard --allocation-method static --query publicIp.ipAddress -o tsv

或者,你可以在不同的资源组中创建一个 IP 地址,该资源组可以与你的 AKS 群集分开管理。 如果在其他资源组中创建 IP 地址,请确保满足以下条件:

  • AKS 群集使用的群集标识已将权限委托给资源组,例如“网络参与者”。
  • 添加 --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-load-balancer-resource-group"="<RESOURCE_GROUP>" 参数。 将 <RESOURCE_GROUP> 替换为 IP 地址驻留的资源组的名称。

更新入口控制器时,必须将参数传递给 Helm 版本,以便入口控制器知道要分配给入口控制器服务的负载均衡器的静态 IP 地址。 为使 HTTPS 证书正常工作,使用 DNS 名称标签来配置用于入口控制器 IP 地址的 FQDN。

  1. 添加 --set controller.service.loadBalancerIP="<EXTERNAL_IP>" 参数。 指定在前面的步骤中创建的你自己的公共 IP 地址。
  2. 添加 --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"="<DNS_LABEL>" 参数。 可以在首次部署入口控制器时设置 DNS 标签,也可以稍后进行配置。
DNS_LABEL="demo-aks-ingress"
NAMESPACE="ingress-basic"
STATIC_IP=<STATIC_IP>

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL \
  --set controller.service.loadBalancerIP=$STATIC_IP

有关详细信息,请参阅将静态公共 IP 地址和 DNS 标签用于 AKS 负载均衡器

使用动态 IP 地址

创建入口控制器时,系统将为入口控制器创建一个 Azure 公共 IP 地址。 此公共 IP 地址在入口控制器的寿命期内是静态的。 如果你删除入口控制器,则公共 IP 地址分配会丢失。 如果你随后创建另一个入口控制器,则会分配新的公共 IP 地址。

若要获取公共 IP 地址,请使用 kubectl get service 命令。

kubectl --namespace ingress-basic get services -o wide -w nginx-ingress-ingress-nginx-controller

示例输出显示了有关入口控制器的详细信息:

NAME                                     TYPE           CLUSTER-IP    EXTERNAL-IP     PORT(S)                      AGE   SELECTOR
nginx-ingress-ingress-nginx-controller   LoadBalancer   10.0.74.133   EXTERNAL_IP     80:32486/TCP,443:30953/TCP   44s   app.kubernetes.io/component=controller,app.kubernetes.io/instance=nginx-ingress,app.kubernetes.io/name=ingress-nginx

如果使用自定义域,则需要将 A 记录添加到 DNS 区域。 否则,需要使用完全限定的域名 (FQDN) 配置公共 IP 地址。

将 A 记录添加到 DNS 区域

使用 az network dns record-set a add-recordA 记录添加到使用 NGINX 服务的外部 IP 地址的 DNS 区域。

az network dns record-set a add-record \
    --resource-group myResourceGroup \
    --zone-name MY_CUSTOM_DOMAIN \
    --record-set-name "*" \
    --ipv4-address MY_EXTERNAL_IP

为入口控制器配置 FQDN

(可选)可以为入口控制器 IP 地址而不是自定义域配置 FQDN。 FQDN 的格式会是 <CUSTOM LABEL>.<AZURE REGION NAME>.cloudapp.azure.com

方法 1:使用 Azure CLI 设置 DNS 标签

此示例适用于 Bash shell。

# Public IP address of your ingress controller
IP="MY_EXTERNAL_IP"

# Name to associate with public IP address
DNSNAME="demo-aks-ingress"

# Get the resource-id of the public ip
PUBLICIPID=$(az network public-ip list --query "[?ipAddress!=null]|[?contains(ipAddress, '$IP')].[id]" --output tsv)

# Update public ip address with DNS name
az network public-ip update --ids $PUBLICIPID --dns-name $DNSNAME

# Display the FQDN
az network public-ip show --ids $PUBLICIPID --query "[dnsSettings.fqdn]" --output tsv

方法 2:使用 helm 图表设置来设置 DNS 标签

可以使用 --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name" 参数将注释设置传递给 helm 图表配置。 可以在首次部署入口控制器时设置此参数,也可以稍后进行配置。 以下示例演示如何在部署控制器后更新此设置。

DNS_LABEL="demo-aks-ingress"
NAMESPACE="ingress-basic"

helm upgrade nginx-ingress ingress-nginx/ingress-nginx \
  --namespace $NAMESPACE \
  --set controller.service.annotations."service\.beta\.kubernetes\.io/azure-dns-label-name"=$DNS_LABEL

安装证书管理器

NGINX 入口控制器支持 TLS 终止。 可通过多种方法为 HTTPS 检索和配置证书。 本文演示如何使用证书管理器,该管理器提供自动 Lets Encrypt 证书生成和管理功能。

若要安装证书管理器控制器,请执行以下命令:

# Set variable for ACR location to use for pulling images
ACR_URL=<REGISTRY_URL>

# Label the ingress-basic namespace to disable resource validation
kubectl label namespace ingress-basic cert-manager.io/disable-validation=true

# Add the Jetstack Helm repository
helm repo add jetstack https://charts.jetstack.io

# Update your local Helm chart repository cache
helm repo update

# Install the cert-manager Helm chart
helm install cert-manager jetstack/cert-manager \
  --namespace ingress-basic \
  --version $CERT_MANAGER_TAG \
  --set installCRDs=true \
  --set nodeSelector."kubernetes\.io/os"=linux \
  --set image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CONTROLLER \
  --set image.tag=$CERT_MANAGER_TAG \
  --set webhook.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_WEBHOOK \
  --set webhook.image.tag=$CERT_MANAGER_TAG \
  --set cainjector.image.repository=$ACR_URL/$CERT_MANAGER_IMAGE_CAINJECTOR \
  --set cainjector.image.tag=$CERT_MANAGER_TAG

若要详细了解证书管理器配置,请参阅证书管理器项目

创建 CA 群集证书颁发者

证书管理器需要 IssuerClusterIssuer 资源,才能颁发证书。 这两种 Kubernetes 资源的功能完全相同,区别在于 Issuer 适用于单一命名空间,而 ClusterIssuer 适用于所有命名空间。 有关详细信息,请参阅证书管理器颁发者文档。

使用以下示例清单创建群集证书颁发者,例如 cluster-issuer.yaml。 将电子邮件地址更新为组织提供的有效地址:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: MY_EMAIL_ADDRESS
    privateKeySecretRef:
      name: letsencrypt
    solvers:
    - http01:
        ingress:
          class: nginx
          podTemplate:
            spec:
              nodeSelector:
                "kubernetes.io/os": linux

若要创建证书颁发者,请使用 kubectl apply 命令。

kubectl apply -f cluster-issuer.yaml

更新入口路由

需要更新入口路由,以处理发送到 FQDN 或自定义域的流量。

在以下示例中,到地址 hello-world-ingress.MY_CUSTOM_DOMAIN 的流量会路由到 aks-helloworld-one 服务 。 到地址 hello-world-ingress.MY_CUSTOM_DOMAIN/hello-world-two 的流量会路由到 aks-helloworld-two 服务。 到 hello-world-ingress.MY_CUSTOM_DOMAIN/static 的流量会路由到静态资产的名为 aks-helloworld-one 的服务 。

注意

如果为入口控制器 IP 地址(而不是自定义域)配置了 FQDN,请使用 FQDN 而不是 hello-world-ingress.MY_CUSTOM_DOMAIN。 例如,如果 FQDN 为“demo-aks-ingress.eastus.cloudapp.azure.com”,则将“hello-world-ingress.MY_CUSTOM_DOMAIN”替换为 hello-world-ingress.yaml 中的“demo-aks-ingress.eastus.cloudapp.azure.com”。

使用以下示例 YAML 创建或更新 hello-world-ingress.yaml 文件。 将 spec.tls.hostsspec.rules.host 更新为在前面步骤中创建的 DNS 名称。

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /$2
    nginx.ingress.kubernetes.io/use-regex: "true"
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    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
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: hello-world-ingress-static
  annotations:
    nginx.ingress.kubernetes.io/ssl-redirect: "false"
    nginx.ingress.kubernetes.io/rewrite-target: /static/$2
spec:
  ingressClassName: nginx
  tls:
  - hosts:
    - hello-world-ingress.MY_CUSTOM_DOMAIN
    secretName: tls-secret
  rules:
  - host: hello-world-ingress.MY_CUSTOM_DOMAIN
    http:
      paths:
      - path: /static(/|$)(.*)
        pathType: Prefix
        backend:
          service:
            name: aks-helloworld-one
            port: 
              number: 80

使用 kubectl apply 命令更新入口资源。

kubectl apply -f hello-world-ingress.yaml --namespace ingress-basic

验证是否已创建证书对象

接下来,必须创建证书资源。 证书资源定义了必需的 X.509 证书。 有关详细信息,请参阅证书管理器证书。 证书管理器已使用 ingress-shim(自 v0.2.2 以来随证书管理器自动部署)为你自动创建了证书对象。 有关详细信息,请参阅 ingress-shim 文档

若要验证证书是否已成功创建,请使用 kubectl get certificate --namespace ingress-basic 命令,并验证 READY 是否为 True,这可能需要数分钟。

kubectl get certificate --namespace ingress-basic

以下示例输出了显示了证书的状态:

NAME         READY   SECRET       AGE
tls-secret   True    tls-secret   11m

测试入口配置

打开 Web 浏览器并访问 Kubernetes 入口控制器的 hello-world-ingress.MY_CUSTOM_DOMAIN 或 FQDN。 请注意,系统会将你重定向,让你使用 HTTPS。证书是受信任的,演示应用程序显示在 Web 浏览器中。 添加 /hello-world-two 路径,并注意显示了自定义标题的第二个演示应用程序。

清理资源

本文使用 Helm 来安装入口组件、证书和示例应用。 在部署 Helm 图表时,会创建若干 Kubernetes 资源。 这些资源包括 pod、部署和服务。 若要清理这些资源,可以删除整个示例命名空间,也可以删除单个资源。

删除示例命名空间以及所有资源

若要删除整个示例命名空间,请使用 kubectl delete 命令并指定命名空间名称。 将会删除命名空间中的所有资源。

kubectl delete namespace ingress-basic

单独删除资源

也可采用更细致的方法来删除单个已创建的资源。 首先,删除群集颁发者资源:

kubectl delete -f cluster-issuer.yaml --namespace ingress-basic

使用 helm list 命令列出 Helm 版本。 查找名为“nginx”和“cert-manager”的图表,如以下示例输出中所示 :

$ helm list --namespace ingress-basic

NAME                    NAMESPACE       REVISION        UPDATED                                 STATUS          CHART                   APP VERSION
cert-manager            ingress-basic   1               2020-01-15 10:23:36.515514 -0600 CST    deployed        cert-manager-v0.13.0    v0.13.0    
nginx                   ingress-basic   1               2020-01-15 10:09:45.982693 -0600 CST    deployed        nginx-ingress-1.29.1    0.27.0  

使用 helm uninstall 命令卸载这些版本。 以下示例将卸载 NGINX 入口和证书管理器部署。

$ helm uninstall cert-manager nginx --namespace ingress-basic

release "cert-manager" uninstalled
release "nginx" uninstalled

接下来,删除两个示例应用程序:

kubectl delete -f aks-helloworld-one.yaml --namespace ingress-basic
kubectl delete -f aks-helloworld-two.yaml --namespace ingress-basic

删除将流量定向到示例应用的入口路由:

kubectl delete -f hello-world-ingress.yaml --namespace ingress-basic

最后,可以删除自身命名空间。 使用 kubectl delete 命令并指定命名空间名称。

kubectl delete namespace ingress-basic

后续步骤

本文包含 AKS 的一些外部组件。 若要详细了解这些组件,请参阅以下项目页面:

也可执行以下操作: