在私有 AKS 配置 Cert Manager 管理TLS证书

2025-09-01#Azure#证书#Kubernetes

Cert Manager 是 Kubernetes 生态中用于自动化管理和签发 TLS 证书的工具,支持多种证书颁发机构。其提供的主要挑战方法包括 HTTP-01(通过 HTTP 验证域名控制权)和 DNS-01(通过 DNS 记录记录验证)等。本文介绍在私有 AKS 里使用 Cert Manager 的方法。

关键要点 🔗

  1. 私有 AKS 没有暴露给互联网。因此无法使用 HTTP-01 挑战;而应该使用 DNS-01 挑战;
  2. 私有 AKS 的虚拟网络可能关联了私有DNS区域,因此 Cert Manager在验证 DNS TXT 的时候,无法访问公共 DNS 区域。

安装和配置 Cert Manager 🔗

创建 UAI 并授予权限 🔗

确保 UAI 能够读写公共 DNS 区域的域名的 TXT 记录。如果能够接受不那么严格的最小权限原则,那么可以给它授予 DNS Zone Contributor 角色。

确保 Cert Manager 可创建 cert-manager.io:ClusterIssuer 🔗

Cert Manager 会创建集群级别的资源 cert-manager.io:ClusterIssuer,应该确保它有权限创建。

创建 Helm chart 🔗

Cert Manager 提供了使用 Helm 部署的详细文档 文档。可创建一个新的 Helm Chart,然后 cert-manager 作为依赖项。比如:

apiVersion: v2
name: cert-manager
description: Cert Manager
type: application
version: 1.0.0
appVersion: v1.18.2

dependencies:
  - name: cert-manager
    version: v1.18.2
    repository: https://charts.jetstack.io
    alias: cert-manager
    condition: cert-manager.enabled

其默认的 values 文件为:

global:
  leaderElection:
    namespace: cert-manager

cert-manager:
  enabled: true
  namespace: cert-manager
  crds:
    enabled: true
  podLabels:
    azure.workload.identity/use: "true"
  prometheus:
    enabled: false
  serviceAccount:
    labels:
      azure.workload.identity/use: "true"
  dns01RecursiveNameserversOnly: true
  dns01RecursiveNameservers: 8.8.8.8:53,1.1.1.1:53

注意:这里实质上给 cert-manager-controller 设置了 --dns01-recursive-nameservers-only=true --dns01-recursive-nameservers=8.8.8.8:53,1.1.1.1:53 选项。这是因为如果 Cert Manager 所在的节点如果启用了私有DNS区域,那么无法访问公共 DNS 上的 TXT 记录来验证域名;启用这两个选项后,那么 Cert Manage 机会使用这两个公共的递归 DNS 服务器进行 TXT 记录查询。

除此之外,还需要创建一个模板,用于创建 ClusterIssuer。比如:

apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt-dns-01
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: {{ .Values.clusterIssuer.email }}
    privateKeySecretRef:
      name: letsencrypt-dns-01
    solvers:
    - dns01:
        azureDNS:
          subscriptionID: {{ .Values.clusterIssuer.subscriptionID }}
          resourceGroupName: {{ .Values.clusterIssuer.resourceGroupName }}
          hostedZoneName: {{ .Values.clusterIssuer.hostedZoneName }}
          environment: AzurePublicCloud
          managedIdentity:
            resourceID: {{ .Values.clusterIssuer.managedIdentityResourceID }}

这样 Helm Chart 就创建好了。

Values 文件 🔗

Helm Chart 里的 values 文件已经包含了大部分配置。在需要部署时,还需要执行 workload identity id 等。为此,创建部署时需要的额外的 values 文件,内部大致如下:

cert-manager:
  serviceAccount:
    annotations:
      azure.workload.identity/client-id: {uai_client_id}

clusterIssuer:
  email: ''
  resourceGroupName: {resource_group_name}
  hostedZoneName: {zone_name}
  subscriptionID: {subscription_id}
  managedIdentityResourceID: /subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.ManagedIdentity/userAssignedIdentities/{uai_name}

使用证书 🔗

在 Ingress 中使用证书 🔗

在 Ingress 中使用证书是一个常见的场景,见文档《Annotated Ingress resource》,使用 cert-manager.io/cluster-issuer 注解即可。

创建 Certificate 🔗

可创建如下的模板,用于创建证书:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: {{ .Value.certificate.name }}
  namespace: {{ .Release.Namespace }}
spec:
  secretName: {{ .Values.certificate.secretName }}
  issuerRef:
    name: {{ .Values.certificate.issuerName }}
    kind: ClusterIssuer
  commonName: {{ .Values.certificate.domain }}
  dnsNames:
    - {{ .Values.certificate.domain }}

在应用中,使用 Certificate 创建的 Secret,即可加载证书。但是需要注意的是创建顺序,因为这个 Secret 的创建会有延迟:创建了 Certificate 创建之后的,需要等一段时间才会成功签发证书,此后才会创建 Secret。