Esta vez me ha tocado un poco de automatización 😊. Ha surgido la necesidad de poder actualizar los certificados de tráfico del F5 de forma dinámica en un proyecto , ya que no tienen mucho tiempo de vida. En este caso los certificados se los genera Let’s Encrypt.

Por ello, he montado una pequeña POC que me gustaría compartiros donde monto un escenario y automatizo la renovación de dichos certificados para los balanceadores F5.

En el post, no entro a mucho nivel de comandos ya que no es el objetivo de la PoC, pero si tenéis dudas no dudéis en escribirnos.

En esta PoC vamos a mostrar como renovar certificados (o importarlos nuevos) en F5 de una forma totalmente automatizada. De esta forma no tendremos que estar pendiente de la caducidad de los certificados, sino que el automatismo lo hará por nosotros.

¿Qué requisitos son necesarios para montar este escenario?

  1. Dispositivo F5 con Licencia (puede ser de Trial ya que es una PoC)
  2. Cliente Linux
  3. Ansible

A modo simplista os muestro la arquitectura del escenario montado para la POC, a continuación se detallan a groso modo los diferentes pasos que se producen en el sistema:

Proceso de automatización de certificados en F5 con Ansible

Puntos más importantes del proceso:

  1. Petición a Let's Encrypt que nos genere un certificado para un dominio específico.
  2. Nos responde y nos lanza un desafío (Una clave que comprobará por http o DNS). Esto es para comprobar que seamos propietario del dominio.
  3. El dominio resolverá a una IP que tiene el F5, por lo que Let's Encrypt lanzará el desafío al F5, preguntando por una ruta específica.
  4. Desde el equipo Unix, se cargará el desafío al F5 usando Ansible. También se creará una iRule para procesar el desafío HTTP y responder correctamente.
  5. Una vez validado el desafío, Let's Encrypt envía el equipo Unix el certificado firmado correctamente.
  6. Cuando el equipo Unix tiene posesión del certificado firmado, usando Ansible lo carga automáticamente al F5.

Una vez hemos comentado muy por encima el funcionamiento del escenario vamos a comentar lo interesante, ¿Cómo montarlo?

Configuración F5 para automatizar la renovación de certificados

Como he comentado anteriormente, necesitamos un dispositivo F5 con licencia. En mi caso lo he virtualizado y he generado una licencia de pruebas (puede hacerse con cualquier cuenta, aquí ).

Licencias F5
GNS3 F5

Realmente en el F5 la configuración inicial es mínima, asignarle una IP, crear un Virtual Server y asignarle la iRule que creamos:

Creación Virtual Server F5
Creación de listener para virtual Server F5

En esta PoC es necesario que el dominio para el que se va a generar el certificado acabe resolviendo a la IP que tiene el F5. En este escenario solo se disponía de 1 IP pública, la del router de salida a INET, por lo que se ha usado un servicio de DNS dinámico (gratuito). El conocido NO-IP.

Servicio NO-IP

Una vez tenemos esta asignación de DNS, realizamos una publicación en el router para que reenvíe el puerto 80 a 192.168.1.69:80 (el F5)

Crear regla de router

Con estas configuraciones, ya tendríamos la parte inicial del F5 configuradas.

Configuración Unix y Ansible para automatizar la renovación de certificados

Para implementar esta configuración, nos hemos basado en los siguientes sitio de github:

  1. Dehydrated bigip ansible
  2. Dehydrated

Realmente quien implementa toda la lógica en cuanto a certificado es dehydrated, que es una herramienta escrita en BASH que interactúa con Let's Encrypt usando el estándar ACME (Automatic Certificate Management Environment). Para dotar de automatismo a la hora de desplegar/renovar, han desarrollado unos Playbooks de ansible para hacer toda la integración en F5.

Como comentaba anteriormente, hay varios tipos de desafíos. En esta PoC hemos usado HTTP.

Instalación de dehydrated y ansible

Podemos hacerlo fácilmente por paquetería:

dnf install epel-relase
dnf install ansible
dnf install dehydrated

Para testeo debemos usar el servicio de pruebas de Let's Encrypt,

vim /etc/dehydrated/config
CA="letsencrypt-test"

Tenemos que definir para que dominio generamos el certificado:

Definición de dominios para generar el certificado

Para configurar los playbooks de ansible, podemos visitar la WIKI del desarrollador

