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

Cert-manager 和 Let's Encrypt 与适用于容器的应用程序网关 - 网关 API

本指南介绍如何使用 cert-manager 自动为适用于容器的应用程序网关部署的一个或多个前端颁发和续订 SSL/TLS 证书。 我们使用网关 API 配置所需的资源。

在本示例中,我们让 cert-manager 配置从 Let's Encrypt 颁发的证书,以演示一个端到端的部署,其中适用于容器的应用程序网关提供 TLS 卸载功能。

该示意图展示了 cert-manager 从 Let's Encrypt 检索证书并将其存储到 Kubernetes 的机密存储中,以便通过适用于容器的应用程序网关实现 TLS。

对于 Let's Encrypt 颁发的证书,机构需要进行质询以验证域所有权。 进行此验证时,需要让 cert-manager 创建一个 pod 和 HTTPRoute 资源,以在证书颁发期间公开一个终结点,证明你对域名的所有权。

有关 cert-manager 和 Let's Encrypt 与 AKS 的更多详细信息,请参阅此处

先决条件

  1. 如果遵循 BYO 部署策略,请确保设置适用于容器的应用程序网关资源和 ALB 控制器

  2. 如果遵循 ALB 托管部署策略,请确保预配 ALB 控制器,并通过 ApplicationLoadBalancer 自定义资源预配适用于容器的应用程序网关资源。

  3. 部署示例 HTTP 应用程序。在群集上应用以下deployment.yaml 文件来创建示例 Web 应用程序,以演示标头重写。

    kubectl apply -f https://raw.githubusercontent.com/MicrosoftDocs/azure-docs/refs/heads/main/articles/application-gateway/for-containers/examples/traffic-split-scenario/deployment.yaml
    

    此命令在群集上创建以下内容:

    • 名为test-infra的命名空间
    • test-infra命名空间中名为backend-v1backend-v2的两个服务
    • test-infra 命名空间中名为 backend-v1backend-v2 的两个部署

创建网关资源

创建一个新的 Gateway 资源,用于在质询过程中侦听来自 Let's Encrypt 的 HTTP 请求。

创建网关:

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway-01
  namespace: test-infra
  annotations:
    alb.networking.azure.io/alb-namespace: alb-test-infra
    alb.networking.azure.io/alb-name: alb-test
    cert-manager.io/issuer: letsencrypt-cert
spec:
  gatewayClassName: azure-alb-external
  listeners:
  - name: http-listener
    protocol: HTTP
    port: 80
    allowedRoutes:
        namespaces:
          from: Same
EOF

注意

当 ALB 控制器在 ARM 中创建适用于容器的应用程序网关时,它将对前端资源使用以下命名约定:fe-<8 个随机生成的字符>

如果要更改在 Azure 中创建的前端的名称,请考虑按照创建自己的部署策略中的说明进行操作。

创建网关资源后,请确保状态有效,侦听器已编程,并地址已分配给网关。

kubectl get gateway gateway-01 -n test-infra -o yaml

成功创建了网关时的示例输出。

status:
  addresses:
  - type: IPAddress
    value: xxxx.yyyy.alb.azure.com
  conditions:
  - lastTransitionTime: "2023-06-19T21:04:55Z"
    message: Valid Gateway
    observedGeneration: 1
    reason: Accepted
    status: "True"
    type: Accepted
  - lastTransitionTime: "2023-06-19T21:04:55Z"
    message: Application Gateway For Containers resource has been successfully updated.
    observedGeneration: 1
    reason: Programmed
    status: "True"
    type: Programmed
  listeners:
  - attachedRoutes: 0
    conditions:
    - lastTransitionTime: "2023-06-19T21:04:55Z"
      message: ""
      observedGeneration: 1
      reason: ResolvedRefs
      status: "True"
      type: ResolvedRefs
    - lastTransitionTime: "2023-06-19T21:04:55Z"
      message: Listener is accepted
      observedGeneration: 1
      reason: Accepted
      status: "True"
      type: Accepted
    - lastTransitionTime: "2023-06-19T21:04:55Z"
      message: Application Gateway For Containers resource has been successfully updated.
      observedGeneration: 1
      reason: Programmed
      status: "True"
      type: Programmed
    name: https-listener
    supportedKinds:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute

安装 cert-manager

使用 Helm 安装 cert-manager:

helm repo add jetstack https://charts.jetstack.io --force-update
helm install \
  cert-manager jetstack/cert-manager \
  --namespace cert-manager \
  --create-namespace \
  --version v1.17.1 \
  --set config.enableGatewayAPI=true \
  --set crds.enabled=true

Helm 安装会在名为 cert-manager 的新命名空间中创建三个部署以及一些服务和 Pod。 它还会安装群集范围的支持资源,如 RBAC 角色和自定义资源定义。

创建 ClusterIssuer

创建 ClusterIssuer 资源,以定义 cert-manager 与 Let's Encrypt 的通信方式。 对于此示例,需要使用 HTTP 质询。 在质询期间,cert-manager 会创建一个 HTTPRoute 资源和相应的 Pod,并提供一个验证终结点来证明域的所有权。

