Google+

domingo, 5 de noviembre de 2017

OpenVPN en Debian 9 (Road to Warrior)


Hola a tod@s,

primeramente darle las gracias a Ismael por darme esta oportunidad para hacer una entrada en el blog. Espero que sea de ayuda e interés.

Escenario:
  1. Equipo con Debian 9.2 instalado desde netinstall y con gestión por ssh. (125 paquetes)
  2. Dispositivo móvil Android 8
Parametrización previa de la máquina Debian:
  • /boot -> 256M Ext2
  • /root -> 1G XFS
  • /tmp -> 512M XFS Opciones: nodev,nosuid,noexec
  • /swap -> 512M
  • /opt -> 256M XFS Opciones: nodev,nosuid,noexec
  • /var -> 1G XFS Opciones: nodev,nosuid,noexec
  • /var/log -> 256M XFS Opciones: nodev,nosuid,noexec
  • /var/log/audit -> 64Mb XFS Opciones: nodev,nosuid,noexec
  • /usr -> 1,5G  XFS
  • /home -> 64M XFS Opciones: nodev,nosuid,noexec
Paquetería necesaria:
apt install openssl easy-rsa openvpn haveged -y

Instalaremos el paquete haveged para generar la suficiente cantidad de entropía en el sistema, de manera que podamos generar claves de calidad.

Modificaremos el fichero /etc/openvpn/easy-rsa/vars quedando de la siguiente manera:
export EASY_RSA="/etc/openvpn/easy-rsa"

export KEY_SIZE=4096
export CA_EXPIRE=1825
export KEY_EXPIRE=1825
export KEY_COUNTRY="ES"
export KEY_PROVINCE="LCG"
export KEY_CITY="Cambre"
export KEY_ORG="TestLab Enterprises"
export KEY_EMAIL="root@localhost”
export KEY_OU="IT"

Según las lineas anteriores, se van a generar claves y certificados de 4096 bits con duración de 5 años y ubicadas en la ruta /etc/openvpn/easy-rsa

Hacemos source a vars. Recomendaría posicionarse en /etc/openvpn/easy-rsa
source vars

Y probamos que los scripts funcionan correctamente:
./clean-all

Ya podemos empezar a generar los certificados, primeramente la CA
./build-ca CA
El del servidor
./build-key-server srvovpn
Diffie-Helman (Si no es un equipo con cierta potencia, puede tardar unas horas)
./build-dh
Clave TA para evitar DDoS hacia la VPN
openvpn --genkey --secret ta.key
En este punto ya podemos empezar a generar certificados y claves para los usuarios de la VPN
./build-key cliente1

Crearemos la configuración del servidor VPN en /etc/openvpn/
dev tun
proto udp
port 37194
### Aumenta el cache del buffer de envio de paquetes
sndbuf 65536
### Aumenta el cache del buffer de descarga de paquetes
rcvbuf 65536
### Certificados y claves del servidor
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/srvovpn.crt
key /etc/openvpn/easy-rsa/keys/srvovpn.key
dh /etc/openvpn/easy-rsa/keys/dh4096.pem
tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0
remote-cert-tls client
crl-verify /etc/openvpn/easy-rsa/keys/crl.pem
### Hace que OpenVPN trabaje con este user/group
user nobody
group nogroup
### Graceful transition from old to new key
tran-window 256
### Subnet de la VPN
server 10.58.0.0 255.255.255.224
### Redirecciona todo el trafico del cliente Openvpn hasta el gw del servidor
push "redirect-gateway def1"
### Fichero para mantener una asociación continua de IP y dispositivos
ifconfig-pool-persist ipp.txt
### Servidores DNS
push "dhcp-option DNS 8.8.8.8" #Podríamos usar un servidor interno
push "dhcp-option DNS 8.8.4.4" # O 2 para redundancia
### Cifrado y Encriptacion
tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
cipher aes-256-cbc
auth sha512
auth-nocache
tls-version-min 1.2
### Habilita el servidor TLS y empieza a negociar la clave
tls-server
### Sale en el caso de que la negociacion TLS falle.
tls-exit
persist-key
push "persist-key"
persist-tun
### Maximo de clientes de la VPN y posibilidad de verse entre ellos
max-clients 6
client-to-client
### Compresion
comp-lzo
### Ping cada 10 segundos y máximo de 120 para contestación
keepalive 10 120
### Logs
log-append /var/log/openvpn.log
status /var/log/openvpn-status.log
verb 4
explicit-exit-notify 1

