Saltar al contenido
Sistemas · Finalizado · May 2026

Infraestructura on-premise para un sistema de fichaje con RFID

Proyecto de Fin de Ciclo (ASIR): diseño y despliegue de toda la infraestructura para un control de asistencia presencial. Virtualización con Proxmox, red segmentada y firewall en MikroTik, VPN WireGuard, DNS firmado con DNSSEC, aplicación web propia (PHP/MySQL) y lectores RFID con ESP32.

Bash BIND9 DNS DNSSEC ESP32 Linux MikroTik MySQL NGINX PHP Proxmox RFID WireGuard

Objetivo técnico

Garantizar que un fichaje solo pueda originarse de forma presencial (pasando una tarjeta RFID por un lector físico en la sede) y nunca desde la web, construyendo para ello una infraestructura propia, segmentada, cifrada, monitorizada y documentada de principio a fin.

Descripción completa

Proyecto de Fin de Ciclo del ciclo de ASIR, calificado con un 9. Partía de un problema real de una empresa de formación con varias sedes: su control horario era una web a la que cualquiera podía acceder desde cualquier sitio, así que nada garantizaba que el empleado estuviera realmente en la oficina al fichar.

La solución que diseñé y desplegué cambia el enfoque por completo: el fichaje solo ocurre cuando una tarjeta RFID válida se acerca a un lector físico (ESP32 + RC522) instalado en la entrada de cada sede; la web pasa a ser únicamente un panel de gestión y consulta. Los lectores de las sedes remotas alcanzan el servidor central a través de una VPN WireGuard, de modo que el endpoint de fichaje nunca queda expuesto a internet.

El proyecto cubre la pila completa —virtualización, red, seguridad, servicios y desarrollo— sobre hardware propio y con software libre, y todo quedó documentado, monitorizado con alertas y respaldado con copias automáticas y su prueba de restauración.

Arquitectura y planteamiento

- Servidor físico con Proxmox VE 8.2 (Debian 12) virtualizando contenedores LXC no privilegiados.
- lxc-dns (10.10.10.10): BIND9 como resolver recursivo con DoH y autoritativo de las zonas internas firmadas con DNSSEC.
- lxc-web (10.10.10.20): aplicación de fichaje (Apache + PHP 8.2 + MySQL 8.0).
- lxc-proxy (10.10.10.30): NGINX como proxy inverso, termina TLS y exige mTLS en la ruta de la API.
- lxc-logs (10.10.20.40): centralización de logs (rsyslog + lnav) y destino de las copias de seguridad.
- Router MikroTik (RouterOS 7) como único punto de paso: firewall, VLANs 802.1Q y terminador de la VPN.
- Segmentación: VLAN 10 servicios (10.10.10.0/24), VLAN 20 gestión (10.10.20.0/24) y red lógica WireGuard (10.10.30.0/24).
- Lectores ESP32-WROOM-32 + módulo RC522 (RFID), uno por sede; las sedes remotas llegan al servidor por WireGuard.
- Salida a internet por NAT; ningún servicio interno publicado: el único acceso externo es el túnel WireGuard.

Pasos realizados

1. Instalación de Proxmox VE y despliegue de los contenedores LXC (DNS, web, proxy y logs).
2. Segmentación de la red en VLANs sobre un único enlace físico y diseño del firewall del MikroTik con política «denegar por defecto».
3. Microsegmentación: aislamiento entre VLANs, bloqueo de las redes domésticas ajenas (RFC1918) y AllowedIPs mínimos por peer.
4. Servidor DNS con BIND9: generación de claves KSK/ZSK (ECDSAP256SHA256), firma de zona, delegación con DS y validación con «delv».
5. Resolución externa con DoH (DNS over HTTPS) hacia 1.1.1.1.
6. CA propia y certificados con SAN; terminación TLS en NGINX y mTLS para los lectores en la ruta /api/.
7. VPN WireGuard con peers individualizados (administración, lector ESP32, invitado) y acceso por DDNS.
8. Aplicación web de fichaje (PHP + MySQL): roles (Administrador, RRHH y Empleado), usuarios, tarjetas, horarios, fichajes y ajustes de horas.
9. Endpoint /api/fichar.php: valida el token, localiza tarjeta y usuario, alterna Entrada/Salida y registra dispositivo e IP.
10. Firmware del ESP32 (C++/Arduino): WiFi, NTP, túnel WireGuard, lectura RFID y envío firmado al servidor.
11. Monitorización con alertas por Telegram y correo (chequeo diario de DNSSEC, vigilancia de expiración de firmas y de la integridad del trust-anchor).
12. Copias de seguridad automáticas (vzdump + mysqldump + rsync a lxc-logs) y prueba real de restauración.

Problemas encontrados

Fue un proyecto lleno de incidencias reales. Las más representativas: una cadena de confianza DNSSEC rota («broken trust chain») al validar la zona; el «VLAN filtering» del MikroTik activo pero con la lista de VLANs vacía, que descartaba en silencio todo el tráfico etiquetado; un bucle en el arranque de BIND al usar el nombre del servidor DoH en lugar de su IP; el certificado del servidor rechazado por no incluir SubjectAltName (SAN); una política CSP demasiado estricta que rompía los estilos; Wazuh, que no arrancaba en un LXC no privilegiado; y el clásico NAT loopback al probar la VPN desde la propia red.

Soluciones aplicadas

Regeneré las claves y la delegación DS/DNSKEY hasta que «delv» devolvió «fully validated», y añadí un chequeo diario que avisa por Telegram si la cadena se rompe. Declaré explícitamente las VLAN permitidas en el bridge del MikroTik. Rompí el bucle de arranque del DNS apuntando el upstream DoH a la IP literal 1.1.1.1 en lugar de al nombre. Reemití el certificado con SAN (nombre + IP). Relajé la CSP lo justo para los estilos manteniendo cerrado el origen de scripts. Ante las limitaciones de Wazuh en LXC no privilegiado opté, de forma pragmática, por rsyslog + lnav. Y validé la VPN desde fuera de la red (datos móviles) para descartar el NAT loopback.

Aprendizajes

El aprendizaje principal es que la seguridad no se añade al final: atraviesa cada decisión, desde el plan de direccionamiento hasta el orden en que arrancan los servicios. Pensarla por capas (segmentación + firewall + VPN + DNS firmado + backups) marca la diferencia. También aprendí que instalar y configurar el entorno y depurar incidencias «tontas» (permisos, certificados, codificaciones) lleva tanto tiempo como programar, y que documentarlo todo con honestidad es lo que convierte un montaje frágil en algo mantenible. Por último, probar la restauración de una copia es tan importante como hacerla.