RAND_bytes() failed es una afirmación sobre una primitiva local, no sobre la cuenta, la clave precompartida ni el puerto remoto. Dos fallos muy distintos producen esa misma línea y dejan pruebas diferentes. Uno es un motor criptográfico que se niega a emitir bytes; el otro es un proceso que no alcanza la fuente de entropía para la que se compiló su código. Separarlos exige una lectura de la cola de errores y una mirada a la vista del sistema de archivos del propio proceso enjaulado, y esa comprobación va antes de crear nada bajo /dev.

Qué distingue el valor de retorno

El contrato documentado separa tres resultados, no dos: 1 para el éxito, -1 cuando el método RAND cargado no admite la petición, y 0 para los demás fallos, con la explicación reservada a la cola de errores. La referencia de RAND_bytes añade un punto fácil de pasar por alto: el generador predeterminado se siembra desde el sistema operativo en las plataformas compatibles, y cuando esa siembra falla se queda en un estado de error en lugar de devolver bytes predecibles.

Solo uno de esos números describe el entorno. Un -1 es una cuestión de compilación, de proveedor o de funcionalidad, porque el código pidió algo que la implementación activa no ofrece. Un 0 con una queja de siembra es una cuestión de entorno, porque el generador no pudo obtener entropía en absoluto. El número por sí solo nunca dice cuál de las dos cosas, y el nombre de la función tampoco.

Cuándo un nodo de dispositivo oculto es la causa real

Un servicio confinado ve un árbol distinto del shell en el que escribes. Las jaulas chroot, las imágenes de contenedor y las unidades endurecidas presentan a menudo un /dev con menos nodos que el del anfitrión. Si la implementación que falla abre /dev/urandom por su ruta, esa diferencia basta para romper el arranque mientras el anfitrión parece perfectamente sano. Un dispositivo que existe fuera de la jaula no demuestra nada sobre lo que el proceso enjaulado tiene permitido abrir.

No toda interfaz aleatoria necesita una ruta, sin embargo. La llamada al sistema getrandom de Linux no acepta ningún nombre de archivo ni descriptor de archivo, y su página de manual señala que esa propiedad es útil precisamente donde un chroot oculta las rutas de los dispositivos.

Así que la explicación del nodo ausente es una hipótesis sobre una rama del código, no una regla sobre los números aleatorios en general. Se sostiene cuando las pruebas nombran una ruta, y es conjetura cuando las pruebas nombran otra cosa.

Leer la cola de errores y después la vista del proceso

La forma más rápida de zanjar la cuestión es leer lo que la biblioteca ya registró y luego mirar directamente la vista enjaulada. Empieza por la compilación de OpenSSL que el servicio cargó realmente, porque las pilas de proveedores difieren entre versiones mayores y entre distribuciones. Pregunta después a systemd qué proceso se está ejecutando y qué restricciones se le aplican. Solo cuando ambos hechos estén sobre la mesa merece la pena listar los nodos que ese proceso puede ver.

openssl version -a
systemctl show openvpn-server@lab -p MainPID -p PrivateDevices -p DevicePolicy
pid=$(systemctl show -p MainPID --value openvpn-server@lab)
sudo ls -l /proc/"$pid"/root/dev/urandom /proc/"$pid"/root/dev/random

Ejecuta esas lecturas contra el mismo proceso, no contra el shell que resulte estar abierto. Comparar el /dev del anfitrión con la vista de un proceso ajeno es cómo se repara dos veces la dependencia equivocada.

Añadir la dependencia solo cuando puedas nombrarla

Cuando las pruebas sí nombran una ruta, la reparación es pequeña: deja disponible esa única ruta dentro de la jaula y no toques nada más. Un montaje bind del nodo único suele bastar, y mknod con los números mayor y menor estándar del nodo produce el mismo resultado en instalaciones donde el montaje no es una opción. Ampliar el entorno aislado, conceder acceso a todos los dispositivos de caracteres o desactivar PrivateDevices cambia una corrección puntual por una regresión de seguridad permanente.

Un demonio de entropía no sustituye esa reparación. Paquetes como haveged cambian cómo se alimenta el grupo del núcleo; no pueden crear una ruta que un proceso enjaulado tenga permitido abrir. Instalar uno puede hacer que un gráfico de salud se vea mejor mientras la llamada de apertura sigue fallando. Mantén los dos problemas separados, o el siguiente fallo volverá a atribuirse a la capa equivocada.

Verifica el generador y el túnel por separado

Un reinicio es la única prueba que reutiliza la misma configuración, el mismo archivo de unidad y el mismo confinamiento que produjeron el fallo. Ejecútalo y luego lee las entradas más recientes del diario en lugar de una muestra de un arranque anterior.

sudo systemctl restart openvpn-server@lab
sudo journalctl -u openvpn-server@lab --since -5min --no-pager | grep -iE 'rand|entropy|Initialization Sequence'

Busca dos cosas separadas en esa salida: que el mensaje de la fuente aleatoria desaparezca y que el túnel alcance su hito habitual de arranque. Un generador que vuelve a funcionar elimina un fallo local y no dice nada sobre la identidad del servidor, las credenciales ni el enrutamiento. Prueba eso con la misma configuración de cliente que fallaba antes, para que el resultado sea comparable y no solo mejor.

Artículos relacionados