Guardamos cambios y ejecutamos:
touch /var/log/openvpn.log && /etc/init.d/openvpn restart && tail -f /var/log/openvpn.log

Si todo ha ido bien, deberíamos de ver que el servicio se ha iniciado correctamente con la configuración que hemos establecido anteriormente.

Seguidamente, creamos un script de iptables para dar cierta seguridad al entorno:
#!/bin/bash
### BEGIN INIT INFO
# Provides: fwipv4-StateFull
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Activando Iptables SPI-VPN
### END INIT INFO
flush_reglas(){
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
}
set_policy(){
iptables -P INPUT DROP
iptables -P OUTPUT DROP
iptables -P FORWARD DROP
}
unset_policy(){
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
}
reglas(){
/sbin/modprobe ip_conntrack
/sbin/modprobe ip_tables
/sbin/modprobe iptable_filter
/sbin/modprobe iptable_mangle
/sbin/modprobe iptable_nat
#Reglas
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-reply -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
### 1: Drop invalid packets ###
iptables -t mangle -A PREROUTING -m conntrack --ctstate INVALID -j DROP
### 2: Drop TCP packets that are new and are not SYN ###
iptables -t mangle -A PREROUTING -p tcp ! --syn -m conntrack --ctstate NEW -j DROP
### 3: Drop SYN packets with suspicious MSS value ###
iptables -t mangle -A PREROUTING -p tcp -m conntrack --ctstate NEW -m tcpmss ! --mss 536:65535 -j DROP
### 4: Block packets with bogus TCP flags ###
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN,RST,PSH,ACK,URG NONE -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,SYN FIN,SYN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,RST SYN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,RST FIN,RST -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags FIN,ACK FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,URG URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,FIN FIN -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ACK,PSH PSH -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ALL -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL NONE -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,FIN,PSH,URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL SYN,RST,ACK,FIN,URG -j DROP
iptables -t mangle -A PREROUTING -p tcp --tcp-flags ALL ACK,RST,SYN,FIN -j DROP
### 5: Block spoofed packets ###
iptables -t mangle -A PREROUTING -s 224.0.0.0/3 -j DROP
iptables -t mangle -A PREROUTING -s 169.254.0.0/16 -j DROP
iptables -t mangle -A PREROUTING -s 172.16.0.0/12 -j DROP
iptables -t mangle -A PREROUTING -s 192.0.2.0/24 -j DROP
iptables -t mangle -A PREROUTING -s 0.0.0.0/8 -j DROP
iptables -t mangle -A PREROUTING -s 240.0.0.0/5 -j DROP
iptables -t mangle -A PREROUTING -s 127.0.0.0/8 ! -i lo -j DROP
### 6: Drop ICMP (useless protocol) ###
iptables -t mangle -A PREROUTING -p icmp -j DROP
### 7: Drop fragments in all chains ###
iptables -t mangle -A PREROUTING -f -j DROP
### Reglas para la VPN ###
iptables -A FORWARD -o ens160 -p udp --dport 53 -m state -d 8.8.8.8,8.8.4.4 --state NEW,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i ens160 -p udp --sport 53 -m state -s 8.8.8.8,8.8.4.4 --state ESTABLISHED -j ACCEPT
iptables -A FORWARD -o ens160 -p udp --dport 123 -m state -d ipntpserver --state NEW,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i ens160 -p udp --sport 123 -m state -s ipntpserver --state ESTABLISHED -j ACCEPT
iptables -A FORWARD -o ens160 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A FORWARD -i ens160 -p tcp -m multiport --sports 80,443 -m state --state 
iptables -t nat -A POSTROUTING -s 10.58.0.0/26 -o ens160 -j SNAT --to iplanservidorvpn
# MAKE SURE NEW OUTGOING TCP CONNECTIONS ARE SYN PACKETS; OTHERWISE WE NEED TO DROP THEM
iptables -A FORWARD -p tcp ! --syn -m state --state NEW -j DROP
# DROP PACKETS WITH OUTGOING FRAGMENTS. THIS ATTACK RESULT INTO LINUX SERVER PANIC SUCH DATA LOSS
iptables -A FORWARD -f -j DROP
# DROP OUTGOING MALFORMED XMAS PACKETS
iptables -A FORWARD -p tcp --tcp-flags ALL ALL -j DROP
# DROP OUTGOING MALFORMED NULL PACKETS
iptables -A FORWARD -p tcp --tcp-flags ALL NONE -j DROP
#Invalid icmp packets need to be dropped to prevent a possible exploit.
iptables -A FORWARD -m state -p icmp --state INVALID -j DROP
### Puertos en escucha ###
iptables -A INPUT -i ens160 -p tcp -s lan/CIDR --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o ens160 -p tcp -d lan/CIDR --sport 22 -m state --state ESTABLISHED -j ACCEPT
iptables -A INPUT -i ens160 -p udp --dport 37194-m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o ens160 -p udp --sport 37194-m state --state ESTABLISHED -j ACCEPT
# MAKE SURE NEW INCOMING TCP CONNECTIONS ARE SYN PACKETS; OTHERWISE WE NEED TO DROP THEM
iptables -A INPUT -p tcp ! --syn -m state --state NEW -j DROP
# DROP PACKETS WITH INCOMING FRAGMENTS. THIS ATTACK RESULT INTO LINUX SERVER PANIC SUCH DATA LOSS
iptables -A INPUT -f -j DROP
### Salida del servidor hacia la LAN ###
iptables -A OUTPUT -o ens160 -p udp -m multiport --dports 53,123 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i ens160 -p udp -m multiport --sports 53,123 -m state --state ESTABLISHED -j ACCEPT
iptables -A OUTPUT -o ens160 -p tcp -m multiport --dports 80,443 -m state --state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -i ens160 -p tcp -m multiport --sports 80,443 -m state --state ESTABLISHED -j ACCEPT
}
case "$1" in
start)
flush_reglas
set_policy
reglas
echo "Firewall activado"
;;
stop)
flush_reglas
unset_policy
echo "Firewall desactivado"
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usar ejecutando: /etc/init.d/$0 {start|stop|restart}"
;;
esac

