Crear autoridad certificadora (CA) y certificados autofirmados en Linux

Una autoridad certificadora (CA) es una entidad con capacidad para firmar certificados. Para crear una CA es necesario crear el par criptográfico llave privada (ca.key) y certificado publico (ca.cert). Esta CA puede ser usada para firmar certificados de autoridades certificadores intermedias (intermediate CAs) o certificados finales de usuarios o servidores.

En esta entrada se verá como crear una CA así como crear y firmar certificados con nuestra CA. Además los certificados creados y firmados por la CA incorporarán la extensión SAN (Subject Alternative Name).

Crear la entidad certificadora (CA)

Preparar el directorio

1
2
3
4
5
6
7
DIR_CA="/root/ca"
cd $DIR_CA
mkdir certs csr crl newcerts private
chmod 700 private
touch index.txt
touch index.txt.attr
echo 1000 > serial

Preparar los archivos de configuración

Confluence: Consulta SQL para listar los espacios junto con sus administradores y el tamaño de cada uno

Aunque hace casi un año que no trabajo con productos Atlassian, revisando mis viejas notas me tope con un par de consultas SQL que me resultaron muy útiles para ejecutar la consolidación de varias instancias de Confluence.

Una de las consultas SQL permite obtener el listado de espacios de Confluence con las columnas ID, nombre del espacio, login del propietario, nombre del propietario y email del propietario. Esta consulta es útil cuando la migración se ejecuta faseada, de forma, que es posible informar a los responsables de los espacios cuando se migrará su espacio.

La otra consulta SQL permite obtener el listado de espacios de Confluence con las columnas ID, nombre del espacio y tamaño en MB del espacio. Esta consulta es útil para estimar los tiempos de migración así como permitir fasear la migración creando paquetes de migración de tamaños similares.

Error al ejecutar rsync en Vagrant mediante node.vm.synced_folder

Esta es una receta un pelín vieja para resolver un problema que me encontré al trabajar con Vagrant, por lo que es posible que ya este corregido en versiones actuales; aunque en su momento, en la última disponible, vagrant-1.9.5, fue la única forma de hacer funcionar rsync entre Vagrant y la VM en HyperV en Windows 8.1.

El problema surgía al sincronizar, mediante node.vm.synced_folder, una carpeta local de Windows a una carpeta de la VM desplegada con Vagrant. Concretamente me dió problemas al adaptar unos antiguos scripts para aprovisonar los nodos de un clúster Spark. Los scripts tiraban de recursos en Internet, que ya no estaban accesibles por lo que no era posible levantar el mismo entorno de desarrollo que el que estaba en producción, por lo que el paso que dí fue copiar todos los recursos a una carpeta local y modificar el vagrantfile para que tirara desde recursos locales.

La solución que encontré fue editar el archivo \plugins\synced_folders\rsync\helper.rb, en mi caso localizado en C:\HashiCorp\Vagrant\embedded\gems\gems\vagrant-1.9.5\plugins\synced_folders\rsync\helper.rb, y aplicar el siguiente fix:

Crear solicitud de certificado (CSR)

Una solicitud de certificado (CSR) contiene la parte fundamental de un certificado SSL (CRT), y esta preparado para ser firmado por una autoridad certificadora (CA). Mediante la firma del CSR por una CA se obtiene el CRT que puede ser instalado en un servidor para cifrar el tráfico (HTTPS).

El CSR contiene una firma digital, el identificador del algoritmo de cifrado e información del certificado. Los campos que incluyen la información del certificado son:

  • Common Name, es el FQDN del certificado. Ejemplo: blog.guillen.io
  • Organization, nombre de la organización.
  • Department, departamento que gestiona el certificado.
  • City/Locality, localidad.
  • State/County/Region, ciudad.
  • Country, país.
  • Email address, una dirección de correo de contacto.

Para generar el par clave cifrada/solicitud de certificado (key/csr) solo es necesario ejecutar openssl req -new -newkey rsa:2048 -nodes -keyout wildcard.guillen.io.key -out, ejemplo:

Actualizar PROXMOX 4.x a 5.x sin suscripción

A continuación un procedimiento para actualizar PROXMOX cuando no dispones de una suscripción activa. He usado este procedimiento desde PROXMOX 3.0, por lo que funciona desde versiones anteriores a los ejemplos de esta entrada.

Ojo, que PROXMOX 3.4, liberado en 2015/02/19, fue la última versión con soporte para OpenVZ por lo que si estás actualizando desde una versión anterior a PROXMOX 4.0 deberás de convertir los contenedores OpenVZ a contenedores LXC, el procedimiento se resume en un backup & restore en cualquier caso PROXMOX publico la guía Convert OpenVZ to LXC.

También es importante notar que en esta actualización se actualiza el SO a Debian Stretch (9.x) desde Debian Jessie (8.x) si actualizas desde PROXMOX 4.x o desde Debian Wheezy (7.x) si actualizas desde PROXMOX 3.x.

Administrar firewalld

Firewalld permite gestionar de forma dinámica las reglas de firewall, es decir, es posible implementar cambios en ejecución sin necesidad de reiniciar el servicio. Esta separación entre el entorno de ejecución y configuración permanente permite evaluar y testear las reglas sin hacer cambios permanentes en la configuración.

Firewalld sigue un diseño de dos capas:

  • Capa Núcleo, es responsable de gestionar la configuración y los backends tales como iptables, iptables6, ebtables, ipset, así como la carga de módulos del kernel.
  • Capa D-BUS, es la interface principal para modificar la configuración del firewall.

Isso: raise UnicodeError("The status string must be a native string")

Tras levantar un nuevo entorno de Isso, al intentar recuperar los comentarios o publicar uno nuevo se registraba el siguiente error en los logs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Oct 22 08:25:17 blog isso-dev: 192.168.100.100 - - [2017-10-22 08:25:17] "GET /js/embed.min.js HTTP/1.1" 200 56494 0.045020
Oct 22 08:25:18 blog isso-dev: Traceback (most recent call last):
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/gevent/pywsgi.py", line 935, in handle_one_response
Oct 22 08:25:18 blog isso-dev: self.run_application()
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/gevent/pywsgi.py", line 908, in run_application
Oct 22 08:25:18 blog isso-dev: self.result = self.application(self.environ, self.start_response)
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/werkzeug/contrib/fixers.py", line 152, in __call__
Oct 22 08:25:18 blog isso-dev: return self.app(environ, start_response)
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/isso/wsgi.py", line 119, in __call__
Oct 22 08:25:18 blog isso-dev: return self.app(environ, start_response)
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/isso/wsgi.py", line 147, in __call__
Oct 22 08:25:18 blog isso-dev: add_cors_headers("200 Ok", [("Content-Type", "text/plain")])
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/isso/wsgi.py", line 144, in add_cors_headers
Oct 22 08:25:18 blog isso-dev: return start_response(status, headers.to_list(), exc_info)
Oct 22 08:25:18 blog isso-dev: File "/opt/isso/dev/lib/python2.7/site-packages/gevent/pywsgi.py", line 830, in start_response
Oct 22 08:25:18 blog isso-dev: raise UnicodeError("The status string must be a native string")
Oct 22 08:25:18 blog isso-dev: UnicodeError: The status string must be a native string
Oct 22 08:25:18 blog isso-dev: Sun Oct 22 08:25:18 2017 {'REMOTE_PORT': '44922', 'HTTP_HOST': 'dev-comment.guillen.io', 'REMOTE_ADDR': '192.168.100.21', (hidden keys: 32)} failed with UnicodeError

Apache: Location Deny-Allow

A continuación un ejemplo práctico para limitar el acceso a ciertas rutas, en función de la IP de origen.

