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?
- Dispositivo F5 con Licencia (puede ser de Trial ya que es una PoC)
- Cliente Linux
- 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:
Puntos más importantes del proceso:
- Petición a Let's Encrypt que nos genere un certificado para un dominio específico.
- 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.
- 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.
- 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.
- Una vez validado el desafío, Let's Encrypt envía el equipo Unix el certificado firmado correctamente.
- 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í ).
Realmente en el F5 la configuración inicial es mínima, asignarle una IP, crear un Virtual Server y asignarle la iRule que creamos:
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.
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)
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:
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:
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:
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
Después de la ejecución, podemos comprobar como se han creado los certificados en el 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.
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: