BLOG | NGINX

Habilitación de la gestión de certificados y DNS de autoservicio en Kubernetes

NGINX - Parte de F5 - horizontal, negro, tipo RGB
Miniatura de Jason Schmidt
Jason Schmidt
Publicado el 1 de noviembre de 2022

El objetivo final del desarrollo de aplicação es, por supuesto, exponer aplicaciones en Internet. Para un desarrollador, Kubernetes simplifica este proceso hasta cierto punto al proporcionar el controlador de Ingress como mecanismo para enrutar solicitudes a la aplicação. Pero no todo es tan autoservicio como probablemente quisieras: aún necesitas un registro en el Sistema de nombres de dominio (DNS) para asignar el nombre de dominio de la aplicación a la dirección IP del controlador de Ingress y un certificado TLS para proteger las conexiones usando HTTPS. En la mayoría de las organizaciones, usted no es propietario de DNS o TLS y, por lo tanto, debe coordinarse con el grupo operativo (o los grupos) que sí lo tienen.

Las cosas no son necesariamente más fáciles para los operadores. En la mayoría de las organizaciones, la necesidad de actualizar registros DNS es tan poco frecuente que los procedimientos (tanto las reglas comerciales como los pasos técnicos reales) tienden a ser escasos o inexistentes. Esto significa que cuando necesitas agregar un registro DNS primero debes buscar la documentación, preguntar a un colega o (en el peor de los casos) averiguarlo. También debe asegurarse de cumplir con todas las normas de seguridad corporativas y de que el ingreso esté etiquetado correctamente para los firewalls.

Afortunadamente, existe una manera de hacer la vida más fácil tanto a los desarrolladores como a los operadores. En esta publicación, mostramos cómo los operadores pueden configurar una implementación de Kubernetes para permitir el autoservicio para que los desarrolladores actualicen registros DNS y generen certificados TLS en un entorno de Kubernetes. Al desarrollar la infraestructura con anticipación, puede asegurarse de que se cumplan todos los requisitos comerciales y técnicos necesarios.

Descripción general y requisitos previos

Con la solución implementada, todo lo que un desarrollador necesita hacer para exponer una aplicação a Internet es crear un controlador de Ingress siguiendo una plantilla proporcionada que incluye un nombre de dominio completo (FQDN) dentro de un dominio administrado por la instalación de Kubernetes. Kubernetes usa la plantilla para asignar una dirección IP para el controlador de Ingress, crear el registro DNS A para asignar el FQDN a la dirección IP y generar certificados TLS para el FQDN y agregarlos al controlador de Ingress. La limpieza es igual de sencilla: cuando se elimina el Ingress, se limpian los registros DNS.

La solución aprovecha las siguientes tecnologías (proporcionamos instrucciones de instalación y configuración a continuación):

Antes de configurar la solución, necesita:

  • Una instalación en la nube de Kubernetes con un objeto de salida ( LoadBalancer ). La solución utiliza Linode, pero también funcionan otros proveedores de nube.
  • Un nombre de dominio alojado con Cloudflare , que elegimos porque es uno de los proveedores de DNS compatibles con cert-manager y admite ExternalDNS ( en versión beta al momento de escribir este artículo). Recomendamos encarecidamente que el dominio no se utilice para producción ni para ningún otro propósito crítico.
  • Acceso a la API de Cloudflare, que está incluida en el nivel gratuito.
  • Helm para instalar e implementar Kubernetes.
  • kubectl como interfaz de línea de comandos para Kubernetes.
  • Opcionalmente, K9s , una interfaz de usuario tangible (TUI) bien construida que proporciona una forma más estructurada de interactuar con Kubernetes.

También asumimos que tienes un conocimiento básico de Kubernetes (cómo aplicar un manifiesto, usar un gráfico de Helm y emitir comandos kubectl para ver la salida y solucionar problemas). Comprender los conceptos básicos de Let's Encrypt es útil, pero no obligatorio; para obtener una descripción general, consulte nuestro blog . Tampoco es necesario que sepas cómo funciona cert-manager , pero si te interesa saber cómo funciona (y los certificados en general) con NGINX Ingress Controller, consulta mi publicación reciente, Automatizar la gestión de certificados en un entorno de Kubernetes .