En este caso se limitará el acceso al sistema de login de Spacewalk, para ello creé el archivo /etc/httpd/conf.d/zzz-spacewalk-security.conf con el siguiente contenido:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<Location /rhn/LoginSubmit.do*>
Order deny,allow
Deny from all
Allow from localhost
Allow from NBMAD001.my-company.com
</Location>
<Location /rhn/ReLoginSubmit.do*>
Order deny,allow
Deny from all
Allow from localhost
Allow from NBMAD001.my-company.com
</Location>
<Location /rhn/help/*>
Order deny,allow
Deny from all
Allow from localhost
Allow from NBMAD001.my-company.com
</Location>

Obtener la IP del cliente en NGINX cuando está detrás de HAProxy

Cuando un servidor está detrás de un proxy, la IP del cliente que ve el servidor es la IP del proxy. Si bien esto no afecta directamente al servicio, no es útil por varias razones como por ejemplo:

  1. En los logs no se registra la IP correcta del cliente.
  2. No es posible implementar ningún sistema, basado en IP, para limitar los ataques de fuerza bruta contra el sistema de login.
  3. Si desea usar usar algún módulo de localización geográfica como por ejemplo el módulo ngx_http_geoip_module de NIGNX.

Para lograr esto, es necesario:
1.- Usar el parámetro real_ip_header, del módulo ngx_http_realip_module de NGINX, para modificar la cabecera que contiene la IP del cliente.
2.- Configurar HAProxy para que añada la cabecera X-Forwarded-For o X-Real-IP.
3.- Configurar NGINX para que reemplace el parámetro fastcgi REMOTE_ADDR con la IP de la cabecera X-Forwarded-For o X-Real-IP.

Instalar NextCloud usando NGINX, PHP-FPM, APCu, Redis y GlusterFS

Aprovechando que he montado un nuevo volumen Raid1 con dos discos duros Hitachi HGST_HTS721010A9E630 en mi servidor personal en Madrid he decidido migrar algunos contenedores desde el viejo volumen en Western Digital, especialmente porque el throughput del nuevo volumen de discos Hitachi es muy superior al volumen con discos Western Digital.

En algunos casos he optado por hacer instalaciones limpias, en lugar de mover el contenedor de volumen; como por ejemplo el contenedor que corre el nodo de NexctCloud en Madrid. Así que he aprovechado la ocasión para documentar el proceso en forma de post.

Algunas Consideraciones previas:

  1. El servicio de NextCloud está clústerizado en los nodos Madrid/Sevilla. Aunque debido a que la línea de Madrid es mucho mejor (300MB/300MB frente a 30MB/3MB), no se hace balanceo; por defecto todo el tráfico es enrutado hacia el nodo de Madrid, por lo que a efectos prácticos el servicio no dispone de alta disponibilidad (se precisa intervención humana para cambiar la DNS).
  2. Las comunicaciones entre los nodos de Madrid y Sevilla tiene lugar a través de un túnel VPN montado con OpenVPN.
  3. La base de datos es un clúster multimaster de MariaDB 10.1 con un nodo en Madrid y otro en Sevilla además de un Árbitro en Madrid para evitar situaciones de split-brain. Lo idóneo sería contar con una tercera ubicación donde colocar el Árbitro, aunque de momento con este sistema no he tenido problemas en 2 años a pesar de tener numerosas caídas, especialmente del nodo de Sevilla.
  4. El clúster multimaster de MariaDB esta alojado en otro contenedor, por lo que solo es necesario permitir el login desde la IP del nuevo contenedor de NextCloud; es decir, este punto no se toca en está entrada.
  5. La replicación a nivel de archivos se consigue a través de GlusterFS, con un brick en Madrid y otro en Sevilla.
  6. Los nodos del GlusterFS corren dentro del propio contenedor de NextCloud. Para evitar la caída del servicio se añadirá un nuevo nodo al clúster de GlusterFS, y una vez el nuevo servidor este configurado, sincronizado y operativo se eliminará el viejo nodo.
  7. Redis se usa como cache local para gestionar los bloqueos transaccionales, es decir, no existe un clúster de Redis por los motivos expuestos en el punto 1.