Damos permisos y hacemos que se ejecute en cada arranque

chmod 700 && chown root:root && chmod +x
update-rc-d nombrescript defaults

Ahora hacemos un pequeño tunning en el sysctl.conf y añadimos:
# Size of the listen queue for accepting new TCP connections (default: 128)
net.core.somaxconn = 4096
# Maximum number of sockets in TIME-WAIT to be held simultaneously (default: 180000)
net.ipv4.tcp_max_tw_buckets = 600000
# Maximum Socket Receive Buffer for all protocols (in bytes)
net.core.rmem_max = 16777216
net.core.rmem_default = 16777216
# Set Linux autotuning TCP buffer limits
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 87380 16777216
# Turn off the tcp_sack
net.ipv4.tcp_sack = 0
net.ipv4.tcp_dsack = 0
### VPN ###
net.ipv4.ip_forward = 1
net.ipv4.conf.all.accept_redirects = 1
net.ipv4.conf.default.accept_redirects = 1
# Turn off to disable IPv4 protocol features which are considered to have few legitimate uses and to be easy to abuse
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
# Protect from ICMP attacks
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Enable RFC-recommended source validation  (should not be used on machines which are routers for very complicated networks)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Enable TCP SYN Cookie Protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_timestamps = 0
# ExecShield
kernel.randomize_va_space = 2
# Core Dumps
fs.suid_dumpable = 0
#kernel.core_pattern = /proc/sys/kernel/core_pattern
# Use up to 90% of RAM (10% free)
vm.swappiness = 10
# DMESG only readeable by root
kernel.dmesg_restrict = 1
# Not allow user read kernel address symbol tables
kernel.kptr_restrict = 2
# Hardening
kernel.core_uses_pid = 1
kernel.sysrq = 0
fs.protected_symlinks = 1
fs.protected_hardlinks = 1
# TCP BBR congestion control
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

Es el turno de configurar el cliente:
dev tun
client
proto udp
remote direccionipexterna 37194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher aes-256-cbc
auth sha512
tls-cipher TLS-DHE-RSA-WITH-AES-256-CBC-SHA256
ca ca.crt #Fichero a copiar en el dispositivo cliente
cert cliente1.crt #Fichero a copiar en el dispositivo cliente
key cliente1.key #Fichero a copiar en el dispositivo cliente
tls-auth ta.key 1 #Fichero a copiar en el dispositivo cliente
auth-nocache
comp-lzo
verb 3