Hemos probado la solución tanto en macOS como en Linux. No hemos realizado pruebas en el Subsistema de Windows para Linux versión 2 (WSL2), pero no prevemos ningún problema.

Nota:  La solución está pensada como una muestra de prueba de concepto y no para su uso en producción. En particular, no incorpora todas las mejores prácticas de operación y seguridad. Para obtener información sobre estos temas, consulte la documentación de cert-manager y ExternalDNS .

Implementación de la solución

Siga los pasos de estas secciones para implementar la solución:

Descargar software
  1. Descargue su token de API de Cloudflare .
  2. Clonar el repositorio del controlador de ingreso NGINX:

    $ git clone https://github.com/nginxinc/kubernetes-ingress.git Clonando en 'kubernetes-ingress'... remoto: Enumeración de objetos: 45176, listo. remoto: Contando objetos: 100% (373/373), hecho. remoto: Comprimiendo objetos: 100% (274/274), hecho. remoto: Total 45176 (delta 173), reutilizados 219 (delta 79), paquete reutilizado 44803 Objetos recibidos: 100% (45176/45176), 60,45 MiB | 26,81 MiB/s, listo.
    Resolviendo deltas: 100% (26592/26592), listo.
  3. Verifique que pueda conectarse al clúster de Kubernetes.

    $ kubectl cluster-info El plano de control de Kubernetes se está ejecutando en https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443 KubeDNS se está ejecutando en https://ba35bacf-b072-4600-9a04-e04...6a3d.us-west-2.linodelke.net:443/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy Para depurar y diagnosticar mejor los problemas del clúster, utilice 'kubectl cluster-info dump'.

Implementar el controlador de ingreso NGINX

  1. Usando Helm, implemente el controlador de ingreso NGINX. Tenga en cuenta que estamos agregando tres opciones de configuración no estándar :

    • controller.enableCustomResources : indica a Helm que instale las definiciones de recursos personalizadas (CRD) utilizadas para crear los recursos personalizados NGINX VirtualServer y VirtualServerRoute .
    • controller.enableCertManager : configura el controlador de ingreso NGINX para comunicarse con los componentes del administrador de certificados .
    • controller.enableExternalDNS : configura el controlador de ingreso para comunicarse con componentes ExternalDNS.
    NOMBRE: nginx-kic ÚLTIMA IMPLEMENTACIÓN: Día Lun DD hh : mm : ss AAAA ESPACIO DE NOMBRES: nginx-ingress ESTADO: implementado REVISIÓN: 1 CONJUNTO DE PRUEBAS: Ninguna NOTAS:
    Se ha instalado el controlador de ingreso NGINX.
  2. Verifique que el controlador de ingreso NGINX se esté ejecutando y anote el valor en el campo IP EXTERNA : es la dirección IP del controlador de ingreso NGINX (aquí, www.xxx.yyy.zzz ). La salida se distribuye en dos líneas para facilitar la legibilidad.

    $ kubectl get services --namespace nginx-ingress NOMBRE TIPO IP DEL CLÚSTER ... nginx-kic-nginx-ingress Balanceador de carga 10.128.152.88 ... ... PUERTO(S) IP EXTERNO(S) EDAD ... www.xxx.yyy.zzz 80:32457/TCP,443:31971/TCP 3h8m

Implementar cert-manager

En la solución, cert-manager utiliza el tipo de desafío DNS-01 al obtener un certificado TLS, lo que requiere que se proporcione el token de API de Cloudflare durante la creación del recurso ClusterIssuer . En la solución, el token de API se proporciona como un secreto de Kubernetes.

  1. Usando Helm, implemente cert-manager :

    $ helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.9.1 --set installCRDs=true NOMBRE: cert-manager ÚLTIMA IMPLEMENTACIÓN: Día Lun DD hh : mm : ss AAAA ESPACIO DE NOMBRES: cert-manager ESTADO: implementado REVISIÓN: 1 CONJUNTO DE PRUEBAS: Ninguna NOTAS: ¡cert-manager v1.9.1 se ha implementado correctamente!
  2. Implemente el token de API de Cloudflare como un secreto de Kubernetes, sustituyéndolo por <su-token-API>:

    $ kubectl apply -f - <<EOFapiVersion: v1
    tipo: Metadatos secretos: nombre: Espacio de nombres de Cloudflare-api-token-secret: tipo de administrador de certificados: Opaco
    stringData:
    api-token: "<su-token-API>"
    Final de carrera
    Se creó el secreto/token de API de Cloudflare secreto
  3. Cree un objeto ClusterIssuer, especificando Cloudflare-api-token-secret (definido en el paso anterior) como el lugar para recuperar el token. Si lo desea, puede reemplazar example-issuer en el campo metadata.name (y example-issuer-account-key en el campo spec.acme.privateKeySecretRef.name ) con un nombre diferente.

    $ kubectl apply -f - <<EOFapiVersion: cert-manager.io/v1
    tipo: Metadatos de ClusterIssuer: nombre: example-issuer espacio de nombres: cert-manager especificación: acme: correo electrónico: example@example.com servidor: https://acme-v02.api.letsencrypt.org/directory privateKeySecretRef: nombre: example-issuer-account-key solucionadores: - dns01:
              Cloudflare: apiTokenSecretRef: nombre: Clave secreta del token de API de Cloudflare: api-token EOF clusterissuer.cert-manager.io/example-issuer creado
  4. Verifique que ClusterIssuer esté implementado y listo (el valor en el campo READY es True ).

    $ kubectl get clusterissuer NOMBRE LISTO EDAD ejemplo-emisor Verdadero 3h9m

Implementar ExternalDNS

Al igual que cert-manager, el proyecto ExternalDNS requiere un token de API de Cloudflare para administrar DNS. Se puede usar el mismo token para ambos proyectos, pero no es obligatorio.

  1. Cree los CRD de ExternalDNS para el controlador de ingreso NGINX para permitir la integración entre los proyectos.

    $ kubectl create -f ./kubernetes-ingress/deployments/common/crds/externaldns.nginx.org_dnsendpoints.yaml customresourcedefinition.apiextensions.k8s.io/dnsendpoints.externaldns.nginx.org creado
  2. Cree el servicio DNS externo ( external-dns ). Como el manifiesto es bastante largo, aquí lo dividiremos en dos partes. La primera parte configura cuentas, roles y permisos:

    • Crea un objeto ServiceAccount llamado external-dns para administrar todas las operaciones de escritura y actualización para administrar DNS.
    • Crea un objeto ClusterRole (también llamado external-dns ) que define los permisos necesarios.
    • Vincula el ClusterRole a la ServiceAccount.
    $ kubectl apply -f - <<EOFapiVersion: v1
    tipo: Metadatos de ServiceAccount: nombre: external-dns --- apiVersion: rbac.authorization.k8s.io/v1 tipo: Metadatos de ClusterRole: nombre: external-dns reglas: - apiGroups: [""] recursos: ["servicios","puntos finales","pods"] verbos: ["obtener","vigilar","listar"] - apiGroups: ["extensiones","networking.k8s.io"] recursos: ["ingresos"] verbos: ["obtener","vigilar","listar"] - apiGroups: ["externaldns.nginx.org"] recursos: ["dnsendpoints"] verbos: ["obtener","vigilar","listar"] - apiGroups: ["externaldns.nginx.org"] recursos: ["dnsendpoints/estado"] verbos: ["actualizar"] - apiGroups: [""] recursos: ["nodos"] verbos: ["listar","vigilar"] --- apiVersion: rbac.authorization.k8s.io/v1 tipo: Metadatos de ClusterRoleBinding: nombre: external-dns-viewer roleRef: apiGroup: rbac.authorization.k8s.io tipo: Nombre de ClusterRole: dns externos sujetos: - tipo: Nombre de cuenta de servicio: external-dns espacio de nombres: predeterminado EOF serviceaccount/external-dns creado clusterrole.rbac.authorization.k8s.io/external-dns creado clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer creado

    La segunda parte del manifiesto crea la implementación de ExternalDNS:

    • Crea un filtro de dominio que limita el alcance de posibles daños causados por ExternalDNS mientras administra dominios. Por ejemplo, puede especificar los nombres de dominio de los entornos de prueba para evitar cambios en los entornos de producción. En este ejemplo, establecemos domain-filter en example.com .
    • Establece la variable de entorno CF_API_TOKEN en su token de API de Cloudflare. Para <su-token-API>, sustituya el token real o un secreto que contenga el token. En el último caso, también es necesario proyectar el secreto en el contenedor mediante una variable de entorno.
    • Establece la variable de entorno FREE_TIER en "verdadero" (apropiado a menos que tenga una suscripción paga de Cloudflare).
    $  kubectl apply -f - <<EOF
    ---
    apiVersion: apps/v1
    kind: Metadatos de implementación: nombre: dns externo especificación: estrategia: tipo: Recrear selector: matchLabels: app: external-dns plantilla: metadatos: etiquetas: app: external-dns especificación: serviceAccountName: external-dns contenedores: - nombre: external-dns imagen: k8s.gcr.io/external-dns/external-dns:v0.12.0 argumentos: - --source=servicio - --source=ingress - --source=crd - --crd-source-apiversion=externaldns.nginx.org/v1 - --crd-source-kind=DNSEndpoint - --domain-filter=example.com - --provider=Cloudflare env: - nombre: CF_API_TOKEN
    valor: "<su-token-API>"
              - nombre: Valor FREE_TIER: "verdadero" EOF serviceaccount/external-dns creado clusterrole.rbac.authorization.k8s.io/external-dns creado clusterrolebinding.rbac.authorization.k8s.io/external-dns-viewer creadoployment.apps/external-dns creado

