
🌐 También en: English · Deutsch · Français
Mi homelab tiene tres controladores de dominio, dos clientes, tres placas de gestión iLO y, hasta la semana pasada, exactamente cero certificados en los que alguien tuviera motivos para confiar. Cada sesión RDP empezaba con una advertencia, cada iLO me recibía con «La conexión no es privada» (emisor: Default Issuer (Do not trust), que al menos es honesto), y los controladores de dominio no hablaban LDAPS en absoluto.
No tengo muchos servicios web internos, así que durante un tiempo pensé que una PKI privada era una solución en busca de un problema. Error. Un dominio Windows tiene un montón de sitios donde los certificados mejoran las cosas sin hacer ruido. El truco está en dejar que Active Directory los reparta por su cuenta, para no tener que volver a pensar nunca en renovarlos.
El mismo flujo de trabajo que en los artículos anteriores sobre Windows: yo decido, y mi coadministrador de IA (Claude, que maneja PowerShell por WinRM y los iLO por Redfish) lo construye y verifica cada paso. Esta vez la verificación incluyó comprobar nuestros propios handshakes TLS desde una máquina Linux con openssl s_client.
🎯 Qué se beneficia de verdad de los certificados
- Controladores de dominio: con un certificado «Kerberos Authentication» hablan LDAPS en el puerto 636 y pueden hacer Kerberos basado en certificados (requisito previo para cosas como Windows Hello for Business).
- Escritorio remoto: RDP usa un certificado autofirmado por máquina. Con uno emitido por la CA desaparece el diálogo «no se puede comprobar la identidad del equipo remoto», y una advertencia real de ataque de intermediario volvería a significar algo.
- WinRM sobre HTTPS (5986): mi automatización iba por HTTP con el cifrado de mensajes de NTLM. Funciona, pero TLS de verdad con una identidad de servidor verificable es mejor.
- Interfaces web de los iLO: las clásicas páginas de «pasar de la advertencia con un clic».
- Firma de código: un certificado para mí, para poder firmar mis scripts de inicio de PowerShell y, con el tiempo, permitir que solo se ejecuten scripts firmados.
Fuera de la lista: todo lo público. Nextcloud y el blog se quedan con Let’s Encrypt, porque en una raíz privada solo confían mis propios dispositivos, y de eso se trata.
🏛️ Diseño: un solo nivel, en un DC, y por qué es un compromiso
La PKI de manual tiene dos niveles: una CA raíz offline que está apagada en un cajón y solo firma la CA emisora, más una CA emisora que hace el trabajo diario. Si la CA emisora se ve comprometida, la revocas y la raíz sobrevive.
Yo monté una Enterprise Root CA de un solo nivel: «Muench Homelab Root CA», RSA 4096, SHA-256, válida 10 años, en HP3. Es un compromiso consciente. Mis tres servidores son controladores de dominio, y una CA en un DC tiene inconvenientes reales: el servidor ya no se puede renombrar y degradarlo se complica. Sin servidor miembro y sin hipervisor, ahora mismo no hay mejor hogar para ella. Cuando llegue un hipervisor, una arquitectura de dos niveles con una VM raíz offline será el siguiente paso natural.
Tres decisiones antes del primer clic:
CAPolicy.infconLoadDefaultTemplates=0. Sin esto, una Enterprise CA recién instalada publica de inmediato una docena de plantillas predeterminadas con derechos de inscripción generosos. En esos valores predeterminados viven la mayoría de los vectores de ataque conocidos contra AD CS. Mi CA arrancó con cero plantillas publicadas.- Listas de revocación y certificado de la CA solo por LDAP. Las extensiones CDP/AIA predeterminadas apuntan también a
http://<ca>/CertEnroll/, un servidor web que aquí no existe. Los clientes lo intentarían y acabarían en timeout. Todos los clientes de este dominio pueden leer LDAP, así que HTTP fuera. - Sin inscripción web. Las viejas páginas
/certsrvson el objetivo del ataque de retransmisión NTLM conocido como ESC8. Ni instalado ni necesario.
Además, la higiene aburrida: auditoría de la CA activada y certificados emitidos limitados a dos años. Y la base de datos de la CA forma parte de la copia de seguridad nocturna del estado del sistema de HP3, que existe desde el artículo anterior.
📜 Plantillas: pequeñas, estrictas y explícitas
Una plantilla de certificado decide qué puede hacer un certificado y quién puede solicitarlo. Equivocarse con el «quién» es la forma en que caen los dominios: el famoso ESC1 es una plantilla en la que un usuario con pocos privilegios puede poner cualquier nombre en la solicitud, incluido el de un administrador del dominio. Así que hay cuatro plantillas, cada una con los derechos más restringidos que todavía funcionan:
| Plantilla | Finalidad | Sujeto | Quién puede inscribirse |
|---|---|---|---|
| Kerberos Authentication (integrada) | Certificados de DC: LDAPS, Kerberos | desde AD | Domain Controllers (auto) |
| HomelabComputer | RDP, WinRM HTTPS | desde AD (CN + SAN DNS = FQDN) | Domain Computers + DC (auto) |
| HomelabWebServer | iLO, más adelante Windows Admin Center | indicado en la solicitud | solo Domain Admins, manual |
| HomelabCodeSigning | firma de scripts de PowerShell | desde AD | yo (auto, al iniciar sesión) |
La plantilla WebServer es la peligrosa, porque el solicitante elige el nombre. Precisamente por eso solo los Domain Admins pueden usarla. Y el flag de la CA EDITF_ATTRIBUTESUBJECTALTNAME2 (ESC6, «dejar que los solicitantes añadan cualquier SAN como atributo de la solicitud») sigue desactivado. Los nombres salen del propio CSR, y eso basta para los iLO.
Crear plantillas sin interfaz gráfica (y tres trampas)
PowerShell no tiene New-CATemplate. El «Duplicar plantilla» de la MMC en realidad no es más que copiar un objeto de AD: un pKICertificateTemplate bajo CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration, más un objeto msPKI-Enterprise-Oid a juego con un OID nuevo bajo la base de OID del bosque. Así que eso hicimos, atributo a atributo: versión de esquema 2, flags de nombre, flags de inscripción, EKU y luego la ACL con los derechos extendidos Enroll y AutoEnroll. Por el camino:
- Las variables de PowerShell no distinguen entre mayúsculas y minúsculas.
$Eguardaba el GUID de Enroll,$eera la variable del bucle. Adivina cuál ganó. - PowerShell desenrolla los arrays de un solo elemento.
@(@('512','manual'))no es una lista que contiene un par, es el propio par, así que el bucle intentó alegremente resolver el usuario «5». La solución es la coma unaria:@(,@('512','manual')). Add-CATemplatese empeñaba en que las plantillas recién creadas «no existen en el dominio», mientrascertutil -templatelas listaba sin problema.certutil -SetCATemplates +HomelabComputer,…las publicó a la primera.
Y el clásico de siempre: WinRM envía los scripts como Base64 UTF-16 en una línea de comandos limitada a 8191 caracteres. Un script de plantilla creció de 2.970 a 3.170 caracteres y dejó de hacer nada en absoluto, sin avisar. Ni error ni salida. Mi coadministrador ahora cuenta caracteres antes de enviar. Yo también.
🤖 Inscripción automática: la parte en la que AD hace el trabajo
Una GPO, homelab – PKI Auto-Enrollment, vinculada en la raíz del dominio: inscripción automática para equipos y usuarios, con «renovar certificados caducados» y «actualizar certificados pendientes» activados. Tras un gpupdate y un certutil -pulse, cada DC tenía en menos de un minuto dos certificados nuevos: Kerberos Authentication y HomelabComputer, con el FQDN correcto y válidos un año. La renovación se produce seis semanas antes de la caducidad y nadie tiene que acordarse de nada.
Los DC adoptaron el certificado Kerberos para LDAPS automáticamente, sin ninguna configuración: en cuanto hay un certificado adecuado en el almacén del equipo, el puerto 636 responde.
RDP: la directiva que no hacía nada
Hay una directiva de grupo hecha exactamente para esto: Plantilla de certificado de autenticación de servidor. RDP debería inscribir un certificado a partir de esa plantilla y usarlo. Estaba configurada, verificada en el registro, SessionEnv reiniciado, TermService reiniciado en los servidores sin sesiones, y RDP seguía presentando su certificado autofirmado. Ni un solo evento en ningún registro explicaba por qué.
En lugar de depurar un mecanismo invisible, tomamos el camino determinista: un pequeño script de inicio en la misma GPO. En cada arranque elige el certificado HomelabComputer válido más reciente y lo vincula a RDP (Win32_TSGeneralSetting.SSLCertificateSHA1Hash). El mismo script crea o actualiza el listener WinRM HTTPS con ese certificado, y la GPO añade una regla de cortafuegos para el 5986, solo LAN. Las máquinas se reinician cada mes por los parches y la renovación empieza seis semanas antes, así que un certificado renovado siempre queda vinculado a tiempo. El script escribe su log en %ProgramData%\homelab\pki-bind.log, porque «seguramente se ejecutó» no es un estado.
🔌 Certificados de iLO por Redfish
Los iLO no son miembros del dominio, así que no hay inscripción automática. Pero iLO 5 puede generar su propia clave y su CSR, y todo ello se puede automatizar por Redfish:
POST …/SecurityService/HttpsCert/Actions/HpeHttpsCert.GenerateCSRcon el FQDN como nombre común eIncludeIP: true. Entre diez y treinta segundos después, el CSR aparece enCertificateSigningRequest. Contiene una clave de 2048 bits y SAN para el nombre DNS y la dirección IP. La clave privada nunca sale del iLO.- En la CA:
certreq -submit -attrib "CertificateTemplate:HomelabWebServer". …/HpeHttpsCert.ImportCertificatecon el PEM. El iLO se reinicia solo; el host ni se entera.
Adiós, Default Issuer (Do not trust). Como el certificado incluye tanto el nombre como la IP, el iLO es de confianza de cualquiera de las dos formas. Eso importa cuando lo que intentas arreglar es precisamente el DNS.
✅ Confía, pero verifica (con OpenSSL)
Los miembros del dominio confían automáticamente en la nueva raíz: una Enterprise CA publica su certificado en AD y la directiva de grupo lo distribuye. Como prueba, exporté la raíz a la máquina Linux de copias de seguridad y comprobé cada endpoint como lo haría un cliente estricto, con verificación del nombre:
openssl s_client -connect 192.168.10.30:636 -CAfile muench-homelab-root-ca.crt
\
-verify_hostname HP1-dc01.muench.home.arpa # Verify return code: 0 (ok)| Endpoint | HP1 | HP2 | HP3 |
|---|---|---|---|
| LDAPS :636 | ✅ | ✅ | ✅ |
| WinRM HTTPS :5986 | ✅ | ✅ | ✅ |
| Certificado RDP emitido por la CA | ✅ | ✅ | ✅ |
| iLO :443 por nombre y por IP | ✅ | ✅ | ✅ |
Nueve certificados emitidos hasta ahora: tres para Kerberos, tres para los equipos y tres para los iLO. Los dos clientes vendrán en su próximo arranque, y mi certificado de firma de código en mi próximo inicio de sesión.
🧭 Próximos pasos
- Forzar la firma LDAP y el channel binding. Con LDAPS funcionando, se acabó la última excusa. Es una sola opción de seguridad en la Default Domain Controllers Policy, y esa opción sobrescribe sin avisar cualquier valor del registro que pongas por la vía «lista».
- Firmar los scripts de inicio con el nuevo certificado de firma de código y luego pasar la directiva de ejecución de Bypass a AllSigned.
- Windows Admin Center en la estación de administración, con un certificado de la plantilla WebServer en lugar de su certificado autofirmado predeterminado.
- Dos niveles, en cuanto haya un hipervisor: una VM raíz offline que firme una nueva CA emisora y vuelva a dormirse.
🎯 Conclusión
Una PKI privada sonaba a exceso empresarial para un homelab casi sin servicios web internos. En la práctica, el cliente era el propio dominio: DC, RDP, WinRM, iLO. Lo mejor es que, tras la configuración, nada de esto requiere atención. Los certificados aparecen, se renuevan y se vinculan solos. Lo difícil no es instalar una CA; es lo que no publicas, a quién no dejas inscribirse y los flags que dejas desactivados. La seguridad, como siempre, es sobre todo el arte de decir que no. 🔏