Como comentaba al principio, en Android se puede usar esta aplicación OpenVPN for Android 

Ya quedaría complemente listo y funcional.

Saludos a tod@s!


viernes, 12 de agosto de 2016

Cluster SSH


Buenos días amig@s!

Hoy quería enseñaros una forma fácil y rápida de administrar varias máquinas linux, esto sólo es recomendable cuando hay pocas máquinas, en caso de que haya más os recomendaría otra método como puede ser Puppet o Ansible.

Ahí vamos.

1º Necesitaremos tener una máquina Linux (en mi caso la distribución es Debian, pero puede ser cualquier, lo único que cambiará será el apt-get)


javi@Linuxtargz# apt-get install clusters

2ª Cuando se instale, necesitaremos poner el comando "ssh ip" por ejemplo:

javi@Linuxtargzcssh 172.22.2.231 172.22.2.53 172.22.2.54 

Se pueden poner tantas ips como quieras..También se puede poner si quieres entrar
como root del servidor

Ejm.

javi@Linuxtargzcssh root@172.22.2.231 root@172.22.2.53 root@172.22.2.54  root@172.22.2.52

No es necesario entrar con root, al igual que tampoco poner la ip (siempre que resuelva por DNS) un ejemplo de ello:


javi@Linuxtargzcssh squidx ftpx openvpn

Espero que os haya sido útil y os ahorre un poco de tiempo al tener que instalar algo en varias máquinas o hacer un mantenimiento.

Un saludo!!

miércoles, 10 de agosto de 2016

Cambiar nombre sistema VyOS


Buenas chic@s.

La entrada de hoy es muy simple, pero seguro que todos queréis que vuestro FW no se llama @vyos.

Vamos a darle un nombre más afín, para que esté en sintonía con nuestra infraestructura

Con estos simples comandos podréis definir el nombre de sistema de vuestro VyOS

Así viene por defecto:

vyos@vyos:~$ 

Empezamos:

vyos@vyos:~$ configure

vyos@vyos# set system host-name LinuxTargz  (Aquí podeis poner el nombre que desees)
vyos@vyos# commit     (Siempre recordar aplicar el "commit" para aplicar los cambios)

[ system host-name LinuxTargz ]
Stopping enhanced syslogd: rsyslogd.
Starting enhanced syslogd: rsyslogd.



vyos@LinuxTargz:~$


Con estos simples comandos podréis definir el nombre de sistema de vuestro VyOS

Espero que os haya resultado útil.

Saludos!

jueves, 4 de agosto de 2016

Configuración túnel IPSEC con VyOS


Buenos días chic@s.

Siguiendo con nuestro post anterior, hoy os enseñaré cómo configurar una vpn IPSEC con nuestro VyOS, contra otro FW VyOS o de otro fabricante.

Para este ejemplo, contamos con una red de prueba que es la siguiente:

RED - 161.111.128.0/24
GW Remoto - 161.111.128.82

Sin más empezamos:

Entramos por ssh al FW (si no recuerdas como entrar, tienes las instrucciones en el post anterior) dentro meteremos los siguientes comandos.

*Existen diferentes opciones a la expuestas a continuación, podéis cambiar el cifrado, el hash, dh y por supuesto es muy recomendable cambiar la password que aquí vamos a poner.

vyos@vyos:~$ configure
vyos@vyos# set vpn ipsec ipsec-interfaces interface eth0
vyos@vyos# set vpn ipsec ike-group IKE-Ltgz proposal 1
vyos@vyos# set vpn ipsec ike-group IKE-Ltgz proposal 1 dh-group 2
vyos@vyos# set vpn ipsec ike-group IKE-Ltgz proposal 1 encryption 3des
vyos@vyos# set vpn ipsec ike-group IKE-Ltgz proposal 1 hash sha1
vyos@vyos# set vpn ipsec ike-group IKE-Ltgz lifetime 3600

