Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2575026dc7 | |||
| edb3a22ec0 | |||
| 6253223fdf | |||
| 06a513799e | |||
| 7f38023c7d | |||
| 63a21e5145 |
162
DNS_ARCHITECTURE.md
Normal file
162
DNS_ARCHITECTURE.md
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# Arquitectura DNS y Validación ACME
|
||||||
|
|
||||||
|
Este documento explica cómo funciona el sistema DNS distribuido y la validación de certificados SSL para dominios FQDN.
|
||||||
|
|
||||||
|
## Componentes DNS
|
||||||
|
|
||||||
|
### 1. Servidores Knot (Autoritativos Remotos)
|
||||||
|
|
||||||
|
**Ubicación:** `anarres.sutty.nl`, `athshe.sutty.nl`, `gethen.sutty.nl`, `ganam.sutty.nl`
|
||||||
|
|
||||||
|
**Función:** DNS autoritativo real para:
|
||||||
|
- Zona `abyaya.la`
|
||||||
|
- Zonas FQDN (ej: `latina.red`, `example.com.ar`)
|
||||||
|
|
||||||
|
**Actualización:** Via `knsupdate` ejecutado desde el proxy
|
||||||
|
|
||||||
|
### 2. Proxy (Hetzner: 5.161.236.18)
|
||||||
|
|
||||||
|
**Servicios DNS en diferentes IPs:**
|
||||||
|
|
||||||
|
| Servicio | IP | Puerto | Función |
|
||||||
|
|----------|-------|--------|---------|
|
||||||
|
| **dnsmasq** | `10.13.12.1` + `127.0.0.1` | 53 | DNS cache/resolver para VPN interna |
|
||||||
|
| **certbot dns-standalone** | `5.161.236.18` | 53 | DNS temporal para validación ACME |
|
||||||
|
|
||||||
|
**No hay conflicto de puertos** porque usan IPs diferentes en la misma máquina.
|
||||||
|
|
||||||
|
## Flujo de Validación ACME para Dominios FQDN
|
||||||
|
|
||||||
|
### Ejemplo: Certificado para `kipu.latina.red`
|
||||||
|
|
||||||
|
#### Paso 1: knsupdate configura delegación en Knot
|
||||||
|
|
||||||
|
Cuando se despliega un servicio con FQDN, `knsupdate` crea estos registros en los servidores Knot:
|
||||||
|
|
||||||
|
```dns
|
||||||
|
; En zona latina.red
|
||||||
|
kipu.latina.red IN A 5.161.236.18
|
||||||
|
*.kipu.latina.red IN A 5.161.236.18
|
||||||
|
_acme-challenge.kipu.latina.red IN CNAME abyaya.la.
|
||||||
|
_acme-challenge.kipu.latina.red IN NS _acme-challenge.abyaya.la.
|
||||||
|
|
||||||
|
; En zona abyaya.la
|
||||||
|
_acme-challenge.abyaya.la IN A 5.161.236.18
|
||||||
|
_acme-challenge IN NS _acme-challenge.abyaya.la.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Propósito de la delegación:**
|
||||||
|
- El CNAME redirige la validación a `abyaya.la`
|
||||||
|
- El NS delega la autoridad a `_acme-challenge.abyaya.la`
|
||||||
|
- Que apunta al proxy donde certbot corre
|
||||||
|
|
||||||
|
#### Paso 2: Certbot obtiene/renueva certificado
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm \
|
||||||
|
-v abyayala_certs_data:/etc/letsencrypt \
|
||||||
|
--network host \
|
||||||
|
numericalatina/certbot-wildcard \
|
||||||
|
certonly --dns-standalone-address=5.161.236.18 --dns-standalone-port=53 \
|
||||||
|
-d kipu.latina.red -d *.kipu.latina.red
|
||||||
|
```
|
||||||
|
|
||||||
|
**Certbot:**
|
||||||
|
1. Levanta un servidor DNS temporal en `5.161.236.18:53`
|
||||||
|
2. Crea el registro TXT con el token de validación
|
||||||
|
3. Notifica a Let's Encrypt que está listo
|
||||||
|
|
||||||
|
#### Paso 3: Let's Encrypt valida
|
||||||
|
|
||||||
|
```
|
||||||
|
Let's Encrypt consulta: _acme-challenge.kipu.latina.red
|
||||||
|
↓ Consulta a nameservers de latina.red (Knot)
|
||||||
|
↓ Knot responde con CNAME
|
||||||
|
|
||||||
|
Redirigido a: _acme-challenge.abyaya.la
|
||||||
|
↓ Consulta delegación NS
|
||||||
|
↓ Knot indica: usar nameserver _acme-challenge.abyaya.la
|
||||||
|
|
||||||
|
Consulta directa a: 5.161.236.18:53
|
||||||
|
↓ certbot dns-standalone responde
|
||||||
|
↓ Proporciona el token TXT
|
||||||
|
|
||||||
|
✓ Validación exitosa
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuración Requerida en DNS Externo
|
||||||
|
|
||||||
|
Para que un dominio FQDN externo (no `.abyaya.la`) pueda delegar la validación ACME al proxy, es necesario agregar estos registros en el DNS del dominio:
|
||||||
|
|
||||||
|
```dns
|
||||||
|
_acme-challenge IN CNAME abyaya.la.
|
||||||
|
_acme-challenge IN NS _acme-challenge.abyaya.la.
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ejemplo para `kipu.latina.red`:**
|
||||||
|
```dns
|
||||||
|
; En el DNS de latina.red
|
||||||
|
_acme-challenge.kipu IN CNAME abyaya.la.
|
||||||
|
_acme-challenge.kipu IN NS _acme-challenge.abyaya.la.
|
||||||
|
```
|
||||||
|
|
||||||
|
Esto se hace **una sola vez por dominio** y permite que todos los subdominios deleguen automáticamente.
|
||||||
|
|
||||||
|
## Renovación Automática
|
||||||
|
|
||||||
|
La renovación de certificados funciona automáticamente porque:
|
||||||
|
|
||||||
|
1. ✅ **Delegación persistente**: Los registros `_acme-challenge` ya están en Knot
|
||||||
|
2. ✅ **Cron configurado**: Se ejecuta los días 4 y 18 de cada mes
|
||||||
|
3. ✅ **Sin conflictos**: dnsmasq y certbot usan IPs diferentes
|
||||||
|
4. ✅ **Mismo método**: `certbot renew` usa dns-standalone automáticamente
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Configurado en roles/certbot/tasks/main.yml
|
||||||
|
- name: automatic letsencrypt certs renewal
|
||||||
|
cron:
|
||||||
|
name: certificate renewal
|
||||||
|
day: 4,18
|
||||||
|
hour: 0
|
||||||
|
minute: 0
|
||||||
|
job: "docker run --rm -v abyayala_certs_data:/etc/letsencrypt --network host numericalatina/certbot-wildcard renew --dns-standalone-address=5.161.236.18 --dns-standalone-port=53 >> /var/log/renewal.log 2>&1"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Ventajas de esta Arquitectura
|
||||||
|
|
||||||
|
1. **Centralizada**: Un solo proxy maneja validación ACME para todos los dominios
|
||||||
|
2. **Segura**: No requiere credenciales API de proveedores DNS externos
|
||||||
|
3. **Flexible**: Soporta dominios `.abyaya.la` y FQDN externos
|
||||||
|
4. **Automatizada**: Renovación sin intervención manual
|
||||||
|
5. **Escalable**: Agregar nuevos dominios solo requiere actualizar `abyayala.yml`
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Verificar delegación DNS
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Verificar CNAME
|
||||||
|
dig _acme-challenge.kipu.latina.red CNAME
|
||||||
|
|
||||||
|
# Verificar NS delegation
|
||||||
|
dig _acme-challenge.kipu.latina.red NS
|
||||||
|
|
||||||
|
# Probar resolución completa
|
||||||
|
dig @5.161.236.18 _acme-challenge.kipu.latina.red TXT
|
||||||
|
```
|
||||||
|
|
||||||
|
### Ver logs de renovación
|
||||||
|
|
||||||
|
```bash
|
||||||
|
tail -f /var/log/renewal.log
|
||||||
|
```
|
||||||
|
|
||||||
|
### Probar renovación manualmente
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm \
|
||||||
|
-v abyayala_certs_data:/etc/letsencrypt \
|
||||||
|
--network host \
|
||||||
|
numericalatina/certbot-wildcard \
|
||||||
|
renew --dns-standalone-address=5.161.236.18 --dns-standalone-port=53 --dry-run
|
||||||
|
```
|
||||||
133
FQDN_AUTHORITATIVE.md
Normal file
133
FQDN_AUTHORITATIVE.md
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
# Soporte para Dominios FQDN Autoritativos
|
||||||
|
|
||||||
|
Esta feature añade soporte para usar dominios FQDN externos (ejemplo.com, kipu.latina.red, etc.) además de subdominios .abyaya.la.
|
||||||
|
|
||||||
|
## Cambios Implementados
|
||||||
|
|
||||||
|
### 1. Generación Automática de Subdominio Default
|
||||||
|
|
||||||
|
Cuando se define un dominio FQDN, el sistema genera automáticamente un subdominio `.abyaya.la` basado en el `service_name` que funciona como alias.
|
||||||
|
|
||||||
|
**Ejemplo:**
|
||||||
|
```yaml
|
||||||
|
- service_name: kipu
|
||||||
|
domains:
|
||||||
|
- kipu.latina.red
|
||||||
|
nodo: kipu.comun
|
||||||
|
force_https: yes
|
||||||
|
```
|
||||||
|
|
||||||
|
El sistema automáticamente añade `kipu.abyaya.la` a la lista de dominios, por lo que ambos dominios funcionarán y redirigirán al primero de la lista.
|
||||||
|
|
||||||
|
### 2. Soporte para TLDs Compuestos
|
||||||
|
|
||||||
|
El sistema detecta automáticamente TLDs compuestos como `.com.ar`, `.co.uk`, `.com.br`, etc., y extrae correctamente la zona DNS.
|
||||||
|
|
||||||
|
**TLDs soportados:**
|
||||||
|
- com.ar, gov.ar, org.ar, gob.ar, net.ar, mil.ar, edu.ar
|
||||||
|
- com.mx
|
||||||
|
- co.uk
|
||||||
|
- com.br
|
||||||
|
- co.nz, net.nz, org.nz
|
||||||
|
|
||||||
|
Para añadir más TLDs, editar `roles/knsupdate/vars/main.yml`.
|
||||||
|
|
||||||
|
### 3. Actualización DNS Multi-Zona
|
||||||
|
|
||||||
|
El sistema ahora actualiza correctamente el DNS en Knot para cada dominio según su tipo:
|
||||||
|
|
||||||
|
- **Subdominios .abyaya.la**: Se actualizan en la zona `abyaya.la.`
|
||||||
|
- **FQDN autoritativos**: Se actualizan en su zona correspondiente (ej: `latina.red.`, `example.com.ar.`)
|
||||||
|
|
||||||
|
La detección es **completamente automática** basada en el sufijo del dominio.
|
||||||
|
|
||||||
|
## Uso
|
||||||
|
|
||||||
|
### Caso Básico: Solo FQDN
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- service_name: ejemplo
|
||||||
|
domains:
|
||||||
|
- ejemplo.latina.red
|
||||||
|
nodo: ejemplo.comun
|
||||||
|
force_https: yes
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resultado:**
|
||||||
|
- `ejemplo.latina.red` → Dominio principal (detectado como FQDN)
|
||||||
|
- `ejemplo.abyaya.la` → Generado automáticamente como alias
|
||||||
|
- Ambos tienen certificados SSL wildcard
|
||||||
|
- Ambos redirigen al primero (ejemplo.latina.red)
|
||||||
|
|
||||||
|
### Caso Avanzado: Múltiples Dominios
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- service_name: miapp
|
||||||
|
domains:
|
||||||
|
- miapp.com.ar
|
||||||
|
- miapp.latina.red
|
||||||
|
- miapp.abyaya.la
|
||||||
|
nodo: miapp.comun
|
||||||
|
force_https: yes
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resultado:**
|
||||||
|
- Los tres dominios funcionan
|
||||||
|
- Todos redirigen al primero (miapp.com.ar)
|
||||||
|
- Certificados SSL para cada dominio + wildcards
|
||||||
|
- DNS actualizado en zonas: `com.ar.`, `latina.red.`, `abyaya.la.`
|
||||||
|
|
||||||
|
### Subdominios de FQDN
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- service_name: api
|
||||||
|
domains:
|
||||||
|
- api.ejemplo.com.ar
|
||||||
|
nodo: api.comun
|
||||||
|
force_https: yes
|
||||||
|
```
|
||||||
|
|
||||||
|
**Resultado:**
|
||||||
|
- `api.ejemplo.com.ar` → Dominio principal (hostname: api, zona: com.ar.)
|
||||||
|
- `api.abyaya.la` → Generado automáticamente
|
||||||
|
|
||||||
|
## Archivos Modificados
|
||||||
|
|
||||||
|
1. **roles/proxy/tasks/main.yml**: Añade dominio default .abyaya.la automáticamente
|
||||||
|
2. **roles/knsupdate/vars/main.yml**: Lista de TLDs compuestos
|
||||||
|
3. **roles/knsupdate/tasks/update.yml**: Procesa múltiples dominios
|
||||||
|
4. **roles/knsupdate/tasks/update_domain.yml**: Nuevo archivo que detecta tipo de dominio
|
||||||
|
5. **roles/knsupdate/tasks/templates/commands.j2**: Usa zona y hostname dinámicos
|
||||||
|
|
||||||
|
## Comportamiento de Certificados SSL
|
||||||
|
|
||||||
|
Certbot obtiene certificados para **todos** los dominios listados más sus wildcards:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
certbot certonly -d ejemplo.com.ar -d *.ejemplo.com.ar -d ejemplo.abyaya.la -d *.ejemplo.abyaya.la
|
||||||
|
```
|
||||||
|
|
||||||
|
Usa el método `dns-standalone` que requiere que el proxy controle el DNS autoritativo. Esto funciona porque knsupdate actualiza Knot con todos los dominios.
|
||||||
|
|
||||||
|
## Migración desde Configuración Anterior
|
||||||
|
|
||||||
|
La configuración anterior sigue funcionando sin cambios:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- service_name: viejo
|
||||||
|
domains:
|
||||||
|
- viejo.abyaya.la
|
||||||
|
nodo: viejo.comun
|
||||||
|
force_https: yes
|
||||||
|
```
|
||||||
|
|
||||||
|
Todo funciona exactamente igual para subdominios .abyaya.la existentes.
|
||||||
|
|
||||||
|
## Notas Técnicas
|
||||||
|
|
||||||
|
- La detección de tipo de dominio es **completamente automática** basada en el sufijo `.abyaya.la`
|
||||||
|
- Los subdominios .abyaya.la siempre se generan automáticamente si no están presentes
|
||||||
|
- La zona DNS se detecta automáticamente considerando TLDs simples y compuestos
|
||||||
|
- Todos los dominios apuntan al mismo nodo en la VPN
|
||||||
|
- El primer dominio en la lista es considerado el principal para certificados SSL
|
||||||
|
- No se requiere ningún flag especial en la configuración
|
||||||
401
TESTING.md
Normal file
401
TESTING.md
Normal file
@ -0,0 +1,401 @@
|
|||||||
|
# Testing en Abyaya.la
|
||||||
|
|
||||||
|
Esta guía documenta las estrategias y herramientas de testing para infraestructura como código (IaC) basada en Ansible.
|
||||||
|
|
||||||
|
## Índice
|
||||||
|
|
||||||
|
1. [Testing de Ansible](#testing-de-ansible)
|
||||||
|
2. [Validación y Sintaxis](#validación-y-sintaxis)
|
||||||
|
3. [Testing de Infraestructura](#testing-de-infraestructura)
|
||||||
|
4. [CI/CD para Ansible](#cicd-para-ansible)
|
||||||
|
5. [Recursos Adicionales](#recursos-adicionales)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing de Ansible
|
||||||
|
|
||||||
|
### Molecule (Framework oficial - RECOMENDADO)
|
||||||
|
|
||||||
|
Molecule es el framework oficial para testing de roles de Ansible. Permite ejecutar tests unitarios, de integración y verificar idempotencia.
|
||||||
|
|
||||||
|
**Documentación Oficial:**
|
||||||
|
- Documentación principal: https://ansible.readthedocs.io/projects/molecule/
|
||||||
|
- Getting Started: https://ansible.readthedocs.io/projects/molecule/getting-started/
|
||||||
|
- Guía de escenarios: https://ansible.readthedocs.io/projects/molecule/configuration/
|
||||||
|
|
||||||
|
**Características:**
|
||||||
|
- Tests unitarios de roles individuales
|
||||||
|
- Tests de integración
|
||||||
|
- Tests de idempotencia (verificar que ejecutar dos veces da el mismo resultado)
|
||||||
|
- Soporte para Docker/Podman para simular entornos
|
||||||
|
|
||||||
|
**Instalación:**
|
||||||
|
```bash
|
||||||
|
pip install molecule molecule-docker
|
||||||
|
```
|
||||||
|
|
||||||
|
**Uso básico:**
|
||||||
|
```bash
|
||||||
|
cd roles/rap
|
||||||
|
molecule init scenario
|
||||||
|
molecule test
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ansible Lint
|
||||||
|
|
||||||
|
Herramienta de análisis estático que verifica mejores prácticas y patrones comunes en playbooks y roles de Ansible.
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- Documentación principal: https://ansible-lint.readthedocs.io/
|
||||||
|
- Catálogo de reglas: https://ansible-lint.readthedocs.io/rules/
|
||||||
|
|
||||||
|
**Instalación:**
|
||||||
|
```bash
|
||||||
|
pip install ansible-lint
|
||||||
|
```
|
||||||
|
|
||||||
|
**Uso:**
|
||||||
|
```bash
|
||||||
|
# Verificar un playbook específico
|
||||||
|
ansible-lint deploy.yml
|
||||||
|
|
||||||
|
# Verificar todos los archivos del proyecto
|
||||||
|
ansible-lint
|
||||||
|
|
||||||
|
# Verificar un rol específico
|
||||||
|
ansible-lint roles/proxy/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Testinfra
|
||||||
|
|
||||||
|
Framework de testing de infraestructura escrito en Python. Permite verificar el estado real de los servidores después del despliegue.
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- Documentación principal: https://testinfra.readthedocs.io/
|
||||||
|
- Ejemplos: https://testinfra.readthedocs.io/en/latest/examples.html
|
||||||
|
|
||||||
|
**Instalación:**
|
||||||
|
```bash
|
||||||
|
pip install testinfra
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ejemplo de test:**
|
||||||
|
```python
|
||||||
|
# tests/test_vpn.py
|
||||||
|
def test_tinc_is_running(host):
|
||||||
|
"""Verificar que el servicio Tinc está corriendo"""
|
||||||
|
tinc = host.service("tinc@comun")
|
||||||
|
assert tinc.is_running
|
||||||
|
assert tinc.is_enabled
|
||||||
|
|
||||||
|
def test_vpn_interface_exists(host):
|
||||||
|
"""Verificar que la interfaz VPN existe"""
|
||||||
|
assert host.interface("comun").exists
|
||||||
|
|
||||||
|
def test_vpn_ip_assigned(host):
|
||||||
|
"""Verificar que la IP VPN está asignada"""
|
||||||
|
comun = host.interface("comun")
|
||||||
|
assert comun.addresses[0].startswith("10.13.12.")
|
||||||
|
|
||||||
|
def test_nginx_is_running(host):
|
||||||
|
"""Verificar que Nginx está corriendo"""
|
||||||
|
nginx = host.service("nginx")
|
||||||
|
assert nginx.is_running
|
||||||
|
|
||||||
|
def test_port_443_listening(host):
|
||||||
|
"""Verificar que el puerto 443 está escuchando"""
|
||||||
|
assert host.socket("tcp://0.0.0.0:443").is_listening
|
||||||
|
```
|
||||||
|
|
||||||
|
**Ejecución:**
|
||||||
|
```bash
|
||||||
|
# Ejecutar tests contra un host
|
||||||
|
testinfra --hosts=ssh://root@hetzner tests/test_vpn.py
|
||||||
|
|
||||||
|
# Ejecutar con Ansible inventory
|
||||||
|
testinfra --ansible-inventory=hosts.production tests/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Validación y Sintaxis
|
||||||
|
|
||||||
|
### YAML Lint
|
||||||
|
|
||||||
|
Validador de sintaxis YAML con verificación de estilos y buenas prácticas.
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- Repositorio: https://github.com/adrienverge/yamllint
|
||||||
|
- Configuración: https://yamllint.readthedocs.io/en/stable/configuration.html
|
||||||
|
|
||||||
|
**Instalación:**
|
||||||
|
```bash
|
||||||
|
pip install yamllint
|
||||||
|
```
|
||||||
|
|
||||||
|
**Uso:**
|
||||||
|
```bash
|
||||||
|
# Validar archivos específicos
|
||||||
|
yamllint deploy.yml abyayala.yml
|
||||||
|
|
||||||
|
# Validar todos los YAML del proyecto
|
||||||
|
yamllint *.yml roles/*/tasks/*.yml roles/*/templates/*.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
**Configuración (.yamllint):**
|
||||||
|
```yaml
|
||||||
|
extends: default
|
||||||
|
|
||||||
|
rules:
|
||||||
|
line-length:
|
||||||
|
max: 120
|
||||||
|
indentation:
|
||||||
|
spaces: 2
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Ansible Syntax Check (Built-in)
|
||||||
|
|
||||||
|
Verificación de sintaxis integrada en Ansible.
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- Testing strategies: https://docs.ansible.com/ansible/latest/reference_appendices/test_strategies.html
|
||||||
|
- Syntax check: https://docs.ansible.com/ansible/latest/cli/ansible-playbook.html#cmdoption-ansible-playbook-syntax-check
|
||||||
|
|
||||||
|
**Uso:**
|
||||||
|
```bash
|
||||||
|
# Verificar sintaxis de un playbook
|
||||||
|
ansible-playbook deploy.yml --syntax-check
|
||||||
|
|
||||||
|
# Dry-run (simular sin ejecutar)
|
||||||
|
ansible-playbook deploy.yml --check
|
||||||
|
|
||||||
|
# Dry-run con diff de cambios
|
||||||
|
ansible-playbook deploy.yml --check --diff
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing de Infraestructura
|
||||||
|
|
||||||
|
### InSpec (Chef)
|
||||||
|
|
||||||
|
Framework de testing de infraestructura enterprise. Alternativa más robusta a Testinfra.
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- Documentación principal: https://docs.chef.io/inspec/
|
||||||
|
|
||||||
|
**Características:**
|
||||||
|
- Lenguaje DSL específico para infraestructura
|
||||||
|
- Compliance as Code
|
||||||
|
- Perfiles de seguridad predefinidos
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD para Ansible
|
||||||
|
|
||||||
|
### GitHub Actions
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- GitHub Actions para Ansible: https://github.com/marketplace/actions/run-ansible-playbook
|
||||||
|
|
||||||
|
**Ejemplo de workflow:**
|
||||||
|
```yaml
|
||||||
|
# .github/workflows/test.yml
|
||||||
|
name: Test Ansible Playbooks
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set up Python
|
||||||
|
uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.x'
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
pip install ansible ansible-lint yamllint molecule molecule-docker
|
||||||
|
|
||||||
|
- name: Run YAML Lint
|
||||||
|
run: yamllint .
|
||||||
|
|
||||||
|
- name: Run Ansible Lint
|
||||||
|
run: ansible-lint
|
||||||
|
|
||||||
|
- name: Syntax check
|
||||||
|
run: ansible-playbook deploy.yml --syntax-check
|
||||||
|
|
||||||
|
- name: Run Molecule tests
|
||||||
|
run: |
|
||||||
|
cd roles/rap
|
||||||
|
molecule test
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### GitLab CI
|
||||||
|
|
||||||
|
**Documentación:**
|
||||||
|
- GitLab CI para Ansible: https://docs.gitlab.com/ee/ci/examples/ansible/
|
||||||
|
|
||||||
|
**Ejemplo de pipeline:**
|
||||||
|
```yaml
|
||||||
|
# .gitlab-ci.yml
|
||||||
|
stages:
|
||||||
|
- lint
|
||||||
|
- test
|
||||||
|
|
||||||
|
lint:yaml:
|
||||||
|
stage: lint
|
||||||
|
image: python:3.9
|
||||||
|
script:
|
||||||
|
- pip install yamllint
|
||||||
|
- yamllint .
|
||||||
|
|
||||||
|
lint:ansible:
|
||||||
|
stage: lint
|
||||||
|
image: python:3.9
|
||||||
|
script:
|
||||||
|
- pip install ansible-lint
|
||||||
|
- ansible-lint
|
||||||
|
|
||||||
|
test:syntax:
|
||||||
|
stage: test
|
||||||
|
image: python:3.9
|
||||||
|
script:
|
||||||
|
- pip install ansible
|
||||||
|
- ansible-playbook deploy.yml --syntax-check
|
||||||
|
|
||||||
|
test:molecule:
|
||||||
|
stage: test
|
||||||
|
image: python:3.9
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
script:
|
||||||
|
- pip install molecule molecule-docker
|
||||||
|
- cd roles/rap && molecule test
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Recursos Adicionales
|
||||||
|
|
||||||
|
### Guías y Tutoriales
|
||||||
|
|
||||||
|
- **Testing Ansible Roles with Molecule**: https://www.digitalocean.com/community/tutorials/how-to-test-ansible-roles-with-molecule-on-ubuntu-20-04
|
||||||
|
- **Developing and Testing Ansible Roles with Molecule and Podman** (Serie de artículos): https://www.ansible.com/blog/developing-and-testing-ansible-roles-with-molecule-and-podman-part-1
|
||||||
|
|
||||||
|
### Best Practices
|
||||||
|
|
||||||
|
- **Ansible Best Practices**: https://docs.ansible.com/ansible/latest/tips_tricks/ansible_tips_tricks.html
|
||||||
|
- **Ansible Style Guide**: https://docs.ansible.com/ansible/latest/dev_guide/style_guide/
|
||||||
|
|
||||||
|
### Libros
|
||||||
|
|
||||||
|
- **Ansible for DevOps** (Jeff Geerling): https://www.ansiblefordevops.com/
|
||||||
|
- Capítulos relevantes sobre testing y CI/CD
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Estrategia de Testing Recomendada para Abyaya.la
|
||||||
|
|
||||||
|
### Fase 1: Inmediato (Quick Wins)
|
||||||
|
|
||||||
|
1. **Validación de sintaxis**
|
||||||
|
```bash
|
||||||
|
ansible-playbook deploy.yml --syntax-check
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **YAML Lint**
|
||||||
|
```bash
|
||||||
|
pip install yamllint
|
||||||
|
yamllint .
|
||||||
|
```
|
||||||
|
|
||||||
|
3. **Ansible Lint**
|
||||||
|
```bash
|
||||||
|
pip install ansible-lint
|
||||||
|
ansible-lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fase 2: Corto Plazo (1-2 semanas)
|
||||||
|
|
||||||
|
1. **Molecule para roles críticos**
|
||||||
|
- Empezar con `roles/rap` (VPN es crítico)
|
||||||
|
- Continuar con `roles/proxy` (punto de entrada público)
|
||||||
|
- Agregar `roles/certbot` (seguridad SSL)
|
||||||
|
|
||||||
|
2. **Pre-commit hooks**
|
||||||
|
```bash
|
||||||
|
pip install pre-commit
|
||||||
|
# Crear .pre-commit-config.yaml
|
||||||
|
pre-commit install
|
||||||
|
```
|
||||||
|
|
||||||
|
### Fase 3: Largo Plazo (1-2 meses)
|
||||||
|
|
||||||
|
1. **Testinfra para verificación post-despliegue**
|
||||||
|
- Tests de conectividad VPN
|
||||||
|
- Tests de disponibilidad de servicios
|
||||||
|
- Tests de configuración de firewall
|
||||||
|
- Tests de certificados SSL
|
||||||
|
|
||||||
|
2. **CI/CD Pipeline**
|
||||||
|
- GitHub Actions o GitLab CI
|
||||||
|
- Tests automáticos en cada push
|
||||||
|
- Tests de integración en staging
|
||||||
|
|
||||||
|
3. **Tests de integración end-to-end**
|
||||||
|
- Despliegue completo en entorno de prueba
|
||||||
|
- Verificación de flujo completo: VPN → Proxy → Servicio
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Comandos Útiles de Testing
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Testing rápido de sintaxis
|
||||||
|
ansible-playbook deploy.yml --syntax-check
|
||||||
|
|
||||||
|
# Dry-run (ver qué cambiaría sin aplicar)
|
||||||
|
ansible-playbook deploy.yml --check --diff -e "host=hetzner alt=abyayala"
|
||||||
|
|
||||||
|
# Verificar sintaxis YAML
|
||||||
|
yamllint *.yml roles/
|
||||||
|
|
||||||
|
# Análisis estático con ansible-lint
|
||||||
|
ansible-lint deploy.yml
|
||||||
|
|
||||||
|
# Test de un rol específico con Molecule
|
||||||
|
cd roles/rap && molecule test
|
||||||
|
|
||||||
|
# Verificación post-despliegue con Testinfra
|
||||||
|
testinfra --hosts=ssh://root@hetzner tests/
|
||||||
|
|
||||||
|
# Ver qué tareas se ejecutarían
|
||||||
|
ansible-playbook deploy.yml --list-tasks -e "host=hetzner alt=abyayala"
|
||||||
|
|
||||||
|
# Ejecutar solo con tags específicos en check mode
|
||||||
|
ansible-playbook deploy.yml --check --tags=vpn -e "host=hetzner alt=abyayala"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contribuir
|
||||||
|
|
||||||
|
Al agregar nuevos roles o modificar existentes:
|
||||||
|
|
||||||
|
1. Ejecutar ansible-lint antes de commit
|
||||||
|
2. Verificar sintaxis con --syntax-check
|
||||||
|
3. Si es un rol crítico, agregar tests de Molecule
|
||||||
|
4. Documentar casos de prueba en este archivo
|
||||||
@ -204,11 +204,11 @@ matrix:
|
|||||||
|
|
||||||
- service_name: kipu
|
- service_name: kipu
|
||||||
domains:
|
domains:
|
||||||
- kipu.abyaya.la
|
- kipu.latina.red
|
||||||
nodo: kipu.comun
|
nodo: kipu.comun
|
||||||
|
ssl: no
|
||||||
ports:
|
ports:
|
||||||
- 223
|
- 223
|
||||||
force_https: yes
|
|
||||||
|
|
||||||
- service_name: carabobolibre
|
- service_name: carabobolibre
|
||||||
domains:
|
domains:
|
||||||
|
|||||||
@ -30,14 +30,13 @@
|
|||||||
env: yes
|
env: yes
|
||||||
value: /bin/bash
|
value: /bin/bash
|
||||||
|
|
||||||
# TODO
|
- name: automatic letsencrypt certs renewal
|
||||||
# - name: automatic letsencrypt certs renewal
|
cron:
|
||||||
# cron:
|
name: certificate renewal
|
||||||
# name: certificate renewal
|
day: 4,18
|
||||||
# day: 4,18
|
hour: 0
|
||||||
# hour: 0
|
minute: 0
|
||||||
# minute: 0
|
job: "docker run --rm -v {{ althost }}_certs_data:/etc/letsencrypt --network host {{ CERTBOT_image }} renew --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 >> /var/log/renewal.log 2>&1"
|
||||||
# job: "docker run --rm -v {{ althost }}_certs_data:/etc/letsencrypt -v {{ althost }}_certs_www:/var/www/letsencrypt certbot/certbot renew >> /var/log/renewal.log 2>&1"
|
|
||||||
|
|
||||||
- name: proxy update, after certs renewal
|
- name: proxy update, after certs renewal
|
||||||
cron:
|
cron:
|
||||||
|
|||||||
@ -1,14 +1,19 @@
|
|||||||
{% for dns_server in dns_servers %}
|
{% for dns_server in dns_servers %}
|
||||||
server {{ dns_server }}
|
server {{ dns_server }}
|
||||||
zone abyaya.la.
|
zone {{ zone }}
|
||||||
origin abyaya.la.
|
origin {{ zone }}
|
||||||
ttl 60
|
ttl 60
|
||||||
del {{ vho }} a
|
del {{ hostname }} a
|
||||||
del {{ vho }} ns
|
del {{ hostname }} ns
|
||||||
add {{ vho }} a {{ host_ip }}
|
add {{ hostname }} a {{ host_ip }}
|
||||||
add *.{{ vho }} a {{ host_ip }}
|
{% if is_abyayala_subdomain %}
|
||||||
add _acme-challenge.{{ vho }} a {{ host_ip }}
|
add *.{{ hostname }} a {{ host_ip }}
|
||||||
add _acme-challenge.{{ vho }} ns _acme-challenge
|
{% else %}
|
||||||
|
add {{ domain }} a {{ host_ip }}
|
||||||
|
add *.{{ domain }} a {{ host_ip }}
|
||||||
|
{% endif %}
|
||||||
|
add _acme-challenge.{{ hostname }} a {{ host_ip }}
|
||||||
|
add _acme-challenge.{{ hostname }} ns _acme-challenge
|
||||||
{% if vhost.dns_extras is defined %}
|
{% if vhost.dns_extras is defined %}
|
||||||
{% for dns_extra in vhost.dns_extras %}
|
{% for dns_extra in vhost.dns_extras %}
|
||||||
{{ dns_extra }}
|
{{ dns_extra }}
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
- set_fact:
|
- name: process each domain in the list
|
||||||
vho: "{{ vhost.domains[0] | regex_replace('([a-z0-9]+)\\.abyaya\\.la', '\\1')}}"
|
include_tasks: update_domain.yml
|
||||||
|
with_items: "{{ vhost.domains }}"
|
||||||
- name: knsupdate
|
loop_control:
|
||||||
shell: knsupdate
|
loop_var: domain
|
||||||
args:
|
|
||||||
stdin: "{{ lookup('template', 'templates/commands.j2') }}"
|
|
||||||
|
|||||||
36
roles/knsupdate/tasks/update_domain.yml
Normal file
36
roles/knsupdate/tasks/update_domain.yml
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
- set_fact:
|
||||||
|
is_abyayala_subdomain: "{{ domain.endswith('.abyaya.la') }}"
|
||||||
|
|
||||||
|
- name: extract zone and hostname for abyaya.la subdomains
|
||||||
|
set_fact:
|
||||||
|
zone: "abyaya.la."
|
||||||
|
hostname: "{{ domain | regex_replace('([a-z0-9-]+)\\.abyaya\\.la', '\\1') }}"
|
||||||
|
when: is_abyayala_subdomain
|
||||||
|
|
||||||
|
- name: split domain into parts
|
||||||
|
set_fact:
|
||||||
|
domain_parts: "{{ domain.split('.') }}"
|
||||||
|
when: not is_abyayala_subdomain
|
||||||
|
|
||||||
|
- name: detect if domain uses compound TLD
|
||||||
|
set_fact:
|
||||||
|
domain_suffix_2: "{{ domain_parts[-2:] | join('.') }}"
|
||||||
|
uses_compound_tld: "{{ domain_parts[-2:] | join('.') in compound_tlds }}"
|
||||||
|
when: not is_abyayala_subdomain
|
||||||
|
|
||||||
|
- name: extract zone and hostname for FQDN with compound TLD
|
||||||
|
set_fact:
|
||||||
|
zone: "{{ domain_parts[-3:] | join('.') }}."
|
||||||
|
hostname: "{{ domain_parts[:-3] | join('.') if domain_parts | length > 3 else '@' }}"
|
||||||
|
when: not is_abyayala_subdomain and uses_compound_tld
|
||||||
|
|
||||||
|
- name: extract zone and hostname for FQDN with simple TLD
|
||||||
|
set_fact:
|
||||||
|
zone: "{{ domain_parts[-2:] | join('.') }}."
|
||||||
|
hostname: "{{ domain_parts[:-2] | join('.') if domain_parts | length > 2 else '@' }}"
|
||||||
|
when: not is_abyayala_subdomain and not uses_compound_tld
|
||||||
|
|
||||||
|
- name: knsupdate for this domain
|
||||||
|
shell: knsupdate
|
||||||
|
args:
|
||||||
|
stdin: "{{ lookup('template', 'templates/commands.j2') }}"
|
||||||
@ -3,3 +3,18 @@ dns_servers:
|
|||||||
- "athshe.sutty.nl"
|
- "athshe.sutty.nl"
|
||||||
- "gethen.sutty.nl"
|
- "gethen.sutty.nl"
|
||||||
- "ganam.sutty.nl"
|
- "ganam.sutty.nl"
|
||||||
|
|
||||||
|
compound_tlds:
|
||||||
|
- com.ar
|
||||||
|
- com.mx
|
||||||
|
- co.uk
|
||||||
|
- com.br
|
||||||
|
- gov.ar
|
||||||
|
- org.ar
|
||||||
|
- gob.ar
|
||||||
|
- net.ar
|
||||||
|
- mil.ar
|
||||||
|
- edu.ar
|
||||||
|
- co.nz
|
||||||
|
- net.nz
|
||||||
|
- org.nz
|
||||||
|
|||||||
@ -45,6 +45,21 @@
|
|||||||
loop_control:
|
loop_control:
|
||||||
loop_var: domino
|
loop_var: domino
|
||||||
|
|
||||||
|
- name: add default abyaya.la subdomain if not present
|
||||||
|
set_fact:
|
||||||
|
matrix_loop_with_defaults: "{{ matrix_loop_with_defaults | default([]) | union([ item_with_default ]) }}"
|
||||||
|
vars:
|
||||||
|
has_abyayala_domain: "{{ item.domains | select('match', '.*\\.abyaya\\.la$') | list | length > 0 }}"
|
||||||
|
default_domain: "{{ item.service_name }}.abyaya.la"
|
||||||
|
domains_with_default: "{{ item.domains + [default_domain] if not has_abyayala_domain else item.domains }}"
|
||||||
|
item_with_default: "{{ item | combine({'domains': domains_with_default}) }}"
|
||||||
|
with_items: "{{ matrix_loop | default([]) }}"
|
||||||
|
|
||||||
|
- name: update matrix_loop with defaults
|
||||||
|
set_fact:
|
||||||
|
matrix_loop: "{{ matrix_loop_with_defaults }}"
|
||||||
|
when: matrix_loop_with_defaults is defined
|
||||||
|
|
||||||
- name: certificates loop
|
- name: certificates loop
|
||||||
include_tasks: ../../certbot/tasks/certbot.yml
|
include_tasks: ../../certbot/tasks/certbot.yml
|
||||||
with_items: "{{ matrix_loop | default([]) }}"
|
with_items: "{{ matrix_loop | default([]) }}"
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
client_max_body_size 1G;
|
client_max_body_size 1G;
|
||||||
proxy_ssl_verify off;
|
proxy_ssl_verify off;
|
||||||
proxy_ssl_server_name on;
|
proxy_ssl_server_name on;
|
||||||
proxy_ssl_name $ssl_server_name;
|
proxy_ssl_name $host;
|
||||||
|
|
||||||
proxy_pass https://$comun_{{ vhost.nodo | replace(".", "") }};
|
proxy_pass https://$comun_{{ vhost.nodo | replace(".", "") }};
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ upstream ssh_{{ vhost.nodo | replace(".", "") }} {
|
|||||||
server {
|
server {
|
||||||
listen {{ vhost.ports[0] }};
|
listen {{ vhost.ports[0] }};
|
||||||
|
|
||||||
server_name .{{ vhost.domains | join(' .') }};
|
server_name {{ vhost.service_name }}.abyaya.la;
|
||||||
|
|
||||||
proxy_pass ssh_{{ vhost.nodo | replace(".", "") }};
|
proxy_pass ssh_{{ vhost.nodo | replace(".", "") }};
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user