Compartir a través de


Cert-manager y Let's Encrypt con Application Gateway for Containers: API de puerta de enlace

En esta guía se muestra cómo usar cert-manager para emitir y renovar automáticamente certificados SSL/TLS a uno o varios servidores front-end de la implementación de Azure Application Gateway for Containers. Usamos la API de puerta de enlace para configurar los recursos necesarios.

Para los fines de este ejemplo, tenemos certificados configurados por cert-manager emitidos desde Let's Encrypt para demostrar una implementación de un extremo a otro, donde Application Gateway for Containers proporciona la descarga de TLS.

Ilustración que muestra cert-manager que recupera un certificado de Let's Encrypt y lo almacena en el almacén de secretos de Kubernetes para TLS con Application Gateway for Containers.

Para que Let's Encrypt emita certificados, la autoridad requiere un desafío para validar la propiedad del dominio. Esta validación se produce al permitir que cert-manager cree un recurso de pod y HTTPRoute que exponga un punto de conexión durante la emisión del certificado, lo que demuestra su propiedad del nombre de dominio.

Puede encontrar más detalles generales sobre cert-manager y Let's Encrypt con AKS aquí.

Requisitos previos

  1. Si sigue la estrategia Traiga su propia (BYO) implementación, asegúrese de configurar los recursos de Puerta de enlace de aplicaciones para contenedores y del controlador de ALB.

  2. Si sigue la estrategia de implementación administrada de ALB, asegúrese de aprovisionar su controlador de ALB y los recursos de Puerta de enlace de aplicaciones para contenedores mediante el recurso personalizado ApplicationLoadBalancer.

  3. Implementar aplicación HTTP de ejemplo: aplique el siguiente archivo deployment.yaml en el clúster para crear una aplicación web de ejemplo para mostrar la reescritura de encabezado.

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

    Este comando crea lo siguiente en el clúster:

    • un espacio de nombres denominado test-infra
    • dos servicios llamados backend-v1 y backend-v2 en el espacio de nombres test-infra
    • dos implementaciones llamadas backend-v1 y backend-v2 en el espacio de nombres test-infra

Creación de un recurso de puerta de enlace

Cree un nuevo recurso de Gateway que escuche las solicitudes HTTP de Let's Encrypt durante el proceso de desafío.

Cree una puerta de enlace:

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

Nota:

Cuando el controlador de ALB cree los recursos de Puerta de enlace de aplicaciones para contenedores en ARM, usará las siguientes convenciones de nomenclatura para un recurso de frontend: fe-<8 caracteres generados aleatoriamente>

Si desea cambiar el nombre del frontend creado en Azure, considere la posibilidad de seguir la estrategia Traiga su propia implementación.

Una vez creado el recurso de puerta de enlace, asegúrese de que el estado sea válido, de que el cliente de escucha se haya programado y de que se haya asignado una dirección a la puerta de enlace.

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

Salida de ejemplo de la creación correcta de la puerta de enlace.

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

Instalar cert-manager

Instale cert-manager mediante Helm:

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

La instalación de Helm crea tres implementaciones y algunos servicios y pods en un nuevo espacio de nombres denominado cert-manager. También instala recursos auxiliares de ámbito de clúster, como roles RBAC y definiciones de recursos personalizados.

Creación de un ClusterIssuer

Cree un recurso ClusterIssuer para definir cómo se comunicará cert-manager con Let's Encrypt. En este ejemplo, se usa un desafío HTTP. Durante el desafío, cert-manager crea un recurso de HTTPRoute y el pod correspondiente que presenta un punto de conexión de validación para demostrar la propiedad del dominio.

Sugerencia

Otros desafíos admitidos por Let's Encrypt se documentan en letsencrypt.org: tipos de desafíos

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

Comprobación de que se creó el recurso

kubectl get ClusterIssuer -A -o yaml

El estado debe mostrar True y el tipo 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

Crear un certificado

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

Ejecute el siguiente comando para validar la emisión del certificado. Si se ha emitido el certificado, el valor de la columna READY debe ser True.

kubectl get certificate letsencrypt-cert -n test-infra

Si no se ha emitido el certificado, puede ejecutar el siguiente comando para validar el estado de un desafío.

Nota:

Si el certificado se ha emitido correctamente, el desafío ya no se mostrará.

kubectl get challenges -n test-infra -o yaml

Habilitación de HTTPS en el recurso de puerta de enlace

Modifique la puerta de enlace para agregar un segundo agente de escucha para finalizar las solicitudes HTTPS con el certificado Let's Encrypt emitido.

Cree una puerta de enlace:

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

Nota:

Cuando el controlador de ALB cree los recursos de Puerta de enlace de aplicaciones para contenedores en ARM, usará las siguientes convenciones de nomenclatura para un recurso de frontend: fe-<8 caracteres generados aleatoriamente>

Si desea cambiar el nombre del frontend creado en Azure, considere la posibilidad de seguir la estrategia Traiga su propia implementación.

Creación de un HTTPRoute que escuche el nombre de host

Cree un HTTPRoute para controlar las solicitudes recibidas por el agente de escucha de https-listener.

Importante

Asegúrese de reemplazar contoso.com por el nombre de dominio al que espera que se emita el certificado.

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

Una vez creado el recurso HTTPRoute, asegúrese de que la ruta se haya aceptado y de que el recurso de Puerta de enlace de aplicaciones para contenedores se haya programado.

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

Compruebe que el estado del recurso Application Gateway for Containers se actualiza correctamente.

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

Prueba de acceso a la aplicación

Ahora estamos listos para enviar tráfico a nuestra aplicación de ejemplo, a través del nombre de host que se usa para el certificado.

Importante

Asegúrese de reemplazar contoso.com por el nombre de dominio al que espera que se emita el certificado.

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

Tras el resultado, debería ver

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

Enhorabuena, ha instalado el controlador ALB, ha implementado una aplicación de back-end, ha emitido un certificado de Let's Encrypt con cert-manager y ha enrutado el tráfico a la aplicación a través de Application Gateway for Containers.