vyos@vyos# set vpn ipsec esp-group ESP-Ltgz proposal 1
vyos@vyos# set vpn ipsec esp-group ESP-Ltgz pfs dh-group5
vyos@vyos# set vpn ipsec esp-group ESP-Ltgz proposal 1 encryption 3des
vyos@vyos# set vpn ipsec esp-group ESP-Ltgz proposal 1 hash sha1
vyos@vyos# set vpn ipsec esp-group ESP-Ltgz lifetime 1800
vyos@vyos# edit vpn ipsec site-to-site peer 161.111.128.82
vyos@vyos# set authentication mode pre-shared-secret
vyos@vyos# set authentication pre-shared-secret 12345678
vyos@vyos# set default-esp-group ESP-Ltgz
vyos@vyos# set ike-group IKE-Ltgz
vyos@vyos# set local-address 161.111.240.24

Como se puede observar hasta aquí, hemos definido toda la fase I de la VPN, ahora nos faltaría por indicarle la fase II donde podremos las redes que tendrán conectividad. 

La topología es la siguiente:
-Redes que ve mi FW (locales-internas) 10.100.200.0/24 y 10.100.201.0/24
-Redes externas (detrás del otro FW)      161.111.128.0/24

En este caso, necesitaré 2 Fases II para poder tener conectividad entre mis redes LAN y la red LAN remota.

vyos@vyos# set tunnel 1 local prefix 10.100.200.0/24
vyos@vyos# set tunnel 1 remote prefix 161.111.128.0/24
vyos@vyos# set tunnel 2 local prefix 10.100.201.0/24
vyos@vyos# set tunnel 2 remote prefix 161.111.128.0/24

Con estos comandos ya tendríais configurado los túneles, habría que hacer lo equivalente ( o lo mismo en caso de que sea otro VyOS) en el otro extremo.

Para comprobar si los túneles están levantados el comando a utilizar es el siguiente:

vyos@vyos:~$ show vpn ipse status (*Aquí sólo podremos ver si están up o down los túneles)

O si lo queremos con más detalle, miraremos el log.

vyos@vyos:~$ show log vpn ipse



Esto ha sido todo, si tenéis cualquier duda, no dudeis en preguntarnos

Un saludo amig@s!

martes, 26 de julio de 2016

Firewall VyOS - Alternativa gratuita -


Buenos dias ami@s!

Hoy os traigo un Firewall virtual gratuito, no tan conocido como pfsense, pero que tiene muchas funcionalidales. Su nombre es VyOS

Nos podremos bajar el FW pinchando aquí 

Una vez descargada e instalada, comenzamos a probarla:


-Asignación de ip al interfaz
-Configuración del interfaz
-Permitir acceso ssh y asignación de puerto
-Establecimiento del Gateway.

Empezamos.

Las credenciales por defecto son:

*****************
vyos login: vos
password:  vyos
*****************

En esta entrada vamos a ver cómo empezar con su configuración:


vyos@vyos: configure
vyos@vyos#set interfaces ethernet eth0 address 161.111.240.40/24
vyos@vyos#set service ssh allow-root
vyos@vyos#set service ssh port 22
vyos@vyos#set system gateway-address 161.111.240.1

Con "commit" aplicamos la configuración, si no lo ejecutas, no funcionara los cambios realizados.
Con "save" salvaremos la configuración en el fichero denominado config.boot.

Ahora podríamos conectarnos a la máquina vía ssh y su administración es más fácil que por el hypervisor.

vyos@vyos: configure
vyos@vyos#set interfaces ethernet eth1 address 10.100.200.1/24
vyos@vyos#set interfaces ethernet eth2 address 10.100.201.1/24
vyos@vyos#set interfaces ethernet eth3 address 161.111.70.40/24
vyos@vyos#set interfaces ethernet eth4 address 10.100.204.1/24
vyos@vyos#set interfaces ethernet eth5 address 10.100.205.1/24
vyos@vyos#set interfaces ethernet eth5 duplex auto
vyos@vyos#set interfaces ethernet eth5 smp_affinity auto
vyos@vyos#set interfaces ethernet eth5 speed auto
vyos@vyos#commit
vyos@vyos#save

Las últimas lineas en la Eth5 no son necesarias, las he puesto para que podais ver todas las opciones que nos da el VyOS.

Así tendríamos nuestro FW configurado, en la próxima entrada veremos cómo configurar y levantar túneles IPSEC.

Un saludo!




jueves, 28 de abril de 2016

Certificados SSL gratis





Esta entrada es de Alberto Gonzalez, la cual fue subida a su blog "http://blog.inittab.org" ,pero me parecía muy interesante y la difundo de nuevo con su permiso.

