Su VPN responde conexiones a las 3 de la madrugada mientras la máquina que firma sus certificados está apagada en un cajón. Un cliente que valida el certificado del servidor nunca contacta con su CA, así que la CA no necesita ser accesible para ninguna conexión. La parte que requiere planificación es el día en que hay que emitir, renovar o revocar un certificado mientras la clave raíz permanece bajo llave.

Qué valida realmente una conexión

Cuando el cliente OpenVPN se conecta, recorre la cadena de firmas desde el certificado hoja del servidor hasta un certificado de CA en el que ya confía, comprueba la ventana de validez y, si el perfil lo indica, consulta una lista de revocación. Nunca busca su CA raíz. El servidor hace la imagen especular para los certificados de cliente. En el momento de la conexión solo están presentes el certificado hoja, el intermedio y el paquete de confianza que distribuyó antes.

Lo que realmente falla es una de tres cosas: la clave de firma no está disponible en la emisión, una lista de revocación ha quedado obsoleta o el paquete de confianza del cliente es más antiguo que la cadena que presenta el servidor. La primera es un problema de proceso; las otras dos son problemas de distribución. Ninguna de ellas exige que la clave raíz esté en línea, y un servicio VPN gestionado que exige un certificado privado para la autenticación del túnel solo traslada la autoridad de firma al proveedor. Azure punto a sitio funciona al revés: se carga un certificado raíz y los certificados firmados bajo él se consideran de confianza, así que pregunte quién firma, quién valida y cómo se retira un certificado antes de tiempo.

Construya la raíz en un host que nunca recibe una dirección

Una raíz sin conexión se usa rara vez: para firmar el certificado de la CA intermedia y, más adelante, para renovarlo o revocarlo. Todo lo demás ocurre un nivel más abajo. Haga el trabajo de la raíz en una máquina mantenida fuera de la red, a ser posible desde un sistema vivo, y anote quién estaba en la sala. Los comandos suponen OpenSSL 1.1.1 o posterior, porque -addext no está disponible en compilaciones antiguas.

openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out root.key
openssl req -x509 -new -key root.key -sha256 -days 7300 \
  -subj "/CN=Example VPN Root CA" -out root.crt \
  -addext "basicConstraints=critical,CA:TRUE" \
  -addext "keyUsage=critical,keyCertSign,cRLSign"

Cree la intermedia en el host de firma y lleve solo su solicitud a la máquina sin conexión. La raíz firma esa solicitud con una longitud de ruta cero, de modo que la CA intermedia puede firmar certificados de punto final pero no puede crear otra CA por debajo. Esa única extensión impide que un host de firma comprometido acuñe una autoridad equivalente a la raíz. Use ECDSA solo si todos los clientes ejecutan OpenVPN 2.4 o posterior; de lo contrario, genere claves RSA y mantenga el flujo idéntico.

openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out intermediate.key
openssl req -new -key intermediate.key -subj "/CN=Example VPN Intermediate CA" -out intermediate.csr
openssl x509 -req -in intermediate.csr -CA root.crt -CAkey root.key \
  -CAcreateserial -days 3650 -sha256 -extfile intermediate.ext -out intermediate.crt

intermediate.ext contiene basicConstraints=critical,CA:TRUE,pathlen:0, keyUsage=critical,keyCertSign,cRLSign y authorityKeyIdentifier=keyid:always. Devuelva la clave raíz a su caja fuerte antes de reconectar el host de firma. Si la raíz debe poder revocar la intermedia, fírmela con openssl ca -config root.cnf -extensions intermediate_ca contra un index.txt de nivel raíz en lugar de openssl x509 -req, para que el número de serie quede registrado; después envíe la lista raíz resultante dentro del perfil del cliente, donde un crl-verify basado en archivo la lee al arrancar. Envíe a los clientes un paquete con los dos certificados de CA; un certificado hoja por sí solo no se validará contra la raíz.

Emita hojas desde la intermedia, con una base de datos

Firmar con openssl x509 -req funciona hasta que necesite revocar, porque nada registra el número de serie. Use openssl ca desde el primer certificado para que el número de serie, la caducidad y el estado de revocación vivan en una sola base de datos. Cree los archivos de la base de datos una vez y luego apunte allí la configuración:

