Sitios como este nos animan a colaborar para que todos podamos disfrutar de productos excepcionales como Issabel. Por favor, perdonad los errores que haya podido cometer y no dudéis en publicarlos. Espero que os sea útil. Un saludo para todos.
OpenVPN deja de funcionar en Issabel
Hemos configurado OpenVPN y todas las extensiones externas están funcionando, pero al cabo de un tiempo, todas ellas dejan de hacerlo.
Lo primero que tenemos que comprobar es que nuestro proveedor de acceso a internet no nos haya capado este puerto (1194 UDP). No lo descartéis, comprobadlo.
En mi caso, como dispongo de un cortafuegos perimetral en el que he abierto un agujero (he definido una regla) al NAT para dicho puerto, he definido una política de seguridad para las entradas hacia Issabel por este puerto, registrando en el log todos los intentos. Esto me ha permitido comprobar que mi proveedor no me capaba dicho puerto (o que me lo había vuelto a activar).
Comprobamos que nuestra centralita Issabel tiene acceso a internet (por ejemplo haciendo una llamada externa a través de un troncal SIP, a través del panel de Issabel, ejecutando “ping 8.8.8.8” desde el panel o desde el shell, etc.).
Por descarte, y entendiendo que los certificados de los teléfonos externos caducan en diferentes fechas (procurad que sea así o comprobadlo en Issabel), tenemos que suponer que el fallo está en el lado servidor, es decir, en OpenVPN en nuestra centralita Issabel.
Comprobamos estado de OpenVPN
Accedemos al shell de nuestra centralita
ssh root@direccion_ip_de_mi_centralita
systemctl status openvpn@* -l
Detrás de la @ se especifica el fichero de configuración, el * le indica que tome cualquier archivo .conf, la opción -l es la forma extendida del comando para mostrar más información.
Salida del comando
● openvpn@server.service - OpenVPN Robust And Highly Flexible Tunneling Application On server
Loaded: loaded (/usr/lib/systemd/system/openvpn@.service; enabled; vendor preset: disabled)
Active: active (running) since jue 2021-12-02 13:00:21 CET; 1 months 3 days ago
Main PID: 855 (openvpn)
Status: "Initialization Sequence Completed"
CGroup: /system.slice/system-openvpn.slice/openvpn@server.service
└─855 /usr/sbin/openvpn --cd /etc/openvpn/ --config server.conf
… :55774 TLS Error: TLS object -> incoming plaintext read error
… :55774 TLS Error: TLS handshake failed
… :55774 SIGUSR1[soft,tls-error] received, client-instance restarting
… : Initial packet from [AF_INET] :55746, sid=
… :55746 VERIFY ERROR: depth=0, error=CRL has expired: C=ES, ST=CC, L=… , O=… , OU=Informatica, CN=… , name=centralita.telefonia.midominio.local, emailAddress=informatica@midominioexterno, serial=5
… :55746 OpenSSL: error:14089086:SSL routines:ssl3_get_client_certificate:certificate verify failed
… :55746 TLS_ERROR: BIO read tls_read_plaintext error
… :55746 TLS Error: TLS object -> incoming plaintext read error
… :55746 TLS Error: TLS handshake failed
...:55746 SIGUSR1[soft,tls-error] received, client-instance restarting
[root@issabel ~]#
He recortado la salida, pero podéis comprobadla ejecutando el comando en vuestra centralita.
En muchos sitios de internet nos informan de este problema, como por ejemplo
https://stackoverflow.com/questions/69990400/cant-connect-to-openvpn
Lo que probablemente ocurre es que nuestro certificado crl.pem haya expirado.
Qué es crl.pem
En
https://openvpn.net/community-resources/revoking-certificates/
dice
The revoke-full script will generate a CRL (certificate revocation list) file called crl.pem in the keys subdirectory. The file should be copied to a directory where the OpenVPN server can access it, then CRL verification should be enabled in the server configuration:
crl-verify crl.pem
Now all connecting clients will have their client certificates verified against the CRL, and any positive match will result in the connection being dropped.
Comprobamos estado del certificado
Los certificados están en
/usr/share/easy-rsa/2.0/keys
El certificado/fichero
crl.pem
también está en
/etc/openvpn
Este es el que se usa, ya que a él se hace referencia en /etc/openvpn/server.conf. No obstante comprobamos el estado de ambos (aunque es el mismo).
Aquí debe estar:
# cd /etc/openvpn
# openssl crl -inform PEM -text -noout -in crl.pem
Aquí se genera:
# cd /usr/share/easy-rsa/2.0/keys
# openssl crl -inform PEM -text -noout -in crl.pem
En ambos casos la salida debería ser igual por tratarse del mismo certificado.
Nos fijamos en una línea tal como
Next Update: Oct 10 07:48:30 2021 GMT
Estoy realizando estas pruebas en 2022, por lo que este certificado está caducado, ya que, como indica, debería haberse actualizado, como muy tarde, el 10 de octubre de 2021 a las 07:48:30 en horario de Greenwich.
Es muy importante tener en cuenta que, como indico en el párrafo anterior, se nos muestra la información en horario de Greenwich, mientras que nosotros tendremos definida la zona horaria de nuestro país o región.
Posibles soluciones
En el apartado anterior “Qué es crl.pem” o más concretamente en
https://forums.openvpn.net/viewtopic.php?t=30780
dicen
Make a new CRL.
Otherwise don't use a CRL at all.
Find Your openvpn server config file and remove the CRL Verify stage.
O sea, tenemos dos soluciones: no usar crl o regenerar crl.pem.
Opcion 1: No usar crl-verify
# vi /etc/openvpn/server.conf
Comentamos la última línea para que quede tal como así
# crl-verify /etc/openvpn/crl.pem
Y reiniciamos OpenVPN
# systemctl restart openvpn@server.service
Opción 2: regenerar crl.pem
Volvemos a analizar lo de antes:
The revoke-full script will generate a CRL (certificate revocation list) file called crl.pem in the keys subdirectory. The file should be copied to a directory where the OpenVPN server can access it, then CRL verification should be enabled in the server configuration:
crl-verify crl.pem
Now all connecting clients will have their client certificates verified against the CRL, and any positive match will result in the connection being dropped.
Nos están informando de dos cosas:
- crl.pem es generado en el directorio keys y debe ser copiado a /etc/openvpn.
- crl.pem es generado por el script (guion) revoke-full.
El script revoke-full está en
/usr/share/easy-rsa/2.0/revoke-full
Este es el script que genera el nuevo crl.pem. Concretamente estas líneas
$OPENSSL ca -gencrl -out "$CRL" -config "$KEY_CONFIG"
if [ -e export-ca.crt ]; then
cat export-ca.crt "$CRL" >"$RT"
else
cat ca.crt "$CRL" >"$RT"
fi
Observamos que se están utilizando una serie de variables, definidas:
• En el mismo guion
CRL="crl.pem"
RT="revoke-test.pem"
• En /usr/share/easy-rsa/2.0/vars
KEY_CONFIG=/usr/share/easy-rsa/2.0/whichopensslcnf /usr/share/easy-rsa/2.0/
OPENSSL="openssl"
O sea, para poder regenerar crl.pem podríamos crear un guion (regenerar-certificado.sh), por ejemplo en /guiones, con el siguiente contenido
#!/bin/sh
##############################################################
Regeneracion de certificados crl.pem revoke-test.pem
(C) 2022 Angel Duran Pascual
regenerar-certificado.sh
Version 1.0
##############################################################
MAILTO="angel.duran@midominio"
El guion "regenerar-certificado.sh" debería estar en un directorio especifico. Ej /guiones
Este guion esta pensado para su uso en issabel
Inicializacion de variables
Estas dos variables seran generadas por source ./vars
export OPENSSL="openssl"
export KEY_CONFIG=/usr/share/easy-rsa/2.0/whichopensslcnf /usr/share/easy-rsa/2.0/
export CRL="crl.pem"
export RT="revoke-test.pem"
cd /usr/share/easy-rsa/2.0
source ./vars
cd /usr/share/easy-rsa/2.0/keys
$OPENSSL ca -gencrl -out "$CRL" -config "$KEY_CONFIG"
if [ -e export-ca.crt ]; then
cat export-ca.crt "$CRL" >"$RT"
else
cat ca.crt "$CRL" >"$RT"
fi
cp -f $CRL /etc/openvpn
systemctl restart openvpn@server.service
El guion /usr/share/easy-rsa/2.0/whichopensslcnf (definido en KEY_CONFIG) llama al guion correspondiente a la versión de openssl que tengamos instalada, por ejemplo a fecha 12 de enero de 2022, llama a openssl-1.0.0.cnf. Pues bien, dentro de este fichero de configuración tenemos, entre otras cosas
default_crl_days= 30
donde se establece el tiempo que durará nuestro certificado.
Vamos a generar un segunda versión de nuestro guion que genere el certificado solo si ha caducado.
#!/bin/sh
##############################################################
Regeneracion de certificados crl.pem revoke-test.pem
(C) 2022 Angel Duran Pascual
regenerar-certificado.sh
Version 2.0
Regenera si ha caducado el certificado
##############################################################
MAILTO="angel.duran@midominio"
El guion "regenerar-certificado.sh" deberia estar en un directorio especifico. Ej /guiones
El guion "regenerar-certificado.sh" deberia ejecutarse desde crontab
Este guion esta pensado para su uso en issabel
Inicializacion de variables
export OPENSSL="openssl"
export KEY_CONFIG=/usr/share/easy-rsa/2.0/whichopensslcnf /usr/share/easy-rsa/2.0/
export CRL="crl.pem"
export RT="revoke-test.pem"
cd /usr/share/easy-rsa/2.0
source ./vars
cd /usr/share/easy-rsa/2.0/keys
Obtenemos fecha de caducidad del certificado
FECHA_CERTIFICADO=openssl crl -inform PEM -text -noout -in crl.pem | grep Next | sed -e 's/ */ /g' | cut -d' ' -f4-8
Ejemplo salida: Feb 12 11:28:44 2022 GMT
MES_CERTIFICADO=echo $FECHA_CERTIFICADO | cut -d' ' -f1
DIA_CERTIFICADO=echo $FECHA_CERTIFICADO | cut -d' ' -f2
HORA_CERTIFICADO=echo $FECHA_CERTIFICADO | cut -d' ' -f3
ANNO_CERTIFICADO=echo $FECHA_CERTIFICADO | cut -d' ' -f4
Convertimos mes de certificado a numero
if [ "$MES_CERTIFICADO" = "Ene" ]; then MES_CERTIFICADO="01"; fi
if [ "$MES_CERTIFICADO" = "Feb" ]; then MES_CERTIFICADO="02"; fi
if [ "$MES_CERTIFICADO" = "Mar" ]; then MES_CERTIFICADO="03"; fi
if [ "$MES_CERTIFICADO" = "Abr" ]; then MES_CERTIFICADO="04"; fi
if [ "$MES_CERTIFICADO" = "May" ]; then MES_CERTIFICADO="05"; fi
if [ "$MES_CERTIFICADO" = "Jun" ]; then MES_CERTIFICADO="06"; fi
if [ "$MES_CERTIFICADO" = "Jul" ]; then MES_CERTIFICADO="07"; fi
if [ "$MES_CERTIFICADO" = "Ago" ]; then MES_CERTIFICADO="08"; fi
if [ "$MES_CERTIFICADO" = "Sep" ]; then MES_CERTIFICADO="09"; fi
if [ "$MES_CERTIFICADO" = "Oct" ]; then MES_CERTIFICADO="10"; fi
if [ "$MES_CERTIFICADO" = "Nov" ]; then MES_CERTIFICADO="11"; fi
if [ "$MES_CERTIFICADO" = "Dic" ]; then MES_CERTIFICADO="12"; fi
Obtenemos fecha de caducidad del sistema en zona horaria UTC (equivalente a GMT)
DIA_ACTUAL=date -u +"%d"
MES_ACTUAL=date -u +"%m"
ANNO_ACTUAL=date -u +"%Y"
Ejemplo Salida: jue ene 13 11:41:19 UTC 2022
Comprobamos si el certificado ha caducado
Si ha caducado lo regeneramos
ESTADO="CORRECTO"
if [ $ANNO_CERTIFICADO -lt $ANNO_ACTUAL ]; then
ESTADO="CADUCADO"
break
else
if [ $MES_CERTIFICADO -gt $MES_ACTUAL ]; then
break
else
if [ $MES_CERTIFICADO -lt $MES_ACTUAL ]; then
ESTADO="CADUCADO"
break
else
if [ $DIA_CERTIFICADO -le $DIA_ACTUAL ]; then
ESTADO="CADUCADO"
fi
fi
fi
fi
if [ "$ESTADO" = "CADUCADO" ]; then
$OPENSSL ca -gencrl -out "$CRL" -config "$KEY_CONFIG"
if [ -e export-ca.crt ]; then
cat export-ca.crt "$CRL" >"$RT"
else
cat ca.crt "$CRL" >"$RT"
fi
cp -f $CRL /etc/openvpn
systemctl restart openvpn@server.service
fi
Planificación de ejecución del guion
Ejecutaremos el guion todos los días a la 1 y 1 minuto, o a la que cada uno desee. Es recomendable ejecutarlo todos los días para evitar que caduque un determinado día y se nos caigan las extensiones externas. Recordad que la carga del guion es ínfima y que solo genera el certificado si ha caducado o va a caducar en el día de la ejecución del guion.
crontab -e
m h dia mes dsem comando
40 /var/lib/asterisk/bin/issabelpbx-cron-scheduler.php
1 1 * /guiones/regenerar-certificado.sh