Hoy vengo a contaros que se pueden conseguir certificados SSL válidos en todos los navegadores, y sistemas operativos, por cero Euros. Aunque realmente lo que quiero contar es como ponerlo en marcha rápidamente, que es lo que espero no sepáis para que terminéis de leer esto 🙂

Let’s Encrypt lleva unos meses funcionando y posiblemente para cuando termine de escribir esta entrada ya habrán generado más de dos millones de certificados. Su objetivo no es acabar con la mafia y el timo de (la mayoría de) los certificados SSL de pago. Su propósito es el que tráfico de Internet viaje cifrado, para que al menos les cueste algo más de presupuesto espiarnos a todos aquellos que lo hacen.

No voy a entrar en detalle sobre el protocolo que desarrollaron (ACME), sólo comentaré las piezas que necesitamos conocer y espero que con un poco de copiar y pegar estéis funcionando en minutos.

Software

Existen varias implementaciones del “cliente ACME” necesario para gestionar la petición de certificados. De entre ellos yo elegí acme-tiny porque su código es sencillo de entender y no tiene apenas dependencias, básicamente Python y openssl. En su repositorio de github tenéis sus instrucciones de uso, muy fáciles de seguir, pero si lo queréis algo un poco más fácil he creado un pequeño script en shell, usa acme-tiny para funcionar y sólo requiere como argumento el nombre, o nombres, de dominio para los que solicitar el certificado.
También necesitaremos un servidor web, aunque el certificado SSL sea para un servidor de correo, XMPP, o lo que se os ocurra. Es necesario porque Let’s Encrypt hará una petición a nuestro servidor web para validar que el dominio del certificado solicitado es realmente nuestro. El funcionamiento a grandes rasgos es: El “cliente ACME” solicita un certificado a Let’s Encrypt, estos piden al cliente que ponga un fichero que pruebe que el dominio es nuestro (challenge) en el servidor web y posteriormente Let’s Encrypt pide al servidor web del dominio en cuestión el fichero acordado. Si el fichero está allí y es correcto, se entiende que el dominio está bajo nuestro control y el certificado se emite.

Configuración

Lo primero que necesitaremos (además de tener acme-tiny  (enlace para “wget-ear”) y opcionalmente mi script (enlace para “wget-ear”)) es un directorio para guardar claves privadas y certificados. Para no ejecutar acme_tiny como root crearemos ese directorio con permisos de escritura para un usuario no privilegiado (no es buena idea usar alguno bajo el que se ejecute Apache/nginx o algún servicio), podemos usar nuestro propio usuario (en mi caso será “agi“). Ya que, en Debian, tenemos los directorios /etc/ssl/(private|certs), yo elegí /etc/ssl/letsencrypt:

# mkdir /etc/ssl/letsencrypt
# chown agi:ssl-cert /etc/ssl/letsencrypt
# chmod 750 /etc/ssl/letsencrypt

Bajaremos el certificado intermedio de Let’s Encrypt para que no de problemas la cadena de validación de nuestro certificado SSL. Lo dejaremos en el directorio creado:

# cd /etc/ssl/letsencrypt
# wget https://letsencrypt.org/certs/lets-encrypt-x3-cross-signed.pem

Crearemos una clave privada para establecer la comunicación con Let’s Encrypt:

# cd /etc/ssl/letsencrypt
# openssl genrsa 4096 > account.key
# chmod 600 account.key
# chown ago account.key

Ahora crearemos el directorio donde el “cliente ACME ” dejará los ficheros de validación (challenge) y que el servidor web tendrá que devolver cuando Let’s Encrypt lo solicite:

# mkdir /var/www/letsencryptchallenges
# chown agi /var/www/letsencryptchallenges

Y configuraremos el servidor web para que sirva el contenido de ese directorio. Si tenemos un sólo dominio lo podemos hacer en la configuración es éste, y si tenemos varios configurar el directorio de forma global. A forma de ejemplo, esta sería la configuración para un servidor Apache:

Alias /.well-known/acme-challenge/ /var/www/letsencryptchallenges/
<Directory /var/www/letsencryptchallenges>
  Options None
  AllowOverride None
  Order allow,deny
  Allow from all
</Directory>

Y esta para un servidor nginx:

location /.well-known/acme-challenge/ {
  alias /var/www/letsencryptchallenges/;
  try_files $uri =404;
}