提示

Let's Encrypt 支持的其他质询记录在 letsencrypt.org - 验证方式

kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-prod
  namespace: test-infra
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory # production endpoint
    #server: https://acme-staging-v02.api.letsencrypt.org/directory # staging endpoint
    email: your-email@example.com
    privateKeySecretRef:
      name: letsencrypt-private-key
    solvers:
      - http01:
          gatewayHTTPRoute:
            parentRefs:
              - name: gateway-01
                namespace: test-infra
                kind: Gateway
EOF

验证创建的资源

kubectl get ClusterIssuer -A -o yaml

状态应显示 True 和类型 Ready

  status:
    acme:
      lastPrivateKeyHash: x+xxxxxxxxxxxxxxxxxxxxxxx+MY4PAEeotr9XH3V7I=
      lastRegisteredEmail: your-email@example.com
      uri: https://acme-staging-v02.api.letsencrypt.org/acme/acct/165888253
    conditions:
    - lastTransitionTime: "2024-10-04T21:22:40Z"
      message: The ACME account was registered with the ACME server
      observedGeneration: 1
      reason: ACMEAccountRegistered
      status: "True"
      type: Ready

创建证书

kubectl apply -f - <<EOF
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: letsencrypt-cert
  namespace: test-infra
spec:
  secretName: letsencrypt-secret # name published to secret store
  issuerRef:
    name: letsencrypt-prod # ClusterIssuer resource name
    kind: ClusterIssuer
  dnsNames:
    - contoso.com # ___domain name to be used
EOF

执行以下命令以验证证书的颁发情况。 如果已颁发证书,则 READY 列的值应 True

kubectl get certificate letsencrypt-cert -n test-infra

如果未颁发证书,可以执行以下命令来验证质询的状态。

注意

如果已成功颁发证书,将不再列出质询。

kubectl get challenges -n test-infra -o yaml

在网关资源上启用 HTTPS

修改网关以添加第二个侦听器,终止具有颁发的 Let's Encrypt 证书的 HTTPS 请求。

创建网关:

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gateway-01
  namespace: test-infra
  annotations:
    alb.networking.azure.io/alb-namespace: alb-test-infra
    alb.networking.azure.io/alb-name: alb-test
    cert-manager.io/issuer: letsencrypt-cert
spec:
  gatewayClassName: azure-alb-external
  listeners:
  - name: http-listener
    protocol: HTTP
    port: 80
    allowedRoutes:
        namespaces:
          from: Same
  - name: https-listener
    port: 443
    protocol: HTTPS
    tls:
      certificateRefs:
      - name: letsencrypt-secret
    allowedRoutes:
      namespaces:
        from: Same
EOF

注意

当 ALB 控制器在 ARM 中创建适用于容器的应用程序网关时,它将对前端资源使用以下命名约定:fe-<8 个随机生成的字符>

如果要更改在 Azure 中创建的前端的名称,请考虑按照创建自己的部署策略中的说明进行操作。

创建侦听主机名的 HTTPRoute

创建 HTTPRoute 来处理 https-listener 侦听器收到的请求。

重要说明

确保将 contoso.com 替换为希望向其颁发证书的域名。

kubectl apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: https-example
  namespace: test-infra
spec:
  parentRefs:
  - name: gateway-01
  hostnames:
  - "contoso.com"
  rules:
  - backendRefs:
    - name: backend-v1
      port: 8080
EOF

创建 HTTPRoute 资源后,请确保路由被接受,并且适用于容器的应用程序网关已编程。

kubectl get httproute cert-manager-route -n test-infra -o yaml

验证是否已成功更新适用于容器的应用程序网关资源的状态。

status:
  parents:
  - conditions:
    - lastTransitionTime: "2023-06-19T22:18:23Z"
      message: ""
      observedGeneration: 1
      reason: ResolvedRefs
      status: "True"
      type: ResolvedRefs
    - lastTransitionTime: "2023-06-19T22:18:23Z"
      message: Route is Accepted
      observedGeneration: 1
      reason: Accepted
      status: "True"
      type: Accepted
    - lastTransitionTime: "2023-06-19T22:18:23Z"
      message: Application Gateway For Containers resource has been successfully updated.
      observedGeneration: 1
      reason: Programmed
      status: "True"
      type: Programmed
    controllerName: alb.networking.azure.io/alb-controller
    parentRef:
      group: gateway.networking.k8s.io
      kind: Gateway
      name: gateway-01
      namespace: test-infra

测试对应用程序的访问

现在,我们已准备好通过用于证书的主机名将一些流量发送到示例应用程序。

重要说明

确保将 contoso.com 替换为希望向其颁发证书的域名。

curl https://contoso.com/ -v 2>&1 | grep issuer

应会看到以下输出:

* issuer: C=US; O=Let's Encrypt; CN=R10

恭喜,你已安装 ALB 控制器,部署了后端应用程序,使用 cert-manager 从 Let's Encrypt 颁发了证书,并通过容器应用程序网关将流量路由到了应用程序。