mkdir -p /etc/vpn-ca/intermediate/newcerts
touch /etc/vpn-ca/intermediate/index.txt
echo 1000 > /etc/vpn-ca/intermediate/serial
echo 1000 > /etc/vpn-ca/intermediate/crlnumber
[ ca ]
default_ca = CA_default
[ CA_default ]
dir = /etc/vpn-ca/intermediate
database = $dir/index.txt
new_certs_dir = $dir/newcerts
serial = $dir/serial
crlnumber = $dir/crlnumber
certificate = $dir/intermediate.crt
private_key = $dir/intermediate.key
default_md = sha256
default_days = 365
default_crl_days = 30
unique_subject = no
policy = policy_any
[ policy_any ]
commonName = supplied
[ server_cert ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @server_names
[ client_cert ]
basicConstraints = CA:FALSE
keyUsage = critical, digitalSignature
extendedKeyUsage = clientAuth
[ server_names ]
DNS.1 = vpn.example.com

La línea de uso de clave supone una clave ECDSA; añada keyEncipherment para RSA. Dé a cada cliente su propio nombre común, porque OpenVPN identifica una conexión por ese campo, y dos portátiles que comparten CN=vpn-client no se pueden distinguir en los registros, en las reglas de client-config-dir ni en ningún envío por usuario, y pierde la atribución que hace defendible una decisión de revocación. Emita y valide un certificado hoja así:

openssl req -new -key alice.key -subj "/CN=alice-laptop" -out alice.csr
openssl ca -config intermediate.cnf -extensions client_cert -in alice.csr -out alice.crt -batch
openssl verify -CAfile ca-bundle.crt -untrusted intermediate.crt alice.crt

Mantenga la clave de firma detrás de una frontera de política en lugar de copiarla al host de VPN: un servicio pequeño que autentica la solicitud, comprueba el nombre común contra una lista de permitidos y devuelve solo el certificado. Registre cada número de serie; el registro es el único vínculo entre un certificado y la persona que lo solicitó.

Publique la revocación sin despertar la raíz

Los certificados de cliente los revoca la intermedia, nunca la raíz. La lista raíz solo importa cuando se quema una intermedia. Apunte el servidor a la lista intermedia con crl-verify. Una CRL basada en archivo se carga al iniciar el servicio, así que recárguela después de cada regeneración; la forma de directorio lee el estado en el momento de la conexión y cuesta un archivo por número de serie.

Revoque y regenere con dos comandos de la misma base de datos:

openssl ca -config intermediate.cnf -revoke /etc/vpn-ca/intermediate/newcerts/1001.pem
openssl ca -config intermediate.cnf -gencrl -out /etc/openvpn/crl.pem

Luego vigile el reloj. Una CRL lleva un campo de próxima actualización, y cuando esa fecha pasa, un par que valida rechaza la lista en lugar de ignorarla. Regenerar mensualmente con default_crl_days = 30 deja margen; regenerar anualmente no. Unos tiempos de vida de hoja más cortos son el control más fiable, porque la revocación solo se aplica donde se consulta la lista.

Pruebe la cadena y luego escriba la ceremonia

Reproduzca cuatro fallos antes de confiar en el diseño. Valide la cadena con openssl verify -CAfile ca-bundle.crt -untrusted intermediate.crt server.crt. Conéctese con un certificado de cliente caducado y confirme que el servidor lo rechaza. Revoque un cliente de prueba, recargue y confirme que la lista surte efecto. Adelante un día el reloj de un host, porque un reloj incorrecto puede emitir y rechazar certificados que parecen válidos en otro lugar.

Una raíz sin conexión solo es un control si existe el papeleo: dos personas nombradas para la ceremonia, un registro de cada número de serie firmado, una copia de seguridad cifrada guardada aparte de la máquina y una prueba de restauración en un host aislado. Firme una intermedia de repuesto durante la misma ceremonia para que un host de firma muerto no le obligue a desbloquear la raíz a medianoche.

Antes de darlo por terminado, confirme cinco cosas: la clave raíz no está en un host en red, la clave intermedia solo vive en el host de firma, el paquete del cliente lleva los dos certificados de CA, la CRL tiene una próxima actualización futura y alguien posee una entrada de calendario para cada caducidad de la cadena. Si falta una, la configuración que parece sin conexión solo está indocumentada.

Artículos relacionados