Llegado este punto, si no vas a usar mi script deberías seguir las instrucciones de acme-tiny para crear un CSR (Petición de firma de certificado), instalar el certificado y programar una tarea periódica que lo renueve.
Si vas a usar mi script deberías repasar las variables de configuración que tiene al principio para ajustar los ficheros y directorios que usará (los comentados anteriormente). Si estás siguiendo literalmente los pasos que llevamos hasta ahora posiblemente sólo tendrás que cambiar el path al script acme_tiny.py (apuntar la variable ACME_TINY al path donde lo dejaras y no olvidar dar permisos de ejecución a ambos). Si ya has recargado la configuración del servidor web, para que se sirva correctamente el directorio de los ficheros challenge, sólo queda una cosa que hacer, pedir el nuevo certificado:

## Ejecutar con el usuario no privilegiado, no como root!
## Lo más sencillo es dejar new_cert en el PATH (p.e. /usr/local/bin)

$ new_cert midominio.com

## Si queremos un certificado para varios (sub)dominios podemos pasar todos
## como argumentos al script.
## IMPORTANTE: En este caso, asegúrate de que el servidor web devolverá
## el fichero challenge correctamente en todos ellos
$ new_cert midominio.com www.midominio.com eldominiodemiprimo.com

Si todo fue bien, deberíamos tener varios ficheros, que toman su nombre del primer dominio especificado en la llamada a new_cert, en el directorio de trabajo que usemos. Los importantes son: DOMINIO.key, la clave privada, y DOMINIO_chained.crt, el certificado solicitado con el certificado intermedio de Let’s Encrypt. Con ellos tendremos que configurar el virtual HTTPS de nuestros dominios. Ejemplo en Apache:

<VirtualHost *:443>
  ServerName DOMINIO
  SSLEngine on
  SSLCertificateFile /etc/ssl/letsencrypt/DOMINIO_chained.crt
  SSLCertificateKeyFile /etc/ssl/letsencrypt/DOMINIO.key
......
</VirtualHost>

Ejemplo en nginx:

server {
  listen 443;
  server_name DOMINIO;
  ssl on;
  ssl_certificate /etc/ssl/letsencrypt/DOMINIO_chained.crt;
  ssl_certificate_key /etc/ssl/letsencrypt/DOMINIO.key;
...
}

Existen varios parámetros (tanto en los servidores web mencionados como en otro tipo de servidores) para mejorar la seguridad y compatibilidad SSL. En el sitio github de acme_tiny mencionan algunos (para deshabilitar SSLv3 e inferiores y corregir posibles ataques conocidos), aunque yo soy fan de la herramienta de análisis (y  recomendaciones) de Qualys SSL Labs. Así que no os quedéis en instalar el certificado y darle un repaso a parametrización del SSL.

Mantenimiento

Los certificados de Let’s Encrypt, al menos en el momento que escribo estas líneas, tienen una vigencia de tres meses. Por ello es importante que preparemos un mecanismo automático de renovación. Que consiste en algo tan simple como una entrada de cron que solicite un nuevo certificado antes de que caduque el actual. En mi caso tengo un fichero en /etc/cron.d llamado local-letsencrypt (el prefijo local- me permite diferenciar los ficheros instalados por el gestor de paquetes de los creados por mi) con el siguiente contenido (y donde digo nginx, digo apache2, postfix, prosody, dovecot, …):
# Ajustar el nombre de usuario, el path a new_cert y el comando para recargar
# la configuración del servidor correspondiente (salvo que uséis nginx y systemd)
0 6 1 * * agi /usr/local/bin/new_cert DOMINIO(s) && sudo systemctl reload nginx

# Y no olvidéis permitir a vuestro usuario ejecutar ese comando con sudo en
# el /etc/sudoers:
agi ALL=NOPASSWD: /bin/systemctl reload nginx

## O sin depender de sudo (recomendación de Tincho):
0 6 1 * * root su -u agi -c "/usr/local/bin/new_cert DOMINIO(s)" && systemctl reload nginx

Cuidado con las cosas gratis

Para los que no se fían de las cosas gratis, les recomiendo que sigan los pasos anteriormente descritos y luego envíen 200 EUR a mi cuenta de Paypal. Una vez al año, por la renovación, claro. Les garantizo que sus  datos viajarán cifrados igualmente que con el certificado más caro de [insertar entidad certificadora aquí].

$ exit