Implementar la aplicação de muestra

Utilice la aplicação de muestra estándar NGINX Ingress Controller llamada Cafe para fines de prueba.

  1. Implementar la aplicação Cafe.

    $ kubectl apply -f ./kubernetes-ingress/examples/ingress-resources/complete-example/cafe.yaml implementación.apps/coffee creado servicio/coffee-svc creado implementación.apps/tea creado servicio/tea-svc creado
  2. Implementar el controlador de ingreso NGINX para la aplicação Cafe. Tenga en cuenta la siguiente configuración:

    • amable: VirtualServer : utilizamos el recurso personalizado NGINX VirtualServer, no el recurso estándar Kubernetes Ingress.
    • spec.host – Reemplace cafe.example.com con el nombre del host que está implementando. El host debe estar dentro del dominio que se administra con ExternalDNS.
    • spec.tls.cert-manager.cluster-issuer – Si ha estado utilizando los valores especificados en esta publicación, este es example-issuer . Si es necesario, sustituya el nombre que eligió en el Paso 3 de Implementar cert-manager .
    • spec.externalDNS.enable – El valor true le indica a ExternalDNS que cree un registro DNS A.

    Tenga en cuenta que el tiempo que tarda en completarse este paso depende en gran medida del proveedor de DNS, ya que Kubernetes interactúa con la API de DNS del proveedor.

    $ kubectl apply -f - <<EOFapiVersion: k8s.nginx.org/v1
    tipo: Metadatos del servidor virtual: nombre: cafe especificación: host: cafe.example.com tls: secreto: cafe-secreto administrador de certificados: cluster-issuer: example-issuer externalDNS: habilitar: verdadero upstreams: - nombre: tea servicio: tea-svc puerto: 80 - nombre: servicio de café: puerto de servicio de café: 80 rutas: - ruta: /tea acción: contraseña: té - ruta: /café acción: contraseña: café EOF virtualserver.k8s.nginx.org/cafe creado

Validar la solución

  1. Verifique el registro A del DNS, en particular que en el bloque SECCIÓN DE RESPUESTA el FQDN (aquí, cafe.example.com ) esté asignado a la dirección IP correcta ( www.xxx.yyy.zzz ).

    $ dig cafe.example.com ; <<>> DiG 9.10.6 <<>> cafe.example.com ;; opciones globales: +cmd ;; Obtuve la respuesta: ;; ->>HEADER<<- código de operación: CONSULTA, estado: NO ERROR, id: 22633 ;; banderas: qr rd ra; CONSULTA: 1, RESPUESTA: 1. AUTORIDAD: 0, ADICIONAL: 1;; OPTAR PSEUDOSECCIÓN: ; EDNS: versión: 0, banderas:; udp: 4096 ;; SECCIÓN DE PREGUNTAS: ;cafe.example.com.		EN UNA SECCIÓN DE RESPUESTAS ;;: cafe.example.com.	279 EN A www.xxx.yyy.zzz ;; Hora de consulta: 1 mseg ;; SERVIDOR: 2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359#53(2607:fb91:119b:4ac4:2e0: xxxx :fe1e:1359) ;; CUANDO: Día Lun DD hh : mm : ss TZ AAAA ;; TAMAÑO DEL MENSAJE recibido: 67
  2. Compruebe que el certificado sea válido (el valor en el campo READY es True ).

    $ kubectl obtener certificados NOMBRE LISTO SECRETO EDAD cafe-secret True cafe-secret 8m51s
  3. Verifique que pueda acceder a la aplicação.

    $ curl https://cafe.example.com/coffee Dirección del servidor: 10.2.2.4:8080 Nombre del servidor: coffee-7c86d7d67c-lsfs6 Fecha: DD/Lun/AAAA:hh:mm:ss +TZ-offset URI: /coffee ID de solicitud: 91077575f19e6e735a91b9d06e9684cd $ curl https://cafe.example.com/tea Dirección del servidor: 10.2.2.5:8080 Nombre del servidor: tea-5c457db9-ztpns Fecha: DD/Lun/AAAA:hh:mm:ss +TZ-offset URI: /tea ID de solicitud: 2164c245a495d22c11e900aa0103b00f

¿Qué sucede cuando un desarrollador implementa el controlador de ingreso NGINX?

Una vez que se implementa la solución, ocurren muchas cosas bajo tierra. El diagrama muestra lo que sucede cuando un desarrollador implementa el controlador de ingreso NGINX con un recurso personalizado NGINX VirtualServer. Téngase en cuenta que se omiten algunos detalles operativos.

  1. El desarrollador implementa un recurso VirtualServer utilizando NGINX CRD
  2. Kubernetes crea el servidor virtual mediante el controlador de ingreso NGINX
  3. El controlador de ingreso de NGINX llama a ExternalDNS para crear un registro DNS A
  4. ExternalDNS crea el registro A en DNS
  5. El controlador de ingreso de NGINX llama a cert-manager para solicitar un certificado TLS
  6. cert-manager agrega un registro DNS para usar durante el desafío DNS-01
  7. cert-manager contacta a Let’s Encrypt para completar el desafío
  8. Let’s Encrypt valida el desafío contra DNS
  9. Let’s Encrypt emite el certificado TLS
  10. cert-manager proporciona el certificado TLS al controlador de ingreso NGINX
  11. El controlador de ingreso NGINX enruta las solicitudes externas protegidas por TLS a los pods de la aplicação

Solución de problemas

Dada la complejidad de Kubernetes junto con los componentes que utilizamos, es difícil proporcionar una guía completa de solución de problemas. Dicho esto, hay algunas sugerencias básicas para ayudarle a determinar el problema.

  • Utilice los comandos kubectl get y kubectl describe para validar la configuración de los objetos implementados.
  • Utilice el kubectl registros <componente> Comando para ver los archivos de registro de los distintos componentes implementados.
  • Utilice K9s para inspeccionar la instalación; el software resalta los problemas en amarillo o rojo (dependiendo de la gravedad) y proporciona una interfaz para acceder a registros y detalles sobre los objetos.

Si aún tienes problemas, encuéntranos en el Slack de la comunidad NGINX y solicita ayuda. Tenemos una comunidad vibrante y siempre estamos felices de resolver los problemas.

Para probar el controlador de ingreso NGINX basado en NGINX Plus, comience hoy su prueba gratuita de 30 días o contáctenos para analizar sus casos de uso .


"Esta publicación de blog puede hacer referencia a productos que ya no están disponibles o que ya no reciben soporte. Para obtener la información más actualizada sobre los productos y soluciones F5 NGINX disponibles, explore nuestra familia de productos NGINX . NGINX ahora es parte de F5. Todos los enlaces anteriores de NGINX.com redirigirán a contenido similar de NGINX en F5.com.