TEMPDIR=`mktemp -d`
cd ${TEMPDIR}
curl -o dehydrated-bigip-ansible-master.zip https://codeload.github.com/EquateTechnologies/dehydrated-bigip-ansible/zip/master
unzip dehydrated-bigip-ansible-master.zip
cp -Rv dehydrated-bigip-ansible-master/etc/dehydrated/ansible /etc/dehydrated/ansible
cp -Rv dehydrated-bigip-ansible-master/etc/dehydrated/lib.d /etc/dehydrated/lib.d
chmod 0600 /etc/dehydrated/ansible/bigip-inventory.ini
chmod 0755 /etc/dehydrated/ansible/hooks/*.sh
cd
rm -rf ${TEMPDIR}

Definición de variables globales

vim /etc/dehydrated/conf.d/ansible.sh
 
ANSIBLE_ARGS=${ANSIBLE_ARGS:-""}
ANSIBLE_INVENTORY=${ANSIBLE_INVENTORY:-"/etc/dehydrated/ansible/bigip-inventory.ini"}
ANSIBLE_PLAYBOOK_CLEAN_CHALLENGE=${ANSIBLE_PLAYBOOK_CLEAN_CHALLENGE:-"/etc/dehydrated/ansible/playbooks/bigip-clean_challenge.yml"}
ANSIBLE_PLAYBOOK_DEPLOY_CERT_MANAGEMENT=${ANSIBLE_PLAYBOOK_DEPLOY_CERT_MANAGEMENT:-"/etc/dehydrated/ansible/playbooks/bigip-deploy_cert-management.yml"}
ANSIBLE_PLAYBOOK_DEPLOY_CERT_TRAFFIC=${ANSIBLE_PLAYBOOK_DEPLOY_CERT_TRAFFIC:-"/etc/dehydrated/ansible/playbooks/bigip-deploy_cert-traffic.yml"}
ANSIBLE_PLAYBOOK_DEPLOY_CHALLENGE=${ANSIBLE_PLAYBOOK_DEPLOY_CHALLENGE:-"/etc/dehydrated/ansible/playbooks/bigip-deploy_challenge.yml"
vim /etc/dehydrated/conf.d/bigip.sh 
 
BIGIP_CLIENT_SSL_MANAGE=${BIGIP_CLIENT_SSL_MANAGE:-1}
BIGIP_CLIENT_SSL_PARENT=${BIGIP_CLIENT_SSL_PARENT:-"/Common/clientssl"}
BIGIP_DATA_GROUP_NAME=${BIGIP_DATA_GROUP_NAME:-"ACME_http-01"}
BIGIP_ISSUER_CERT=${BIGIP_ISSUER_CERT:-"Lets-Encrypt-X3"}
BIGIP_PARTITION=${BIGIP_PARTITION:-"Common"}
BIGIP_SAVE_CONFIG=${BIGIP_SAVE_CONFIG:-1}
BIGIP_SYNC_CONFIG=${BIGIP_SYNC_CONFIG:-0}
BIGIP_SYNC_DEVICE_GROUP=${BIGIP_SYNC_DEVICE_GROUP:-"SYNC-FAILOVER-1"}

Inventario de Ansible:

Inventario de Ansible
NOTA: Tener en cuenta que usamos estas credenciales por defecto al tratarse de una PoC y que siempre deberán modificarse en un entorno productivo.

Una vez configurado y con todos los scripts en sus ubicaciones, estamos en disposición ejecutar el automatismo.

Antes que nada nos registramos:

dehydrated  --register

Ejemplo de ejecución:

dehydrated --hook /etc/dehydrated/ansible/hooks/bigip-traffic-http-01.sh --accept-terms -c
dehydrated F5 Parte 1
dehydrated F5 Parte 2

Después de la ejecución, podemos comprobar como se han creado los certificados en el F5:

Creación de certificado automático en F5
Propiedades Certificado creado en F5

Una vez realizado, este comando se dejará configurado como tarea planificada, para que se ejecute 1 vez al día. Si lo volvemos a lanzar, indica que no lo renueva ya que quedan más de 30 días. El tiempo mínimo para la renovación es configurable. En este caso, cuando queden menos de 30 días, volverá a generar un nuevo certificado de forma automática y lo actualizará en el F5.

Es posible configurar un correo para que avise con notificaciones/resultados.

Emision notificaciones de renovaciones certificados F5

NOTA: Con la siguiente opción podemos forzar la renovación, aunque falten más de X días:

dehydrated --hook /etc/dehydrated/ansible/hooks/bigip-traffic-http-01.sh --accept-terms -c --force

Espero que en algún momento os sea útil, ya que muchos clientes usan este tipo de certificados, evitando tener que estar pendientes de que no caduquen.

Referencias usadas: