Compare commits
261 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 872fdd6d43 | |||
| bb069debaf | |||
| 729f931c39 | |||
| 45fe05844e | |||
| f6f5c90d34 | |||
| 6d442bbaa6 | |||
| 28c80118f7 | |||
| 3467f774df | |||
| 80ed2dea5f | |||
| df8b23525e | |||
| 5e45fed446 | |||
| b201c758b7 | |||
| 380a588f0c | |||
| 5ab33a419a | |||
| 02bfbfc2c6 | |||
| fae291cdc9 | |||
| 73a562b449 | |||
| 41b8ee5647 | |||
| 0487ffde12 | |||
| a6c1bcaeff | |||
| 090c397e24 | |||
| 89866df0bf | |||
| 216c81df39 | |||
| a8b3a63807 | |||
| 02b135f486 | |||
| 7e12b7b20a | |||
| 0a99c7f2d1 | |||
| fc76a7fb91 | |||
| 7d5044f1f1 | |||
| f1d37f21f7 | |||
| 66e3c6fcaf | |||
| 1fc58432dd | |||
| d683f8bcd2 | |||
| 5c19e789c4 | |||
| 838cc5833c | |||
| 135edfe527 | |||
| f72983049d | |||
| be5f8fc5e7 | |||
| acdf35e5a7 | |||
| ee5513587e | |||
| 4ad59e5068 | |||
| e17f872aba | |||
| e5a756525b | |||
| c085c99382 | |||
| 890c496b4e | |||
| c86059e319 | |||
| 07dfd834ca | |||
| 554c51e94c | |||
| 7673ccd160 | |||
| ad118402f7 | |||
| 54b24af0b5 | |||
| 08a3e563d4 | |||
| b31a9abcad | |||
| 11ec613ae9 | |||
| 3fb144d02f | |||
| e5dff263d1 | |||
| 06654b9e41 | |||
| 552911286d | |||
| d94cfd89d0 | |||
| 8cf385b5a5 | |||
| 5f914e071a | |||
| 9296b21f91 | |||
| 1a00b8a60c | |||
| 127504cb62 | |||
| 68ca0b5b61 | |||
| f91a3360af | |||
| 76dea140c7 | |||
| 1b69f0d13f | |||
| 5e849ecee2 | |||
| a973291506 | |||
| 43ea3c9a58 | |||
| 4bec6e7fae | |||
| f180972d15 | |||
| ac8dd13d64 | |||
| 0ee1665acb | |||
| 08a9a38fa5 | |||
| 51bd9c9935 | |||
| 4f18275831 | |||
| 82f6c62803 | |||
| dcc6fe2f48 | |||
| 7b16934a17 | |||
| 0e2d64d39e | |||
| b750293414 | |||
| 1ab755fb10 | |||
| 7e04c03370 | |||
| cdadee266e | |||
| 733c9930e2 | |||
| 71e6eb9429 | |||
| 6ed17848cd | |||
| fd57ecd546 | |||
| dfbd04480c | |||
| 7cdf7bb885 | |||
| ecab24c02f | |||
| 180a7f2ab6 | |||
| edb3a22ec0 | |||
| 6253223fdf | |||
| 06a513799e | |||
| 7f38023c7d | |||
| f106838dc1 | |||
| a3863b9465 | |||
| f2668d63ef | |||
| 29182e8eaf | |||
| fa59614c2a | |||
| 94e71c7516 | |||
| 65090c8c2c | |||
| b7139145dc | |||
| 8e17401f12 | |||
| 206f8adf60 | |||
| 1f73abb74f | |||
| a27a86ce6b | |||
| 2aa6ddcc4d | |||
| 41b30d3a8d | |||
| 4361acfde1 | |||
| 7b5669eae8 | |||
| d2569a7e29 | |||
| 47759f5464 | |||
| 3c690dd1f5 | |||
| 3c30dc976d | |||
| b369e9824b | |||
| a75f06474c | |||
| e1b4fb8ba1 | |||
| f0f0c688c9 | |||
| 5aea3651c2 | |||
| bc44c5074e | |||
| b36346e6d3 | |||
| 0d48f04f15 | |||
| 63a21e5145 | |||
| 957a923a7c | |||
| bd07232180 | |||
| f5cd3f2e2e | |||
| d0beebfe12 | |||
| 299f970b95 | |||
| a581e89f22 | |||
| 23ac2f0b64 | |||
| 144f9c9d85 | |||
| 121c07f766 | |||
| 7bc06903eb | |||
| ed1edd6269 | |||
| 1910b37547 | |||
| 9c38fea199 | |||
| 9455e50af9 | |||
| 645630e9c8 | |||
| d4215f7e3e | |||
| 4a886418e8 | |||
| 741a026408 | |||
| d8f0b5fb66 | |||
| 31fb3b7526 | |||
| 1bf91dfa24 | |||
| e06d6a4414 | |||
| d4384187d9 | |||
| 28ad0386be | |||
| e703628d8d | |||
| 04bcec3352 | |||
| d8600ee1cb | |||
| a63bd72256 | |||
| 8b3a0babf6 | |||
| 38c8db9f53 | |||
| 860487aa9d | |||
| 0b22138ab0 | |||
| 08cb31c8c9 | |||
| 433fda716a | |||
| 61deebaf25 | |||
| 94bacbf352 | |||
| 70dc16c042 | |||
| 0b4c0534f6 | |||
| 75b2b5d269 | |||
| c0b5978ef5 | |||
| f1c5ee7654 | |||
| 4a98e1e92f | |||
| 1548d9f7c2 | |||
| c3247017f0 | |||
| a700bc0b88 | |||
| a4b66d5c49 | |||
| 539c1e47f3 | |||
| 789c0dbfcc | |||
| b36f2e3910 | |||
| c08b998d21 | |||
| fdff1e3496 | |||
| d6edca2ac6 | |||
| bd3117579a | |||
| 008a8b97ae | |||
| 9820cf1db8 | |||
| a67caf2f57 | |||
| c49a2b73cc | |||
| fc46e78fb3 | |||
| aa36848906 | |||
| 35bbc39a3d | |||
| 5f031b7688 | |||
| ee3deadaf8 | |||
| 219ede45ec | |||
| 780a848f25 | |||
| 07f3164720 | |||
| c075375ae8 | |||
| c4b114ebaa | |||
| 053ca48945 | |||
| 85f64fd7f0 | |||
| ed6691c575 | |||
| 868393a045 | |||
| 7e4eb3f21f | |||
| 1a15ebe1e8 | |||
| 4753b8a270 | |||
| 0a378d665c | |||
| ae95c2dd0e | |||
| 4bb2c14c83 | |||
| 52e7da204d | |||
| 87b77339c5 | |||
| 79f052d2a7 | |||
| 1630c554ff | |||
| f5252a4c18 | |||
| 5e61a46c4b | |||
| 9c1bae22d8 | |||
| b53f1686bf | |||
| 34672f27e6 | |||
| 6504043f4e | |||
| 142727cdcd | |||
| d7306ec168 | |||
| 078a55de7c | |||
| a91e793b28 | |||
| 71984956d3 | |||
| 81b863a359 | |||
| 9b334741c9 | |||
| b78859b71b | |||
| a2e5550967 | |||
| ae29a088af | |||
| 1229ed7276 | |||
| 7b783f861e | |||
| 8d9079ca50 | |||
| 20e13644f9 | |||
| 9aeed678e3 | |||
| 92bc0fe191 | |||
| d664a15af9 | |||
| cf63a24756 | |||
| 62b191d039 | |||
| 836a58f37e | |||
| 972321637b | |||
| f450087ab0 | |||
| d6f4a3fcd7 | |||
| 3544b27e4a | |||
| ca75a34eeb | |||
| f61f22377c | |||
| 487945bf80 | |||
| 87c922250b | |||
| 20ce4fb6f3 | |||
| b1574f1967 | |||
| eec4aafd72 | |||
| 4d4e855fcc | |||
| 1d85e24f63 | |||
| f0e4dbb7e0 | |||
| 3a2a235199 | |||
| 5546a6a8b9 | |||
| f9746c1ff2 | |||
| 6f8146aa16 | |||
| a31c155609 | |||
| da3c25fe58 | |||
| 83bcadaab0 | |||
| 60bdce36aa | |||
| 1f103c16f0 | |||
| 98ab948b9d | |||
| c42b1b773a | |||
| 37f1866300 | |||
| 3adee1fd7c |
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "roles/rap/code/rap"]
|
||||
path = roles/rap/code/rap
|
||||
url = https://0xacab.org/pip/rap.git
|
||||
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
|
||||
99
README-root-domain.md
Normal file
99
README-root-domain.md
Normal file
@ -0,0 +1,99 @@
|
||||
# Plan: Añadir Soporte para Dominio Principal www.abyaya.la
|
||||
|
||||
## Objetivo
|
||||
Habilitar que el dominio raíz `abyaya.la` y `www.abyaya.la` apunten al servidor `sutty.comun`, mientras se mantienen funcionando todos los subdominios existentes (ej: `sutty.abyaya.la`, `marmite.abyaya.la`).
|
||||
|
||||
## Estrategia de Desarrollo
|
||||
|
||||
### Rama Tópica
|
||||
Los cambios se implementarán en esta rama tópica:
|
||||
- **Nombre de rama**: `root-domain`
|
||||
- **Bifurcada desde**: `master`
|
||||
|
||||
## Contexto Técnico
|
||||
|
||||
### Arquitectura Actual
|
||||
- **Certificados**: Cada servicio en `abyayala.yml` con `domains` + `nodo` genera un certificado con certbot: `-d DOMAIN -d *.DOMAIN`
|
||||
- **Patron actual**: Todos los dominios siguen el patrón `subdomain.abyaya.la` (ej: `sutty.abyaya.la`)
|
||||
|
||||
### Decisión de Diseño
|
||||
Crear un **servicio separado** para el dominio raíz con un nuevo flag `root: yes` que indica a certbot que NO solicite el certificado wildcard. Esto mantiene limpia la separación de responsabilidades:
|
||||
- Servicio `sutty`: maneja `sutty.abyaya.la` y `*.sutty.abyaya.la`
|
||||
- Servicio `abyaya_root`: maneja únicamente `abyaya.la` y `www.abyaya.la` (sin wildcard)
|
||||
|
||||
## Cambios Implementados
|
||||
|
||||
### 1. `roles/certbot/tasks/certbot.yml`
|
||||
- Lee el flag `root` del servicio y lo mapea a variable `is_root_domain`
|
||||
- Dividido el bloque de certificados en dos tareas condicionales:
|
||||
- Modo estándar (con wildcard): para subdominios (`when: not is_root_domain`)
|
||||
- Modo sin wildcard: para dominios raíz (`when: is_root_domain`)
|
||||
|
||||
### 2. `roles/proxy/templates/vhost.conf`
|
||||
- Agregado condicional para manejar flag `root`
|
||||
- Cuando `root: yes`: genera `server_name` sin punto prefijo (exacto)
|
||||
- Cuando `root: no` (default): genera `server_name .domain` (con wildcard)
|
||||
|
||||
### 3. `abyayala.yml`
|
||||
- Agregado servicio `abyaya_root` con:
|
||||
- Dominios: `abyaya.la` y `www.abyaya.la`
|
||||
- Enrutamiento a: `sutty.comun`
|
||||
- Flag: `root: yes`
|
||||
- HTTPS forzado y compresión habilitada
|
||||
|
||||
## Comandos de Despliegue
|
||||
|
||||
### Despliegue completo
|
||||
```bash
|
||||
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner"
|
||||
```
|
||||
|
||||
### Despliegue solo del servicio nuevo (para testing)
|
||||
```bash
|
||||
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner service=abyaya_root"
|
||||
```
|
||||
|
||||
## Verificación Post-Despliegue
|
||||
|
||||
### 1. Verificar certificado
|
||||
```bash
|
||||
ssh root@hetzner
|
||||
ls -la /var/lib/docker/volumes/abyayala_certs_data/_data/live/abyaya.la/
|
||||
docker run --rm -v abyayala_certs_data:/etc/letsencrypt certbot/certbot certificates | grep abyaya.la
|
||||
```
|
||||
|
||||
Debe contener: `abyaya.la`, `www.abyaya.la` (SIN `*.abyaya.la`)
|
||||
|
||||
### 2. Verificar nginx
|
||||
```bash
|
||||
cat /opt/abyayala/proxy/vhosts/abyaya.la.conf
|
||||
docker exec abyayala_proxy nginx -t
|
||||
```
|
||||
|
||||
### 3. Verificar enrutamiento
|
||||
```bash
|
||||
curl -I http://abyaya.la # Debe redirigir a HTTPS
|
||||
curl -I https://abyaya.la # Debe devolver 200 OK
|
||||
curl -I https://www.abyaya.la # Debe devolver 200 OK
|
||||
```
|
||||
|
||||
### 4. Verificar subdominios siguen funcionando
|
||||
```bash
|
||||
curl -I https://sutty.abyaya.la
|
||||
curl -I https://marmite.abyaya.la
|
||||
```
|
||||
|
||||
## Requisitos DNS
|
||||
|
||||
Antes del despliegue, configurar:
|
||||
```
|
||||
abyaya.la A <IP-del-proxy>
|
||||
www.abyaya.la A <IP-del-proxy>
|
||||
```
|
||||
|
||||
## Extensibilidad Futura
|
||||
|
||||
Este patrón `root: yes` puede reutilizarse para otros dominios raíz:
|
||||
1. Agregar entrada en `abyayala.yml` con `root: yes`
|
||||
2. Desplegar con ansible-playbook
|
||||
3. Configurar DNS
|
||||
216
README.md
216
README.md
@ -1,17 +1,217 @@
|
||||
## DEPLOY
|
||||
# ABYAYA.LA #
|
||||
|
||||
Este sistema automatiza el despliegue de la red Abyaya.la, mediante [Ansible](https://docs.ansible.com/), un software de automatización de código abierto, que permite la gestión de configuraciones, el despliegue de aplicaciones y la orquestación de tareas.
|
||||
|
||||
- Sintaxis basada en YAML, que significa "Yet Another Markup Language". Un formato de serialización de datos legible por humanes.
|
||||
- Se definien playbooks, que son scripts que automatizan secuencias de tareas y configuraciones.
|
||||
- Opera sin necesidad de instalar agentes en los nodos gestionados, ya que se comunica a través de SSH.
|
||||
|
||||
|
||||
### abyayala.yml
|
||||
Así, gestionamos la __infraestructura como código__, en un único archivo de matriz __abyayala.yml__
|
||||
|
||||
Este describe los componentes a desplegar para qu esta red funcione. Podríamos dividirlos en dos grandes componentes:
|
||||
|
||||
### La RAP
|
||||
|
||||
La _Red Autónoma Pirata_ es la __VPN__ que nos permite acceder a nuestros servidores, sin importar el lugar donde estén conectados.
|
||||
|
||||
|
||||
|Características||
|
||||
|-------------------------------|--------------------------------------------|
|
||||
| Red | `10.13.12.1/24` |
|
||||
| DHCP | Automático |
|
||||
| Resolución de nombres | Hostname (ej. `ping ka.comun`) |
|
||||
|
||||
### El PROXY
|
||||
Es un servidor con una IP pública, a la que apuntamos el dominio __abyaya.la__.
|
||||
|
||||
Hace de **proxy reverso** para los demás servidores, ruteando el tráfico a cada servidor a través de la RAP.
|
||||
|
||||
|Características||
|
||||
|-------------------------------|--------------------------------------------|
|
||||
| Subdominios para los servidores|`nuevo.abyaya.la` |
|
||||
| Servicios en los sub-sub-dominios| Ej: `https://sitio.nuevo.abyaya.la` |
|
||||
| Certificados Wildcard| `*.nuevo.abyaya.la` |
|
||||
|
||||
----
|
||||
|
||||
# Cómo funciona
|
||||
|
||||
La idea es reducir todo a un solo comando único *deploy.yml", el cual leerá la matriz **abyayala.yml** para desplegar o actualizar, tanto a la VPN como al Proxy.
|
||||
|
||||
# Componentes Principales
|
||||
|
||||
## Estructura de Archivos
|
||||
- deploy.yml: Playbook principal, el "comando único"
|
||||
- abyayala.yml: Configuración principal (YAML) en donde se define declarativamente la infraestructura de ambos componentes (VPN y Proxy)
|
||||
- tasks/: Playbooks adicionales para tareas específicas
|
||||
- roles/: Cada rol configura un servicio del sistema
|
||||
|
||||
# ALTA DE NODOS "EN 2 PASOS"
|
||||
|
||||
Esta se hace en dos partes, pues hay que configurarlo primero en el nodo de destino y después en el servidor del proxy.
|
||||
|
||||
## 1.1 - Autorizar nuevo nodo en la RAP...
|
||||
|
||||
También tenemos que avisar a la RAP, la cual se define en el archivo abyayala.yml, en el **server_name: vpn**
|
||||
|
||||
En la lista de **nodos** mantenemos los nodos autorizados para conectarse a la RAP
|
||||
```
|
||||
- service_name: vpn
|
||||
roles:
|
||||
- rap
|
||||
nodos:
|
||||
- marmite
|
||||
- ka
|
||||
```
|
||||
Lo agregamos a la lista y ejecutamos el comando **deploy.yml** para autorizarlos.
|
||||
|
||||
Le especificaremos parámetros con **- e**:
|
||||
```
|
||||
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner"
|
||||
```
|
||||
Así estamos desplegando entonces los servicios definidos en el archivo **abyayala.yml**, a nuestro servidor en **hetzner**.
|
||||
|
||||
### Parámetros de deploy.yml
|
||||
|
||||
Los parámetros obligatorios son:
|
||||
- **alt**: nombre de nuestro servidor autónomo, en este caso siempre es 'abyayala'
|
||||
- **host**: nombre del servidor de destino en el archivo de inventario hosts.production
|
||||
|
||||
Los parámetros opcionales pueden ser:
|
||||
- **service**: limita al despliegue a un servicio específico, en lugar de actualizarlos todos
|
||||
|
||||
Siguiendo con el ejemplo anterior, utilizaremos el parametro **service** para ejecutar solamente la vpn.
|
||||
|
||||
```
|
||||
ansible-playbook deploy.yml -e "host=abyayala alt=abyayala"
|
||||
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner service=vpn"
|
||||
```
|
||||
|
||||
# opcional: service define despliegue de servicio especifico
|
||||
# service undefined: ejecuta todos los roles
|
||||
## 1.2 - Instalar la RAP en el nodo
|
||||
|
||||
# -e "service=defined" si es master, ejecuta su rol | si es worker, tambien pero en el otro host
|
||||
# --skip-tags=installation saltea una parte, marcada por un tag. por ejemplo, la instalacion. o --skip-tags=installation,keys
|
||||
Para desplegar la RAP en nuestro nodo destino, utilizamos otro playbook, el script **tasks/rap.yml** especificando sus parámetros con **-e
|
||||
"..."**
|
||||
|
||||
```
|
||||
ansible-playbook --become tasks/rap.yml -e "nodo=nuevo host=miservidora"
|
||||
```
|
||||
|
||||
En donde:
|
||||
- **host**: es el nodo nuevo a configurar, según su definición en el inventario de ansible
|
||||
- **nodo**: es el nombre que le daremos, el cual debe coincidir con el que desplegamos en el proxy más adelante
|
||||
|
||||
|
||||
## 2 - HABILITAR ACCESO HTTPS AL NUEVO NODO
|
||||
|
||||
Por otro lado, hay que actualizar al **Proxy** para que el nuevo nodo sea accesible por HTTPS, en un subdominio público.
|
||||
|
||||
Vemos que cada nodo debe tener una entrada en el archivo **abyayala.yml**, en donde se asocia su **subdominio público** con su **nodo en la RAP**, de esta forma:
|
||||
```
|
||||
- service_name: nuevo
|
||||
domains:
|
||||
- nuevo.abyaya.la
|
||||
nodo: nuevo.comun
|
||||
ssl: yes
|
||||
```
|
||||
Donde
|
||||
- **service_name**: es un nombre arbitrario
|
||||
- **domains**: la unica entrada de domains es el subdominio principal
|
||||
- **nodo**: es el hostname del nodo en la RAP
|
||||
- **ssl**: habilita la conexión SSL/TLS
|
||||
|
||||
### 2.2 DEPLOY.YML
|
||||
|
||||
Luego de agregar nuestro nuevo nodo, volvemos entonces a ejecutar el comando **deploy.yml** para habilitar el acceso HTTPS a éste, y publicar ese subdominio.
|
||||
|
||||
En esta ocasión, lo acotaremos a actualizar la configuración de solamente **un nodo**, especificándolo con el parámetro **service**:
|
||||
```
|
||||
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner service=nuevo"
|
||||
|
||||
```
|
||||
|
||||
### DEPLOY LOCAL
|
||||
### TAGS
|
||||
|
||||
También hay **tags** que marcan secciones del código.
|
||||
|
||||
Por ejemplo se puede acotar aún más, saltándose todas las tareas de instalación con **--skip-tags**
|
||||
|
||||
```
|
||||
ansible-playbook --become deploy.yml -e "host=localhost alt=abyayala" -i hosts.local
|
||||
ansible-playbook deploy.yml -e "alt=abyayala host=hetzner service=nuevo" --skip-tags=installation
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
# INSTALACIÓN
|
||||
|
||||
## Instalar Ansible
|
||||
```
|
||||
# Si tienen Python
|
||||
pip install ansible
|
||||
|
||||
# Para sistemas basados en Debian/Ubuntu
|
||||
sudo apt-get install ansible
|
||||
|
||||
# Para sistemas RHEL/CentOS
|
||||
sudo yum install ansible
|
||||
```
|
||||
## PREPARAR SSH
|
||||
|
||||
También deben tener sus llaves públicas de **SSH** añadidas tanto al nodo como al servidor de destino.
|
||||
### Generar clave SSH (si no existe)
|
||||
```
|
||||
ssh-keygen -t ed25519
|
||||
```
|
||||
### Copiar clave pública al nodo de destino
|
||||
```
|
||||
ssh-copy-id root@nuevo.comun
|
||||
```
|
||||
|
||||
### ALTA DE USUARIXS EN EL PROXY
|
||||
|
||||
Para conectarse al proxy deben agregar sus llaves como dice a continuación:
|
||||
|
||||
* Copiar la(s) llave(s) pública(s) de cada wayki en `tasks/files/ssh/WAYKI.pub`.
|
||||
* Agregarle en `group_vars/all/ssh_users.yml` (copiando la sintaxis)
|
||||
* Correr `ansible-playbook tasks/users.yml -e "host=hetzner"`
|
||||
|
||||
---
|
||||
|
||||
# TESTING
|
||||
|
||||
Si todo anda bien, podemos probarlo así:
|
||||
|
||||
## Conexión VPN
|
||||
Como resultado del deploy de la primera parte (RAP), la máquina **nodo** debe conectarse a la red comun en IPv4 y en el rango 10.13.12.1/24 y poder pingear al server, que es 10.13.12.1
|
||||
|
||||
El proxy a su vez puede pingear a cada nodo por su nombre de host en la red comun. por ej.
|
||||
```
|
||||
root@proxy-reverso-escuela-comun:~# ping ka.comun
|
||||
PING ka.comun (10.13.12.129) 56(84) bytes of data.
|
||||
64 bytes from ka.comun (10.13.12.129): icmp_seq=1 ttl=64 time=169 ms
|
||||
```
|
||||
|
||||
## Acceso HTTPS
|
||||
|
||||
Por otra parte, como resultado del despliegue de la segunda parte (PROXY), el **nodo** debe ser accesible en el subdominio **nuevo. abyaya.la**
|
||||
|
||||
Los servicios de cada nodo son accesibles a través de SSL en **sub-sub-** dominios.
|
||||
|
||||
Por ej. **https://sitio.nuevo.abyaya.la** o **https://nube.nuevo.abyaya.la**
|
||||
|
||||
|
||||
---
|
||||
## DEPLOY LOCAL
|
||||
|
||||
En este ejemplo, instalaremos todo en nuestro localhost para desarrollo, como si fuera un nodo del proxy.
|
||||
```
|
||||
ansible-playbook --become tasks/rap.yml -e "host=localhost nodo=nombrelo" -i hosts.local
|
||||
```
|
||||
Esto también es útil para instalar Ansible en nuestra terminal, junto con sus dependencias (Módulos para docker, etc.)
|
||||
|
||||
#### SSH PARA DESARROLLO
|
||||
Para autoconectarse por SSH hay que autorizarse a sí mismx:
|
||||
```
|
||||
# Habilitar auto-conexión SSH
|
||||
cat ~/.ssh/id_ed25519.pub >> ~/.ssh/authorized_keys
|
||||
```
|
||||
|
||||
252
abyayala.yml
252
abyayala.yml
@ -1,7 +1,253 @@
|
||||
althost: abyayala
|
||||
matrix:
|
||||
- service_name: marmita
|
||||
- service_name: comun
|
||||
roles:
|
||||
- kemal
|
||||
domains:
|
||||
- marmite.abyaya.la
|
||||
nodo: marmite.comun
|
||||
- comun.abyaya.la
|
||||
|
||||
- service_name: knot
|
||||
roles:
|
||||
- knsupdate
|
||||
|
||||
- service_name: vpn
|
||||
roles:
|
||||
- rap
|
||||
nodos:
|
||||
- marmite
|
||||
- nodochasqui
|
||||
- yanapak
|
||||
- comun01
|
||||
- pilmaiken
|
||||
- fundeps
|
||||
- lluvia
|
||||
- lazarzamora
|
||||
- padiuxi
|
||||
- otra
|
||||
- qhanapukara
|
||||
- gtanw
|
||||
- pakkiru
|
||||
- tepeyac
|
||||
- cpogt
|
||||
- vmcpogt
|
||||
- rednasa
|
||||
- respaldos
|
||||
- rednasaazun
|
||||
- comixcal
|
||||
- nodochasqui
|
||||
- narkitila
|
||||
- naxuxi
|
||||
- padiuxiterminal
|
||||
- kurmi
|
||||
- yanapaknodo2
|
||||
- tule
|
||||
- fundepsterminal
|
||||
- jilgerilla
|
||||
- sutty
|
||||
- evoterminal
|
||||
- mexe
|
||||
- chukao
|
||||
- cads
|
||||
- cadt
|
||||
- puerto
|
||||
- barrio
|
||||
- antisistema
|
||||
- rebeldia
|
||||
- kipu
|
||||
- resistencia
|
||||
- carabobolibre
|
||||
- samatuun
|
||||
- kaasavi
|
||||
- llavero
|
||||
- deabajo
|
||||
- testnet
|
||||
|
||||
- service_name: respaldos
|
||||
domains:
|
||||
- respaldos.abyaya.la
|
||||
nodo: respaldos.comun
|
||||
force_https: yes
|
||||
|
||||
- nodo: marmite
|
||||
force_https: yes
|
||||
# Auto-deduced: domains: [marmite.abyaya.la], rap_dn: marmite.comun
|
||||
|
||||
- service_name: yanapak
|
||||
domains:
|
||||
- yanapak.abyaya.la
|
||||
nodo: yanapak.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: comun01
|
||||
domains:
|
||||
- comun01.abyaya.la
|
||||
nodo: comun01.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: pilmaiken
|
||||
domains:
|
||||
- pilmaiken.abyaya.la
|
||||
nodo: pilmaiken.comun
|
||||
force_https: yes
|
||||
ports:
|
||||
- 222
|
||||
|
||||
- service_name: fundeps
|
||||
domains:
|
||||
- fundeps.abyaya.la
|
||||
nodo: fundeps.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: lluvia
|
||||
domains:
|
||||
- lluvia.abyaya.la
|
||||
nodo: lluvia.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: lazarzamora
|
||||
domains:
|
||||
- lazarzamora.abyaya.la
|
||||
nodo: lazarzamora.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: padiuxi
|
||||
domains:
|
||||
- padiuxi.abyaya.la
|
||||
nodo: padiuxi.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: otra
|
||||
domains:
|
||||
- otra.abyaya.la
|
||||
nodo: otra.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: qhanapukara
|
||||
domains:
|
||||
- qhanapukara.abyaya.la
|
||||
nodo: qhanapukara.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: gtanw
|
||||
domains:
|
||||
- gtanw.abyaya.la
|
||||
nodo: gtanw.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: pakkiru
|
||||
domains:
|
||||
- pakkiru.abyaya.la
|
||||
nodo: pakkiru.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: tepeyac
|
||||
domains:
|
||||
- tepeyac.abyaya.la
|
||||
nodo: tepeyac.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: cpogt
|
||||
domains:
|
||||
- cpogt.abyaya.la
|
||||
nodo: cpogt.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: rednasa
|
||||
domains:
|
||||
- rednasa.abyaya.la
|
||||
nodo: rednasa.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: sutty
|
||||
domains:
|
||||
- sutty.abyaya.la
|
||||
nodo: sutty.comun
|
||||
force_https: yes
|
||||
enable_compression: yes
|
||||
|
||||
- service_name: abyaya_root
|
||||
domains:
|
||||
- abyaya.la
|
||||
- www.abyaya.la
|
||||
nodo: sutty.comun
|
||||
force_https: yes
|
||||
enable_compression: yes
|
||||
root: yes
|
||||
|
||||
- service_name: mexe
|
||||
domains:
|
||||
- mexe.abyaya.la
|
||||
nodo: mexe.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: chukao
|
||||
domains:
|
||||
- chukao.abyaya.la
|
||||
nodo: chukao.comun
|
||||
force_https: yes
|
||||
enable_compression: yes
|
||||
|
||||
- service_name: cads
|
||||
domains:
|
||||
- cads.abyaya.la
|
||||
nodo: cads.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: puerto
|
||||
domains:
|
||||
- puerto.abyaya.la
|
||||
nodo: puerto.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: barrio
|
||||
domains:
|
||||
- barrio.abyaya.la
|
||||
nodo: barrio.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: rebeldia
|
||||
domains:
|
||||
- rebeldia.abyaya.la
|
||||
nodo: rebeldia.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: kipu
|
||||
domains:
|
||||
# - abyaya.la
|
||||
# - www.abyaya.la
|
||||
- kipu.latina.red
|
||||
nodo: kipu.comun
|
||||
ports:
|
||||
- 223
|
||||
ssl: yes
|
||||
# root: yes
|
||||
|
||||
- service_name: carabobolibre
|
||||
domains:
|
||||
- carabobolibre.abyaya.la
|
||||
nodo: carabobolibre.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: samatuun
|
||||
domains:
|
||||
- samatuun.abyaya.la
|
||||
nodo: samatuun.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: kaasavi
|
||||
domains:
|
||||
- kaasavi.abyaya.la
|
||||
nodo: kaasavi.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: llavero
|
||||
domains:
|
||||
- llavero.abyaya.la
|
||||
nodo: llavero.comun
|
||||
force_https: yes
|
||||
|
||||
- service_name: deabajo
|
||||
domains:
|
||||
- deabajo.abyaya.la
|
||||
nodo: deabajo.comun
|
||||
force_https: yes
|
||||
|
||||
10
ansible.cfg
10
ansible.cfg
@ -1,2 +1,12 @@
|
||||
[defaults]
|
||||
inventory = ./hosts.production
|
||||
forks = 10
|
||||
|
||||
[ssh_connection]
|
||||
ssh_args = -C -o ControlMaster=auto -o ControlPersist=1h -o PreferredAuthentications=publickey -o ForwardAgent=yes
|
||||
control_path_dir = ~/.ansible/cp
|
||||
control_path = /tmp/ssh-%%r@%%h:%%p
|
||||
pipelining = True
|
||||
scp_if_ssh = smart
|
||||
transfer_method = smart
|
||||
sftp_batch_mode = True
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
# ansible-playbook --vault-id @prompt deploy.yml -e "host=digitalocean alt=numerica"
|
||||
# ansible-playbook --vault-id @prompt deploy.yml -e "alt=abyayala host=hetzner"
|
||||
# opcional: service define despliegue de servicio especifico
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
@ -8,9 +8,9 @@
|
||||
|
||||
- include_role: name=althost
|
||||
|
||||
- include_role: name=users
|
||||
tags: users, installation
|
||||
|
||||
- include_role: name=firewall
|
||||
tags: firewall
|
||||
|
||||
- include_role: name=proxy
|
||||
tags: proxy
|
||||
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
host_ip: 5.161.236.18
|
||||
proxy_scale: 2
|
||||
@ -1,14 +1,31 @@
|
||||
---
|
||||
ssh_users:
|
||||
- name: beto
|
||||
- name: berto
|
||||
comment: "Roberto Soto"
|
||||
sudo: yes
|
||||
servers_allow:
|
||||
- all
|
||||
|
||||
# - name: latina
|
||||
# comment: "intra servers"
|
||||
# root: yes
|
||||
# servers_allow:
|
||||
# - macarena.latina.red
|
||||
- name: infinito
|
||||
comment: "infinito@fedora"
|
||||
sudo: yes
|
||||
servers_allow:
|
||||
- all
|
||||
|
||||
- name: pirra
|
||||
comment: "pirra@drwagnerjr"
|
||||
sudo: yes
|
||||
servers_allow:
|
||||
- all
|
||||
|
||||
- name: chasqui
|
||||
comment: ""
|
||||
sudo: yes
|
||||
servers_allow:
|
||||
- all
|
||||
|
||||
- name: fauno
|
||||
comment: ""
|
||||
sudo: yes
|
||||
servers_allow:
|
||||
- all
|
||||
|
||||
6
group_vars/hetzner/vars
Normal file
6
group_vars/hetzner/vars
Normal file
@ -0,0 +1,6 @@
|
||||
host_ip: 5.161.236.18
|
||||
main_zone: abyaya.la
|
||||
vpn_name: comun
|
||||
vpn_proxy: 10.13.12.1
|
||||
proxy_scale: 2
|
||||
domains_default_force_https: yes
|
||||
5
group_vars/testing/vars
Normal file
5
group_vars/testing/vars
Normal file
@ -0,0 +1,5 @@
|
||||
host_ip: 157.180.114.62
|
||||
main_zone: abyayala.red
|
||||
vpn_name: comun
|
||||
vpn_proxy: 10.13.12.159
|
||||
proxy_scale: 1
|
||||
@ -1,8 +1,19 @@
|
||||
[localhost]
|
||||
127.0.0.1
|
||||
127.0.0.1 ansible_connection=local
|
||||
|
||||
[abyayala]
|
||||
[hetzner]
|
||||
5.161.236.18
|
||||
|
||||
[abyayala:vars]
|
||||
[hetzner:vars]
|
||||
ansible_ssh_user=root
|
||||
|
||||
[sutty]
|
||||
sutty.nl
|
||||
|
||||
[sutty:vars]
|
||||
|
||||
[testing]
|
||||
157.180.114.62
|
||||
|
||||
[testing:vars]
|
||||
ansible_ssh_user=root
|
||||
|
||||
@ -1,13 +1,13 @@
|
||||
- name: check if service volumes exists
|
||||
local_action:
|
||||
module: stat
|
||||
stat:
|
||||
path: "{{ playbook_dir }}/roles/{{ item.roles[0] | default('proxy') }}/templates/volumes.yml"
|
||||
delegate_to: localhost
|
||||
register: volumes_def
|
||||
|
||||
- name: check if service networks exists
|
||||
local_action:
|
||||
module: stat
|
||||
stat:
|
||||
path: "{{ playbook_dir }}/roles/{{ item.roles[0] | default('proxy') }}/templates/networks.yml"
|
||||
delegate_to: localhost
|
||||
register: networks_def
|
||||
|
||||
- set_fact:
|
||||
@ -22,53 +22,53 @@
|
||||
when: networks_def.stat.exists
|
||||
|
||||
- name: define services in local composition
|
||||
local_action:
|
||||
module: blockinfile
|
||||
blockinfile:
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "services:"
|
||||
marker: "# {mark} {{ service_name|upper }}"
|
||||
block: "{{ services_content }}"
|
||||
delegate_to: localhost
|
||||
changed_when: false
|
||||
|
||||
- name: define volumes in local composition
|
||||
local_action:
|
||||
module: lineinfile
|
||||
lineinfile:
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "# volumenes compartidos"
|
||||
line: "volumes: #"
|
||||
state: present
|
||||
regexp: "volumes: #"
|
||||
delegate_to: localhost
|
||||
when: volumes_def.stat.exists
|
||||
changed_when: false
|
||||
|
||||
- name: define volumes content in local composition
|
||||
local_action:
|
||||
module: lineinfile
|
||||
lineinfile:
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "volumes: #"
|
||||
line: "{{ volumes_content }}"
|
||||
state: present
|
||||
regexp: "{{ volumes_content }}"
|
||||
delegate_to: localhost
|
||||
when: volumes_content is defined
|
||||
changed_when: false
|
||||
|
||||
- name: define networks in local composition
|
||||
local_action:
|
||||
module: lineinfile
|
||||
lineinfile:
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "# redes compartidas"
|
||||
line: "networks: #"
|
||||
state: present
|
||||
regexp: "networks: #"
|
||||
delegate_to: localhost
|
||||
when: networks_def.stat.exists
|
||||
changed_when: false
|
||||
|
||||
- name: define networks content in local composition
|
||||
local_action:
|
||||
module: lineinfile
|
||||
lineinfile:
|
||||
path: "{{ local_compose_path }}/docker-compose.yml"
|
||||
insertafter: "networks: #"
|
||||
line: "{{ networks_content }}"
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
when: networks_content is defined
|
||||
changed_when: false
|
||||
|
||||
@ -1,24 +1,56 @@
|
||||
# DOCKER CE this is specific for Debian
|
||||
# https://docs.docker.com/install/linux/docker-ce/debian/
|
||||
# Soporta Debian 12 (bookworm) y Debian 13 (trixie)
|
||||
|
||||
# Clean up conflicting Docker repositories first (always runs, even with --skip-tags=installation)
|
||||
- name: remove old docker repository files to avoid APT conflicts
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: absent
|
||||
loop:
|
||||
- /etc/apt/sources.list.d/docker.list
|
||||
- /etc/apt/sources.list.d/download_docker_com_linux_debian.list
|
||||
|
||||
- block:
|
||||
|
||||
- name: "unattended upgrades"
|
||||
apt:
|
||||
name: "unattended-upgrades"
|
||||
state: "present"
|
||||
|
||||
- name: required packages
|
||||
apt:
|
||||
name: ['apt-transport-https', 'ca-certificates', 'curl', 'gnupg2', 'software-properties-common', 'python3-pip']
|
||||
name: ['ca-certificates', 'curl', 'python3-pip']
|
||||
state: present
|
||||
|
||||
- name: docker signing key
|
||||
apt_key:
|
||||
- name: create keyrings directory
|
||||
file:
|
||||
path: /etc/apt/keyrings
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: download docker gpg key
|
||||
get_url:
|
||||
url: https://download.docker.com/linux/debian/gpg
|
||||
state: present
|
||||
|
||||
- name: docker apt repository
|
||||
apt_repository:
|
||||
repo: deb [arch=amd64] https://download.docker.com/linux/debian bullseye stable
|
||||
dest: /etc/apt/keyrings/docker.asc
|
||||
mode: '0644'
|
||||
|
||||
- name: install docker community edition
|
||||
- name: add docker repository with deb822 format
|
||||
deb822_repository:
|
||||
name: docker
|
||||
types: [deb]
|
||||
uris: https://download.docker.com/linux/debian
|
||||
suites: ["{{ ansible_distribution_release }}"]
|
||||
components: [stable]
|
||||
architectures: [amd64]
|
||||
signed_by: /etc/apt/keyrings/docker.asc
|
||||
|
||||
- name: install docker community edition and compose plugin
|
||||
apt:
|
||||
name: docker-ce
|
||||
name:
|
||||
- docker-ce
|
||||
- docker-ce-cli
|
||||
- containerd.io
|
||||
- docker-compose-plugin
|
||||
update_cache: yes
|
||||
|
||||
- name: is node already in swarm mode
|
||||
@ -44,55 +76,30 @@
|
||||
state: present
|
||||
|
||||
# ansible-docker requirements
|
||||
- name: python package docker-py is deprecated
|
||||
pip:
|
||||
name: docker-py
|
||||
state: absent
|
||||
break_system_packages: true
|
||||
|
||||
- name: ensure python package docker is present
|
||||
pip:
|
||||
name: docker
|
||||
# Use system packages instead of pip to avoid break_system_packages
|
||||
- name: ensure python3-docker package is present
|
||||
apt:
|
||||
name: python3-docker
|
||||
state: present
|
||||
break_system_packages: true
|
||||
|
||||
# # https://stackoverflow.com/questions/77490435/attributeerror-cython-sources
|
||||
# - name: fix python package Cython version
|
||||
# pip:
|
||||
# name: Cython
|
||||
# state: present
|
||||
# version: <3.0.0
|
||||
# break_system_packages: true
|
||||
# changed_when: false
|
||||
|
||||
# - name: fix python package PyYAML version
|
||||
# shell: pip install "pyyaml==5.4.1" --no-build-isolation --break-system-packages
|
||||
|
||||
- name: ensure python package docker-compose is present
|
||||
pip:
|
||||
name: docker-compose
|
||||
state: present
|
||||
break_system_packages: true
|
||||
|
||||
tags: installation
|
||||
|
||||
|
||||
# DOCKER COMPOSITION IN MASTER
|
||||
- block:
|
||||
- name: make sure compose path exists
|
||||
file: path={{ compose_path }} state=directory
|
||||
|
||||
- name: make sure local compose path exists
|
||||
local_action:
|
||||
module: file
|
||||
path: "{{ local_compose_path }}"
|
||||
file:
|
||||
path: "{{ local_compose_path }}"
|
||||
state: directory
|
||||
delegate_to: localhost
|
||||
|
||||
- name: clean docker-compose.yml
|
||||
local_action:
|
||||
module: template
|
||||
template:
|
||||
dest: "{{ local_compose_path }}/docker-compose.yml"
|
||||
src: roles/althost/templates/docker-compose.yml
|
||||
delegate_to: localhost
|
||||
changed_when: false
|
||||
|
||||
- name: execute roles per domain mapping
|
||||
|
||||
@ -1,9 +1,10 @@
|
||||
- set_fact:
|
||||
current_service: "{{ item }}"
|
||||
service_name: "{{ item.service_name }}"
|
||||
# Deducir service_name: usar 'nodo' si existe, sino 'service_name' (retrocompatibilidad)
|
||||
service_name: "{{ item.nodo | default(item.service_name) }}"
|
||||
service_roles: "{{ item.roles | default([]) }}"
|
||||
|
||||
- include_role:
|
||||
- include_role:
|
||||
name: "{{ current_role_name }}"
|
||||
with_items: "{{ service_roles }}"
|
||||
loop_control:
|
||||
|
||||
@ -10,33 +10,55 @@
|
||||
register: vhost_stat
|
||||
|
||||
- set_fact:
|
||||
needs_cert: (loop.ssl | default(domains_default_ssl) ) or (loop.force_https | default(domains_default_force_https))
|
||||
needs_vhost: needs_cert and not vhost_stat.stat.exists
|
||||
obtain_cert: needs_cert and not ssl_cert.stat.exists
|
||||
needs_cert: "{{ ((loop.ssl | default(domains_default_ssl) | bool) or (loop.force_https | default(domains_default_force_https) | bool)) | bool }}"
|
||||
|
||||
- set_fact:
|
||||
needs_vhost: "{{ (needs_cert | bool and not vhost_stat.stat.exists) | bool }}"
|
||||
obtain_cert: "{{ (needs_cert | bool and not ssl_cert.stat.exists) | bool }}"
|
||||
|
||||
- name: certificate obtention
|
||||
block:
|
||||
- set_fact:
|
||||
vhost: "{{ loop }}"
|
||||
|
||||
- name: fetch certificate with certbot container
|
||||
- set_fact:
|
||||
is_root_domain: "{{ loop.root | default(false) | bool }}"
|
||||
|
||||
- name: fetch certificate with certbot container (with wildcard)
|
||||
docker_container:
|
||||
name: chencriptemos
|
||||
image: "{{ CERTBOT_image }}"
|
||||
state: started
|
||||
volumes:
|
||||
- "{{ althost }}_certs_data:/etc/letsencrypt"
|
||||
command: "--non-interactive --agree-tos --email {{ webmaster_email }} certonly --preferred-challenges dns --authenticator dns-standalone --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 --dns-standalone-propagation-seconds=60 -d {{ loop.domains[0] }} -d *.{{ loop.domains[0] }}"
|
||||
command: "--non-interactive --agree-tos --expand --email {{ webmaster_email }} certonly --preferred-challenges dns --authenticator dns-standalone --dns-standalone-address={{ host_ip }} --dns-standalone-port=53 --dns-standalone-propagation-seconds=10 {% for domain in loop.domains %} -d {{ domain }} -d *.{{ domain }} {% endfor %}"
|
||||
detach: no
|
||||
cleanup: yes
|
||||
ports:
|
||||
ports:
|
||||
- "{{ host_ip }}:53:53/tcp"
|
||||
- "{{ host_ip }}:53:53/udp"
|
||||
notify:
|
||||
- reload proxy
|
||||
register: cert_result
|
||||
when: not is_root_domain | bool
|
||||
|
||||
when: obtain_cert
|
||||
- name: fetch certificate with certbot container (without wildcard, root domain - using webroot)
|
||||
docker_container:
|
||||
name: chencriptemos
|
||||
image: certbot/certbot:latest
|
||||
state: started
|
||||
volumes:
|
||||
- "{{ althost }}_certs_data:/etc/letsencrypt"
|
||||
- "{{ althost }}_certbot_webroot:{{ certbot_webroot }}"
|
||||
command: "--non-interactive --agree-tos --expand --email {{ webmaster_email }} certonly --webroot --webroot-path {{ certbot_webroot }} {% for domain in loop.domains %} -d {{ domain }} {% endfor %}"
|
||||
detach: no
|
||||
cleanup: yes
|
||||
notify:
|
||||
- reload proxy
|
||||
register: cert_result
|
||||
when: is_root_domain | bool
|
||||
|
||||
when: obtain_cert | bool
|
||||
|
||||
# RESET
|
||||
- set_fact:
|
||||
|
||||
@ -30,14 +30,13 @@
|
||||
env: yes
|
||||
value: /bin/bash
|
||||
|
||||
# TODO
|
||||
# - name: automatic letsencrypt certs renewal
|
||||
# cron:
|
||||
# name: certificate renewal
|
||||
# day: 4,18
|
||||
# hour: 0
|
||||
# minute: 0
|
||||
# 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: automatic letsencrypt certs renewal
|
||||
cron:
|
||||
name: certificate renewal
|
||||
day: 4,18
|
||||
hour: 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 --log-driver=journald"
|
||||
|
||||
- name: proxy update, after certs renewal
|
||||
cron:
|
||||
@ -45,12 +44,4 @@
|
||||
day: 4,18
|
||||
hour: 6
|
||||
minute: 10
|
||||
job: "docker service update --force {{ althost }}_proxy"
|
||||
|
||||
- name: mail proxy update, after certs renewal
|
||||
cron:
|
||||
name: mail proxy update
|
||||
day: 4,18
|
||||
hour: 6
|
||||
minute: 20
|
||||
job: "docker service update {{ althost }}_correspondencia_front"
|
||||
job: "docker service update --force {{ althost }}_proxy"
|
||||
@ -9,3 +9,9 @@
|
||||
dest: "/etc/dnsmasq.conf"
|
||||
notify:
|
||||
- restart dnsmasq
|
||||
|
||||
- name: activar el servicio
|
||||
systemd_service:
|
||||
name: dnsmasq
|
||||
enabled: true
|
||||
state: restarted
|
||||
|
||||
@ -74,8 +74,8 @@ resolv-file=/etc/resolv.local
|
||||
|
||||
# Add local-only domains here, queries in these domains are answered
|
||||
# from /etc/hosts or DHCP only.
|
||||
local=/comun/
|
||||
domain=comun
|
||||
local=/{{ vpn_name }}/
|
||||
domain={{ vpn_name }}
|
||||
|
||||
# Add domains which you want to force to an IP address here.
|
||||
# The example below send any host in double-click.net to a local
|
||||
@ -117,12 +117,12 @@ domain=comun
|
||||
# specified interfaces (and the loopback) give the name of the
|
||||
# interface (eg eth0) here.
|
||||
# Repeat the line for more than one interface.
|
||||
interface=comun
|
||||
interface={{ vpn_name }}
|
||||
# Or you can specify which interface _not_ to listen on
|
||||
except-interface=eth0
|
||||
# Or which to listen on by address (remember to include 127.0.0.1 if
|
||||
# you use this.)
|
||||
listen-address=10.13.12.1,127.0.0.1
|
||||
listen-address={{ vpn_proxy }},127.0.0.1
|
||||
# If you want dnsmasq to provide only DNS service on an interface,
|
||||
# configure it as shown above, and then use the following line to
|
||||
# disable DHCP and TFTP on it.
|
||||
|
||||
14
roles/firewall/tasks/main.yml
Normal file
14
roles/firewall/tasks/main.yml
Normal file
@ -0,0 +1,14 @@
|
||||
- name: "Paquetes"
|
||||
apt:
|
||||
name:
|
||||
- "iptables-persistent"
|
||||
- "ipset-persistent"
|
||||
state: "present"
|
||||
|
||||
- name: "Rules"
|
||||
with_items:
|
||||
- "rules.v4"
|
||||
- "rules.v6"
|
||||
template:
|
||||
src: "{{ item }}.j2"
|
||||
dest: "/etc/iptables/{{ item }}"
|
||||
18
roles/firewall/templates/rules.v4.j2
Normal file
18
roles/firewall/templates/rules.v4.j2
Normal file
@ -0,0 +1,18 @@
|
||||
*filter
|
||||
:INPUT DROP [106:5591]
|
||||
:FORWARD DROP [28:1715]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
|
||||
-A INPUT -m conntrack --ctstate INVALID -j DROP
|
||||
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
|
||||
-A INPUT -i lo -j ACCEPT
|
||||
-A INPUT -i {{ vpn_name }} -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT
|
||||
-A INPUT -p udp -m udp --dport 53 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 53 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
|
||||
-A INPUT -p udp -m udp --dport 655 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 655 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 3000 -j ACCEPT
|
||||
COMMIT
|
||||
5
roles/firewall/templates/rules.v6.j2
Normal file
5
roles/firewall/templates/rules.v6.j2
Normal file
@ -0,0 +1,5 @@
|
||||
*filter
|
||||
:INPUT DROP [0:0]
|
||||
:FORWARD DROP [0:0]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
COMMIT
|
||||
10
roles/kemal/templates/vhost.conf
Normal file
10
roles/kemal/templates/vhost.conf
Normal file
@ -0,0 +1,10 @@
|
||||
server {
|
||||
server_name {{ vhost.domains | join(' ') }};
|
||||
listen 80;
|
||||
|
||||
client_max_body_size 4k;
|
||||
|
||||
location / {
|
||||
proxy_pass http://{{ vpn_proxy }}:3000;
|
||||
}
|
||||
}
|
||||
8
roles/knsupdate/files/dns_extras/pilmaiken.abyaya.la
Normal file
8
roles/knsupdate/files/dns_extras/pilmaiken.abyaya.la
Normal file
@ -0,0 +1,8 @@
|
||||
del pilmaiken mx
|
||||
del pilmaiken txt
|
||||
del pilmaiken spf
|
||||
add pilmaiken mx 10 correspondencia.latina.red.
|
||||
add pilmaiken txt "v=spf1 mx a:correspondencia.latina.red -all"
|
||||
add pilmaiken spf "v=spf1 mx a:correspondencia.latina.red -all"
|
||||
add dkim._domainkey.pilmaiken txt "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQ6JwPaawDzMXuscSgDpvipRFLGXSqgmvvI6jk18lcg0kK2lfxsvXGJ/6U7oCtKa35IEVzdigxD0o7DzklKxAsNIVbcExPJkFWzQuKuP6ATBESo7YUn7Z5qjfxBiNPS0FJp8XpbpUzN+zg/NTgmkggnwwC0tKgcEQ6HnI9AOa1LQIDAQAB"
|
||||
add _dmarc.pilmaiken txt "v=DMARC1; p=reject; rua=mailto:postmaster@correspondencia.latina.red; ruf=mailto:postmaster@correspondencia.latina.red; adkim=s; aspf=s"
|
||||
22
roles/knsupdate/tasks/loop.yml
Normal file
22
roles/knsupdate/tasks/loop.yml
Normal file
@ -0,0 +1,22 @@
|
||||
- include_vars: dir="../vars" files_matching="main.yml"
|
||||
|
||||
- name: import matrix
|
||||
local_action: "include_vars dir=../../../ files_matching={{ alt }}.yml"
|
||||
|
||||
- name: domains' stuff
|
||||
block:
|
||||
- name: filtrar solo los servicios de la matrix que definen dominios DNS
|
||||
set_fact:
|
||||
matrix_loop: "{{ matrix_loop | default([]) | union([ domino ]) }}"
|
||||
with_items: "{{ matrix }}"
|
||||
when: "{{ domino.domains is defined }}"
|
||||
loop_control:
|
||||
loop_var: domino
|
||||
|
||||
- name: knsupdate ACTUALIZA A KNOT ACERCA DE CADA DOMINIO
|
||||
include_tasks: ./update.yml
|
||||
with_items: "{{ matrix_loop }}"
|
||||
loop_control:
|
||||
loop_var: vhost
|
||||
tags: knot
|
||||
|
||||
7
roles/knsupdate/tasks/main.yml
Normal file
7
roles/knsupdate/tasks/main.yml
Normal file
@ -0,0 +1,7 @@
|
||||
- name: "required packages"
|
||||
apt:
|
||||
name: "knot-dnsutils"
|
||||
state: "present"
|
||||
tags: installation
|
||||
|
||||
- include_tasks: loop.yml
|
||||
31
roles/knsupdate/tasks/templates/commands.j2
Normal file
31
roles/knsupdate/tasks/templates/commands.j2
Normal file
@ -0,0 +1,31 @@
|
||||
{% for dns_server in dns_servers %}
|
||||
|
||||
server {{ dns_server }}
|
||||
zone {{ zone }}
|
||||
origin {{ zone }}
|
||||
ttl 60
|
||||
|
||||
del {{ hostname }} a
|
||||
del {{ hostname }} ns
|
||||
add {{ hostname }} a {{ host_ip }}
|
||||
|
||||
{% if hostname != '@' and hostname != 'www' %}
|
||||
add *.{{ hostname }} a {{ host_ip }}
|
||||
{% else %}
|
||||
add {{ domain }} a {{ host_ip }}
|
||||
add *.{{ domain }} a {{ host_ip }}
|
||||
{% endif %}
|
||||
|
||||
{% if hostname == '@' %}
|
||||
add _acme-challenge a {{ host_ip }}
|
||||
add _acme-challenge ns _acme-challenge
|
||||
{% else %}
|
||||
add _acme-challenge.{{ hostname }} a {{ host_ip }}
|
||||
add _acme-challenge.{{ hostname }} ns _acme-challenge
|
||||
{% endif %}
|
||||
|
||||
{% include "files/dns_extras/" ~ vhost.domains[0] ignore missing %}
|
||||
|
||||
send
|
||||
{% endfor %}
|
||||
quit
|
||||
21
roles/knsupdate/tasks/templates/dns_info.j2
Normal file
21
roles/knsupdate/tasks/templates/dns_info.j2
Normal file
@ -0,0 +1,21 @@
|
||||
|
||||
========================================
|
||||
Configuracion de DNS requerida: {{ domain }}
|
||||
========================================
|
||||
Por favor configue los siguiente registros DNS en su proveedor:
|
||||
|
||||
{% if hostname == '@' %}
|
||||
{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
|
||||
*.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
|
||||
|
||||
_acme-challenge.{{ zone | regex_replace('\\.$', '') }} IN NS ns-acme.{{ zone | regex_replace('\\.$', '') }}.
|
||||
ns-acme.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
|
||||
{% else %}
|
||||
{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
|
||||
*.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
|
||||
|
||||
_acme-challenge.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN NS ns-acme.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }}.
|
||||
ns-acme.{{ hostname }}.{{ zone | regex_replace('\\.$', '') }} IN A {{ host_ip }}
|
||||
{% endif %}
|
||||
|
||||
========================================
|
||||
5
roles/knsupdate/tasks/update.yml
Normal file
5
roles/knsupdate/tasks/update.yml
Normal file
@ -0,0 +1,5 @@
|
||||
- name: process each domain in the list
|
||||
include_tasks: update_domain.yml
|
||||
with_items: "{{ vhost.domains }}"
|
||||
loop_control:
|
||||
loop_var: domain
|
||||
47
roles/knsupdate/tasks/update_domain.yml
Normal file
47
roles/knsupdate/tasks/update_domain.yml
Normal file
@ -0,0 +1,47 @@
|
||||
- set_fact:
|
||||
is_abyayala_subdomain: "{{ domain.endswith('.' ~ main_zone) }}"
|
||||
|
||||
- name: extract zone and hostname for main zone subdomains
|
||||
set_fact:
|
||||
zone: "{{ main_zone ~ '.' }}"
|
||||
hostname: "{{ domain | regex_replace('([a-z0-9-]+)\\.' ~ main_zone|regex_escape , '\\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: Debug knsupdate for this domain
|
||||
debug:
|
||||
msg: "{{ lookup('template', 'templates/commands.j2') }}"
|
||||
when: is_abyayala_subdomain
|
||||
|
||||
- name: knsupdate for this domain
|
||||
shell: knsupdate
|
||||
args:
|
||||
stdin: "{{ lookup('template', 'templates/commands.j2') }}"
|
||||
when: is_abyayala_subdomain
|
||||
|
||||
- name: display DNS configuration instructions for external domains
|
||||
debug:
|
||||
msg: "{{ lookup('template', 'templates/dns_info.j2') }}"
|
||||
when: not is_abyayala_subdomain
|
||||
12
roles/knsupdate/vars/main.yml
Normal file
12
roles/knsupdate/vars/main.yml
Normal file
@ -0,0 +1,12 @@
|
||||
dns_servers:
|
||||
- "anarres.sutty.nl"
|
||||
- "athshe.sutty.nl"
|
||||
- "gethen.sutty.nl"
|
||||
- "ganam.sutty.nl"
|
||||
|
||||
compound_tlds:
|
||||
- com.ar
|
||||
- com.mx
|
||||
- com.br
|
||||
- org.ar
|
||||
- edu.ar
|
||||
@ -0,0 +1 @@
|
||||
return 301 https://hedgedoc.sutty.abyaya.la$request_uri;
|
||||
1
roles/proxy/files/custom_server_includes/2012k.abyaya.la
Normal file
1
roles/proxy/files/custom_server_includes/2012k.abyaya.la
Normal file
@ -0,0 +1 @@
|
||||
client_max_body_size 0;
|
||||
@ -2,21 +2,26 @@
|
||||
include_role: name=dnsmasq
|
||||
tags: dns
|
||||
|
||||
- name: knsupdate
|
||||
include_role: name=knsupdate
|
||||
tags: knot
|
||||
|
||||
- name: certbot role
|
||||
include_role: name=certbot
|
||||
tags: certbot
|
||||
|
||||
- include_tasks: ../../althost/tasks/compose.yml
|
||||
vars: # forcing since this role is included statically
|
||||
service_name: proxy
|
||||
- name: set main_zone_regex from main_zone
|
||||
set_fact:
|
||||
main_zone_regex: "{{ '.' ~ main_zone | replace('.', '\\.') }}"
|
||||
|
||||
- name: configuration path
|
||||
file: path={{ conf_path }} state=directory
|
||||
|
||||
# TODO leaving unused vhosts bugs proxy
|
||||
- name: clean vhosts_path
|
||||
file: path={{ vhosts_path }} state=absent
|
||||
when: clean_vhosts is defined
|
||||
- name: configuration paths
|
||||
file: path={{ abc }} state=directory
|
||||
with_items:
|
||||
- "{{ stream_path }}"
|
||||
- "{{ conf_path }}"
|
||||
- "{{ certbot_webroot }}"
|
||||
loop_control:
|
||||
loop_var: abc
|
||||
|
||||
- name: virtual hosts path
|
||||
file: path={{ vhosts_path }} state=directory
|
||||
@ -31,16 +36,17 @@
|
||||
with_items:
|
||||
- common.conf
|
||||
- common_ssl.conf
|
||||
- nginx.conf
|
||||
- acme_challenge.conf
|
||||
loop_control:
|
||||
loop_var: common
|
||||
|
||||
- name: domains' stuff
|
||||
- name: neo stuff
|
||||
block:
|
||||
- name: slice matrix with those having domains defined
|
||||
set_fact:
|
||||
matrix_loop: "{{ matrix_loop | default([]) | union([ domino ]) }}"
|
||||
with_items: "{{ matrix }}"
|
||||
when: "{{ domino.domains is defined }}"
|
||||
- name: normalize and build matrix_loop
|
||||
include_tasks: normalize_node.yml
|
||||
with_items: "{{ matrix }}"
|
||||
when: "{{ (domino.domains is defined or domino.nodo is defined or domino.service_name is defined) }}"
|
||||
loop_control:
|
||||
loop_var: domino
|
||||
|
||||
@ -55,6 +61,25 @@
|
||||
- name: vhosts loop
|
||||
include_tasks: vhosts.yml
|
||||
with_items: "{{ matrix_loop }}"
|
||||
loop_control:
|
||||
loop_var: vhost
|
||||
when: ((service is undefined) or (service is defined and service == vhost.service_name)) and not vhost.skip_vhost
|
||||
|
||||
- name: streams loop
|
||||
include_tasks: stream.yml
|
||||
with_items: "{{ matrix_loop }}"
|
||||
loop_control:
|
||||
loop_var: vhost
|
||||
when: (service is undefined) or (service is defined and service == vhost.service_name)
|
||||
|
||||
- name: slice matrix with those having ports defined
|
||||
set_fact:
|
||||
matrix_ports: "{{ matrix_ports | default([]) | union(ma.ports) }}"
|
||||
with_items: "{{ matrix }}"
|
||||
when: (ma.ports is defined)
|
||||
loop_control:
|
||||
loop_var: ma
|
||||
|
||||
- include_tasks: ../../althost/tasks/compose.yml
|
||||
vars: # forcing since this role is included statically
|
||||
service_name: proxy
|
||||
21
roles/proxy/tasks/normalize_node.yml
Normal file
21
roles/proxy/tasks/normalize_node.yml
Normal file
@ -0,0 +1,21 @@
|
||||
- set_fact:
|
||||
_existing_abyayala_domains: "{{ (domino.domains | default([])) | select('match', '.*' ~ main_zone_regex ~ '$') | list }}"
|
||||
_other_domains: "{{ (domino.domains | default([])) | reject('match', '.*' ~ main_zone_regex ~ '$') | list }}"
|
||||
_node_name: "{{ domino.nodo | default(domino.service_name) }}"
|
||||
_default_domain: "{{ (domino.nodo | default(domino.service_name)) ~ '.' ~ main_zone }}"
|
||||
_default_rap_dn: "{{ (domino.nodo | default(domino.service_name)) ~ '.' ~ vpn_name }}"
|
||||
|
||||
- set_fact:
|
||||
domino_normalized:
|
||||
nodo: "{{ _node_name }}"
|
||||
rap_dn: "{{ domino.rap_dn | default(_default_rap_dn) }}"
|
||||
domains: "{{ [(_existing_abyayala_domains[0] if (_existing_abyayala_domains | length > 0) else _default_domain)] + _other_domains }}"
|
||||
force_https: "{{ domino.force_https | default(domains_default_force_https) }}"
|
||||
ports: "{{ domino.ports | default([]) }}"
|
||||
enable_compression: "{{ domino.enable_compression | default(domains_default_enable_compression) }}"
|
||||
roles: "{{ domino.roles | default([]) }}"
|
||||
service_name: "{{ domino.service_name | default(_node_name) }}"
|
||||
skip_vhost: "{{ (domino.roles is defined and (domino.roles | length > 0) and domino.domains is not defined) }}"
|
||||
|
||||
- set_fact:
|
||||
matrix_loop: "{{ matrix_loop | default([]) | union([ domino_normalized ]) }}"
|
||||
10
roles/proxy/tasks/stream.yml
Normal file
10
roles/proxy/tasks/stream.yml
Normal file
@ -0,0 +1,10 @@
|
||||
- set_fact:
|
||||
vhost_dest: "{{ stream_path }}/{{ vhost.service_name }}.conf"
|
||||
|
||||
- name: default stream for ssh
|
||||
template:
|
||||
src: "{{ default_stream }}"
|
||||
dest: "{{ vhost_dest }}"
|
||||
when: vhost.ports is defined and (vhost.ports | length > 0)
|
||||
notify:
|
||||
- reload proxy
|
||||
@ -1,10 +1,29 @@
|
||||
|
||||
- set_fact:
|
||||
vhost_dest: "{{ vhosts_path }}/{{ vhost.domains[0] }}.conf"
|
||||
|
||||
- name: generate nginx vhosts
|
||||
- block:
|
||||
- set_fact:
|
||||
custom_vhost: "roles/{{ vhost.roles[0] }}/templates/vhost.conf"
|
||||
- set_fact:
|
||||
proxy_conf: "roles/{{ vhost.roles[0] }}/templates/proxy.conf"
|
||||
when: vhost.roles is defined and (vhost.roles | length > 0)
|
||||
|
||||
- set_fact:
|
||||
proxy_conf_look: "{{ lookup('template', proxy_conf) }}"
|
||||
when: proxy_conf is defined and proxy_conf is is_file
|
||||
|
||||
- name: generate default vhosts
|
||||
template:
|
||||
src: "{{ default_vhost }}"
|
||||
dest: "{{ vhost_dest }}"
|
||||
when: (vhost.roles is undefined or (vhost.roles | length == 0) or vhost.roles[0] == 'proxy') or (custom_vhost is undefined or custom_vhost is not is_file)
|
||||
notify:
|
||||
- reload proxy
|
||||
|
||||
- name: generate nginx custom vhosts
|
||||
template:
|
||||
src: "{{ custom_vhost }}"
|
||||
dest: "{{ vhost_dest }}"
|
||||
when: (vhost.roles is defined and (vhost.roles | length > 0) and vhost.roles[0] != 'proxy') and custom_vhost is defined and custom_vhost is is_file
|
||||
notify:
|
||||
- reload proxy
|
||||
|
||||
25
roles/proxy/templates/acme_challenge.conf
Normal file
25
roles/proxy/templates/acme_challenge.conf
Normal file
@ -0,0 +1,25 @@
|
||||
# Let's Encrypt ACME challenge configuration
|
||||
# This configuration serves the .well-known/acme-challenge directory
|
||||
# for HTTP-01 validation when using webroot method
|
||||
|
||||
location ^~ /.well-known/acme-challenge/ {
|
||||
# Serve files from the certbot webroot
|
||||
root {{ certbot_webroot }};
|
||||
|
||||
# Allow access to challenge files
|
||||
allow all;
|
||||
|
||||
# Ensure plain text content type
|
||||
default_type "text/plain";
|
||||
|
||||
# Disable any authentication
|
||||
auth_basic off;
|
||||
|
||||
# Serve the challenge file directly
|
||||
try_files $uri =404;
|
||||
}
|
||||
|
||||
# Deny access to other .well-known paths for security
|
||||
location ~ /\.well-known/ {
|
||||
deny all;
|
||||
}
|
||||
@ -0,0 +1,4 @@
|
||||
add_header X-Frame-Options "sameorigin";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
|
||||
@ -6,6 +6,14 @@
|
||||
# openssl dhparam -outform pem -out dhparam2048.pem 2048
|
||||
ssl_dhparam /etc/nginx/conf/dhparam2048.pem;
|
||||
|
||||
ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
|
||||
ssl_prefer_server_ciphers on;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
ssl_ecdh_curve X25519:prime256v1:secp384r1;
|
||||
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-CHACHA20-POLY1305;
|
||||
ssl_prefer_server_ciphers off;
|
||||
|
||||
ssl_session_timeout 1d;
|
||||
ssl_session_cache shared:MozSSL:10m;
|
||||
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload" always;
|
||||
|
||||
ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
||||
|
||||
@ -1,15 +1,45 @@
|
||||
# BEGIN PROXY
|
||||
location / {
|
||||
proxy_ssl_verify off;
|
||||
proxy_ssl_name $comun;
|
||||
proxy_ssl_server_name on;
|
||||
{% if vhost.enable_compression | default(false) %}
|
||||
gzip on;
|
||||
gzip_static on;
|
||||
gzip_proxied any;
|
||||
gzip_http_version 1.1;
|
||||
gzip_comp_level 5;
|
||||
gzip_min_length 10240;
|
||||
gzip_vary on;
|
||||
gzip_types application/atom+xml application/javascript text/javascript application/json application/rss+xml application/vnd.ms-fontobject application/x-font-ttf application/x-web-app-manifest+json application/xhtml+xml application/xml font/opentype image/svg+xml image/x-icon text/css text/plain text/x-component;
|
||||
|
||||
proxy_pass https://$comun_{{ vhost.nodo | replace(".", "_") }};
|
||||
gzip_disable "msie6";
|
||||
{% endif %}
|
||||
|
||||
client_max_body_size 1G;
|
||||
|
||||
proxy_ssl_verify off;
|
||||
proxy_ssl_server_name on;
|
||||
proxy_ssl_name $ssl_server_name;
|
||||
|
||||
proxy_pass https://$comun_{{ vhost.rap_dn | replace(".", "") }};
|
||||
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection upgrade;
|
||||
|
||||
proxy_buffering off;
|
||||
proxy_request_buffering off;
|
||||
proxy_redirect off;
|
||||
proxy_connect_timeout 3m;
|
||||
proxy_send_timeout 3m;
|
||||
proxy_read_timeout 3m;
|
||||
|
||||
limit_conn connection_limit 50;
|
||||
limit_req zone=request_limit nodelay burst=20;
|
||||
|
||||
add_header Retry-After $retry_after always;
|
||||
|
||||
{% include "files/custom_proxy_includes/" ~ vhost.domains[0] ignore missing %}
|
||||
}
|
||||
|
||||
56
roles/proxy/templates/nginx.conf
Normal file
56
roles/proxy/templates/nginx.conf
Normal file
@ -0,0 +1,56 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
|
||||
error_log /var/log/nginx/error.log notice;
|
||||
pid /var/run/nginx.pid;
|
||||
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
server_tokens off;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
|
||||
keepalive_timeout 65;
|
||||
|
||||
# Limitar cada dirección IP a 50 peticiones por segundo por IP y
|
||||
# servidor.
|
||||
limit_req_zone $server_name$binary_remote_addr zone=request_limit:10m rate=10r/s;
|
||||
limit_req_status 429;
|
||||
|
||||
# Limita la cantidad de conexiones concurrentes por IP. Según la
|
||||
# documentación de Nginx, cada request en HTTP/2 se cuenta como una
|
||||
# conexión separada aunque sean la misma.
|
||||
limit_conn_zone $binary_remote_addr zone=connection_limit:10m;
|
||||
limit_conn_status 429;
|
||||
|
||||
# Informar a los navegadores que cuando reciban un error de muchas
|
||||
# conexiones, esperen un segundo antes de reintentar.
|
||||
map $status $retry_after {
|
||||
default '';
|
||||
429 '1';
|
||||
}
|
||||
|
||||
#gzip on;
|
||||
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
}
|
||||
|
||||
stream {
|
||||
include /etc/nginx/stream.d/*.conf;
|
||||
}
|
||||
|
||||
@ -8,11 +8,15 @@
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
{% for port in matrix_ports %}
|
||||
- "{{ port }}:{{ port }}"
|
||||
{% endfor %}
|
||||
networks:
|
||||
- proxy
|
||||
volumes:
|
||||
- "{{ vhosts_path }}:/etc/nginx/conf.d/"
|
||||
- "{{ conf_path }}:/etc/nginx/conf/"
|
||||
- "certs_data:{{ nginx_certs_path }}:ro"
|
||||
|
||||
|
||||
- "{{ conf_path }}/nginx.conf:/etc/nginx/nginx.conf:ro"
|
||||
- "{{ stream_path }}:/etc/nginx/stream.d/"
|
||||
- "certbot_webroot:{{ certbot_webroot }}"
|
||||
|
||||
11
roles/proxy/templates/stream.conf
Normal file
11
roles/proxy/templates/stream.conf
Normal file
@ -0,0 +1,11 @@
|
||||
upstream ssh_{{ vhost.rap_dn | replace(".", "") }} {
|
||||
server {{ vhost.rap_dn }}:22;
|
||||
}
|
||||
|
||||
server {
|
||||
listen {{ vhost.ports[0] }};
|
||||
|
||||
server_name {{ vhost.service_name }}.{{ main_zone }};
|
||||
|
||||
proxy_pass ssh_{{ vhost.rap_dn | replace(".", "") }};
|
||||
}
|
||||
@ -1,18 +1,31 @@
|
||||
map $http_host $comun_{{ vhost.nodo | replace(".", "_") }} {
|
||||
map $http_host $comun_{{ vhost.rap_dn | replace(".", "") }} {
|
||||
hostnames;
|
||||
{% for domain in vhost.domains %}
|
||||
.{{ domain }} {{ vhost.nodo }};
|
||||
{% if vhost.root | default(false) %}
|
||||
{{ domain }} {{ vhost.rap_dn }};
|
||||
{% else %}
|
||||
.{{ domain }} {{ vhost.rap_dn }};
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
}
|
||||
|
||||
server {
|
||||
{% if vhost.root | default(false) %}
|
||||
server_name {{ vhost.domains | join(' ') }};
|
||||
{% else %}
|
||||
server_name .{{ vhost.domains | join(' .') }};
|
||||
{% endif %}
|
||||
|
||||
listen 80;
|
||||
|
||||
resolver 127.0.0.1 valid=300s;
|
||||
resolver {{ vpn_proxy }} valid=300s;
|
||||
resolver_timeout 5s;
|
||||
|
||||
{% if vhost.root | default(false) %}
|
||||
# ACME challenge for HTTP-01 validation (webroot method for root domains)
|
||||
include conf/acme_challenge.conf;
|
||||
{% endif %}
|
||||
|
||||
{% if not needs_vhost and ((vhost.ssl | default(domains_default_ssl) ) or (vhost.force_https | default(domains_default_force_https))) %}
|
||||
listen 443 ssl;
|
||||
|
||||
@ -38,7 +51,11 @@ server {
|
||||
|
||||
include conf/common.conf;
|
||||
|
||||
{% include "default_proxy.conf" %}
|
||||
{% if proxy_conf is defined and proxy_conf is is_file %}
|
||||
{{ proxy_conf_look }}
|
||||
{% else %}
|
||||
{% include "default_proxy.conf" %}
|
||||
{% endif %}
|
||||
|
||||
{% include "files/custom_server_includes/" ~ vhost.domains[0] ignore missing %}
|
||||
|
||||
|
||||
@ -1 +1,2 @@
|
||||
certs_data:
|
||||
certbot_webroot:
|
||||
|
||||
@ -1,15 +1,19 @@
|
||||
domains_default_ssl: no
|
||||
domains_default_force_https: no
|
||||
domains_default_enable_compression: no
|
||||
|
||||
# nginx
|
||||
vhosts_path: "{{ compose_path }}/proxy/vhosts"
|
||||
stream_path: "{{ compose_path }}/proxy/stream"
|
||||
conf_path: "{{ compose_path }}/proxy/conf"
|
||||
nginx_certs_path: /etc/nginx/certs
|
||||
|
||||
# defaults
|
||||
needs_vhost: no
|
||||
default_vhost: roles/proxy/templates/vhost.conf
|
||||
default_stream: roles/proxy/templates/stream.conf
|
||||
|
||||
# certbot
|
||||
webmaster_email: webmaster@numerica.cl
|
||||
CERTBOT_image: numericalatina/certbot-wildcard
|
||||
certbot_webroot: /var/www/certbot
|
||||
|
||||
1
roles/rap/code/rap
Submodule
1
roles/rap/code/rap
Submodule
Submodule roles/rap/code/rap added at 05481cdbc3
@ -1,16 +0,0 @@
|
||||
Address = latina.red
|
||||
Port = 65000
|
||||
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIICCgKCAgEAv0oPDlf8mbr8fbiLLfUEucm5QxFLxarqhuph/ui3PmDXoiJGQK0d
|
||||
zHl92dYDdgRMw+4b1ogThGUZ8ryAt3UtpD8B6oLCRmhGn2tjNIFQN3kUIJQ3aa+M
|
||||
5nEBf6ys0IHEieUYVHXr5lxSc09Y/wsNbtATVZ25VT0ercR0c3gbpcypu8JpTdyn
|
||||
iul43IXiO8zKjeQhn9VQAnwIMzAa+6Y5Aj4y2HtFsUqzjJYY3KZBRTTNR1277QJ8
|
||||
NDMuQT0opE79E8ipOZaOdcFRZIUOG8cBhhavozSVCzjI8A1iA8QrJpEjo/zjV+D4
|
||||
h5EQpztvvzYdlOsE/9Cclc+iAGbnxOUt6K2bopMu/TI+gNh7DoA2wgFZ7DlQhCuO
|
||||
MiYV+9dzI4gKZvAO0IxiGnmq8s2UjWRnD9zVZztU5IOE1xBo7OrmcHnnOvsMMsmx
|
||||
Bc8F8jR6u8XgfSODS22sNK62N9joC2E3Gg/ulW75IUqIlyyHumwjm0XMuIXI6qDZ
|
||||
AUv0lOnYOWATveQlgCqLO9OyJmocbejz1ZtkcLgI/EDzwDYEpaKLf+39a7eLuNRa
|
||||
sqf+BIoJkGxi6LVG8gW5YhOLaaPclmsOztiID7vPHs0jH4bY7N0JR2TI8aaIlY9O
|
||||
P6ZJArG60IPtMUvurTrSmUGdHLoSg6+PSPZLfYMXoqKatrAhdEcc9ssCAwEAAQ==
|
||||
-----END RSA PUBLIC KEY-----
|
||||
@ -1,16 +0,0 @@
|
||||
Address = tierra
|
||||
Port = 65000
|
||||
|
||||
-----BEGIN RSA PUBLIC KEY-----
|
||||
MIICCgKCAgEAtr75G3mVKBr8k7Sz5LQLuOBMdN2cwIZVQt0BVPq/gWeUowDPM8he
|
||||
QcjmSDZrwRE0NUQRiB5/Gicb9UXoQaEfq7xQfgcMl4Nt9MfHbhY6sORviAyHOsjM
|
||||
xYw/vy5SfWq3O7E/sH01BEbUt5r/oVoG2dy2rDQ5xBW30zeMJisvTMH5kMwHAWIG
|
||||
kdq0xI1WgFEa8eXo004Li8QD9k064wajN3mU0rUXEY0FCl9GbjP1S6a6ge3Sz+MP
|
||||
Je5RZzbNxvtY/YVeQBzjwUDawsjTZ9Lx968U9RaO2Z7LBrltLSSVU4aw6tH78zN8
|
||||
qVZ5PR0LmUQ38FWYNGcbUtfWRQACZOYkgBKbR0UOyLIbEODMUMmqZD7yOwAWf9BI
|
||||
Tw8NemFmkCs+Jb2LrayIOYaqvV3iY01oL2NgPhjV01XLs51GnHmiWUTfsEvu1lmM
|
||||
2uJoX75AzlL8We2RgWjknux3m4ce1sVTzMM36uatoz2lLDwBw9F6RKd2h6Gwb0kI
|
||||
k5ltlnjEttyQg/X1NowQClOfaUza+75mGaj1owK1zoYWZEUk4iRwoCT0KM1jnSKz
|
||||
z4w0uDz9YHhHDEG/evD6VLgPLcXdU2a+dKMU5GLGOcElKxi0p9bfzLJ9Efb2+PEY
|
||||
IJYfFlMT3YEacWsxLFuxUGbTbVCNccCIwv6QVQ8gnio+rowr8q64wwkCAwEAAQ==
|
||||
-----END RSA PUBLIC KEY-----
|
||||
38
roles/rap/tasks/client.yml
Normal file
38
roles/rap/tasks/client.yml
Normal file
@ -0,0 +1,38 @@
|
||||
# DHCLIENT ESTA DEPRCADO
|
||||
# https://serverfault.com/questions/1108989/isc-dhcp-client-dhclient-alternative
|
||||
- name: instalar dependecias de la RAP
|
||||
apt:
|
||||
name: ['tinc', 'rsync', 'dhcpcd5']
|
||||
state: latest
|
||||
# update_cache: yes
|
||||
tags: installation
|
||||
|
||||
- include_vars: dir="../vars" files_matching="main.yml"
|
||||
|
||||
- name: copiar el codigo fuente
|
||||
synchronize:
|
||||
src: ../roles/rap/code/rap/
|
||||
dest: "{{ rap_path }}"
|
||||
perms: true
|
||||
|
||||
- name: hacer ejecutable el archivo rap
|
||||
file:
|
||||
path: "{{ rap_path }}/rap"
|
||||
state: touch
|
||||
mode: '774'
|
||||
modification_time: preserve
|
||||
access_time: preserve
|
||||
|
||||
- name: inicializar el nodo
|
||||
shell:
|
||||
cmd: "./rap init -i {{ nodo }}"
|
||||
chdir: "{{ rap_path }}"
|
||||
environment:
|
||||
NETWORK: "{{ vpn_name }}"
|
||||
|
||||
- name: instalar el nodo
|
||||
shell:
|
||||
cmd: "./rap install -v {{ nodo }}"
|
||||
chdir: "{{ rap_path }}"
|
||||
environment:
|
||||
NETWORK: "{{ vpn_name }}"
|
||||
39
roles/rap/tasks/main.yml
Normal file
39
roles/rap/tasks/main.yml
Normal file
@ -0,0 +1,39 @@
|
||||
- name: instalar dependecias de la RAP
|
||||
apt:
|
||||
name: ['tinc', 'rsync', 'git']
|
||||
state: present
|
||||
tags: installation
|
||||
|
||||
- name: Verificar si ya existe el codigo fuente
|
||||
stat:
|
||||
path: "{{ rap_path }}"
|
||||
register: rap_status
|
||||
|
||||
- name: copiar el codigo fuente, si no existe
|
||||
synchronize:
|
||||
src: ../roles/rap/code/rap/
|
||||
dest: "{{ rap_path }}"
|
||||
perms: true
|
||||
rsync_opts:
|
||||
- "--exclude=.git"
|
||||
tags: rap
|
||||
when: not rap_status.stat.exists
|
||||
|
||||
- name: agregar nodos a la VPN
|
||||
shell:
|
||||
cmd: "./rap add-host {{ althost }} {{ nod }}"
|
||||
chdir: "{{ rap_path }}"
|
||||
args:
|
||||
creates: "{{ rap_path }}/networks/{{ vpn_name }}/abyayala/hosts/{{ nod }}"
|
||||
environment:
|
||||
NETWORK: "{{ vpn_name }}"
|
||||
with_items: "{{ item.nodos }}"
|
||||
loop_control:
|
||||
loop_var: nod
|
||||
|
||||
- name: actualizar la VPN
|
||||
shell:
|
||||
cmd: "./rap install -v {{ althost }}"
|
||||
chdir: "{{ rap_path }}"
|
||||
environment:
|
||||
NETWORK: "{{ vpn_name }}"
|
||||
1
roles/rap/vars/main.yml
Normal file
1
roles/rap/vars/main.yml
Normal file
@ -0,0 +1 @@
|
||||
rap_path: "/root/rap"
|
||||
1
tasks/files/ssh/berto.pub
Normal file
1
tasks/files/ssh/berto.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCrhho0oQcAWX6ndpwxkNykJTohUg6vvEplqBa5pENU1gD61eahP4BU4weGrOWY28fBy3BhXOYFITWOxmdv7V7T9fG8WKXqT8MHkC9zaLzAZJ11tHq8OeDo0QGkBOoetf0dv0e3+FNijA9QKhqiwz+v0t5Ev0bSuSl28zHI3Tr0vF98SZulIR9CxDTTPA+Hel2Tl+LcVDZb80/tG9oAFBctzMK7AWB80X/DgXVfY0qgP97809JPX+Cqo/Q+LK55HxeDnfqDsA3m3KXQPODZm6ATEfmcx3MBYqJ8m0rdMKBwR16xDvAyB/LezHVCgmQvmzTRgzTwwwitOX83F5oIEArTK64s1dm0VLzj+Pw5Tetkde4YPHfajffXUbUxGTgD6M3NCvCLHedDMQDQT3LNOfFJGngGcwWJdStmMCWR6dd81epzPZiWHEZ093UWCPtE8kvrL4fRfIc/qSKWNCIyAoagKw4SwwyOfg0ONBJpjOfI7+vBKJVCZSDZQYyU/+Bo60k= berto@concon
|
||||
1
tasks/files/ssh/chasqui.pub
Normal file
1
tasks/files/ssh/chasqui.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAII3J2KEOs3PN50dRiA69qci3XV8vUtbd13RWYjRZzAVV chasqui@laboportatil
|
||||
1
tasks/files/ssh/fauno.pub
Normal file
1
tasks/files/ssh/fauno.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIIOceAWSgtO+0pFhvhYGMlHTbpXIN1LDJK1Hx0qgw9qW fauno@local
|
||||
1
tasks/files/ssh/infinito.pub
Normal file
1
tasks/files/ssh/infinito.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJYJlf9XD7scKJIQX7ufxYSiZ9FALOiXPLy6g3oKyR56 infinito@fedora
|
||||
1
tasks/files/ssh/numerica.pub
Normal file
1
tasks/files/ssh/numerica.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCrhho0oQcAWX6ndpwxkNykJTohUg6vvEplqBa5pENU1gD61eahP4BU4weGrOWY28fBy3BhXOYFITWOxmdv7V7T9fG8WKXqT8MHkC9zaLzAZJ11tHq8OeDo0QGkBOoetf0dv0e3+FNijA9QKhqiwz+v0t5Ev0bSuSl28zHI3Tr0vF98SZulIR9CxDTTPA+Hel2Tl+LcVDZb80/tG9oAFBctzMK7AWB80X/DgXVfY0qgP97809JPX+Cqo/Q+LK55HxeDnfqDsA3m3KXQPODZm6ATEfmcx3MBYqJ8m0rdMKBwR16xDvAyB/LezHVCgmQvmzTRgzTwwwitOX83F5oIEArTK64s1dm0VLzj+Pw5Tetkde4YPHfajffXUbUxGTgD6M3NCvCLHedDMQDQT3LNOfFJGngGcwWJdStmMCWR6dd81epzPZiWHEZ093UWCPtE8kvrL4fRfIc/qSKWNCIyAoagKw4SwwyOfg0ONBJpjOfI7+vBKJVCZSDZQYyU/+Bo60k= berto@concon
|
||||
1
tasks/files/ssh/pirra.pub
Normal file
1
tasks/files/ssh/pirra.pub
Normal file
@ -0,0 +1 @@
|
||||
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQC6XFkmTCotjxvlwxcmXrZcs7nmY/gtgc4FQorge9EGBWBXDLy3+tMel0XzHu9P8vKGGPEiw9TjIyBG6sEujwq74+q3rR6w2WfELEXRfIyq7HXpWtmL7RUYRrz7syfCvof8YXAPbYGv/ai7IYI41VzOHaI3mliIX+T5R74954ksI72n/qzsYHdiMHkYOGcO8P/n6T2R/SIdXCkDeCuc47IPVjSb4jTC5elv6p5YPSTozEcRP2TgkjWAa+JHXhzbknHUv6qphJVVSn66O5TYZJBXfkM0v4+7sm8k6nMP7CFkvyAN/YuvL+ZDy3XXQacG7c39meXlCdW0czyhjsvJLyaoZoH5mXPJAQkTJO8bZhJTs26gOCih9mpjr9DjbLKEv85/qyKbzUCxoBqOeaD58De1g9csy0eFo2wMx4xczKKUoWDBswOL58AfXX9CV/pPMbgjIYrkcKzfVxxfeNH+UwNLaC+J1iiHX7V1vVK1D0hQOKbEH/LdOFEzUTmluLsOwd4OXc00cPzsfqal9tiJ9/FIP9fbcCg6z+8zkZaC07+9XpclnmN9Zm0mx7JLzeFgJU1N0ij3rEA399ZjQmcnXjtFM0tW0catBvBIKi7ltxZ+FeGTDoS3w4NhMJkfzs93OSjE2kBtROwHYDM1vUpv/nzNg/DaCJ9HA2VAx0C7sMOlUQ== pirra@drwagnerjr
|
||||
8
tasks/knot.yml
Normal file
8
tasks/knot.yml
Normal file
@ -0,0 +1,8 @@
|
||||
# Instalacion de KNOT - por ahora se ejecuta contra sutty, con variable host (local) e inventario especificado
|
||||
# ansible-playbook --become tasks/knot.yml -e "host=localhost alt=abyayala" -i hosts.local
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
tasks:
|
||||
- name: actualizacion de KNOT en el servidor DNS en la configuracion por vhost
|
||||
include_tasks: ../roles/knsupdate/tasks/loop.yml
|
||||
|
||||
@ -1,72 +1,8 @@
|
||||
# ansible-playbook rap.yml -e "host=hetzner"
|
||||
# Instalacion de la RAP en maquina local
|
||||
# ansible-playbook --become tasks/rap.yml -e "host=localhost nodo=chem" -i hosts.local
|
||||
# ansible-playbook tasks/rap.yml -e "host=testing nodo=testnet"
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
vars:
|
||||
rap:
|
||||
port: 65000
|
||||
rap_dir: "{{ directory | default('/root') }}"
|
||||
environment:
|
||||
PATH: "/usr/sbin:{{ ansible_env.PATH }}"
|
||||
tasks:
|
||||
|
||||
- name: install dependencies
|
||||
package:
|
||||
name: "{{ item }}"
|
||||
state: present
|
||||
loop:
|
||||
- rsync
|
||||
- git
|
||||
- tinc
|
||||
become: yes
|
||||
|
||||
- name: iptables
|
||||
iptables:
|
||||
action: append
|
||||
chain: INPUT
|
||||
table: filter
|
||||
destination_port: "{{ rap.port }}"
|
||||
protocol: "{{ item }}"
|
||||
jump: ACCEPT
|
||||
loop:
|
||||
- tcp
|
||||
- udp
|
||||
become: yes
|
||||
|
||||
- name: install rap
|
||||
git:
|
||||
repo: "https://0xacab.org/pip/rap.git"
|
||||
dest: "{{ rap_dir }}/rap"
|
||||
|
||||
- set_fact:
|
||||
hostname: "{% if '{{ host }} != localhost' %} {{ ansible_hostname }} {% else %} {{ inventory_hostname }} {% endif %}"
|
||||
# inventory_hostname=> localhost/IP | ansible_hostname=>infra
|
||||
|
||||
- name: node name
|
||||
shell: 'echo {{ hostname }} | tr -cd "[:alnum:]" | tr "[:upper:]" "[:lower:]"'
|
||||
register: node_name
|
||||
changed_when: false
|
||||
|
||||
- stat:
|
||||
path: "{{ rap_dir }}/rap/hosts/{{ node_name.stdout }}"
|
||||
register: node_exists
|
||||
|
||||
- name: init node
|
||||
when: "node_exists.stat.exists == False"
|
||||
shell: "cd {{ rap_dir }}/rap && ./rap init -f -a {{ hostname }} -p {{ rap.port }}"
|
||||
|
||||
- name: fetch hosts files
|
||||
fetch:
|
||||
flat: true
|
||||
src: "{{ rap_dir }}/rap/hosts/{{ node_name.stdout }}"
|
||||
dest: "./rap/hosts/{{ node_name.stdout }}"
|
||||
|
||||
- name: copy hosts files
|
||||
copy:
|
||||
src: "./rap/hosts/"
|
||||
dest: "{{ rap_dir }}/rap/hosts/"
|
||||
|
||||
- name: connectto
|
||||
shell: 'cd {{ rap_dir }}/rap && for host in ./hosts/*; do test "./hosts/{{ node_name.stdout }}" = "${host}" && continue ; basename "${host}" | xargs -r ./rap connectto "{{ node_name.stdout }}"; done'
|
||||
|
||||
- name: install node
|
||||
shell: "cd {{ rap_dir }}/rap && ./rap install {{ node_name.stdout }}"
|
||||
- name: instalacion de la RAP en maquina cliente
|
||||
include_tasks: ../roles/rap/tasks/client.yml
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
# ansible-playbook --vault-id @prompt users.yml -e "host=hetzner"
|
||||
# Creacion de usuarixs linux y publicacion de llaves ssh
|
||||
# ansible-playbook tasks/users.yml -e "host=localhost"
|
||||
---
|
||||
- hosts: "{{ host }}"
|
||||
tasks:
|
||||
- include_role:
|
||||
name: users
|
||||
- name: llamar al rol tasks
|
||||
include_tasks: ../roles/users/tasks/main.yml
|
||||
|
||||
22
testnet.yml
Normal file
22
testnet.yml
Normal file
@ -0,0 +1,22 @@
|
||||
althost: testnet
|
||||
matrix:
|
||||
- service_name: comun
|
||||
roles:
|
||||
- kemal
|
||||
domains:
|
||||
- comun.abyayala.red
|
||||
|
||||
- service_name: dns
|
||||
roles:
|
||||
- knsupdate
|
||||
|
||||
- service_name: vpn
|
||||
roles:
|
||||
- rap
|
||||
nodos:
|
||||
- qi
|
||||
|
||||
- nodo: qi
|
||||
ports:
|
||||
- 531
|
||||
# force_https: yes
|
||||
Reference in New Issue
Block a user