Cómo hacer que Ovirt y Let's Encrypt se lleven bien

Avanzando en la mejora de la infraestructura, decidí resolver una antigua y problemática cuestión: proporcionar a mis colegas (desarrolladores, testers, administradores, etc.) la posibilidad de gestionar sus propias máquinas virtuales en ovirt sin movimientos innecesarios. En ovirt hay varios componentes que deben configurarse para solucionar mi problema: la interfaz web, la consola noVNC y la carga de imágenes de disco.

No encontré el botón "Hacerlo Genial", así que muestro qué configuraciones realicé para resolver esta tarea. Instrucciones completas a continuación:

Cómo integrar Ovirt y Let's Encrypt

DESCARGO DE RESPONSABILIDAD:

Antes de comenzar, me gustaría señalar que, por alguna razón desconocida para mí, los dominios de la infraestructura se crean en zonas privadas como lan, local, y así sucesivamente.

No sé qué impide utilizar el dominio de la organización en la zona pública. Por ejemplo, en lugar del dominio Alex-GLuck-Awesome-Company.local, se puede utilizar sin problema el dominio del sitio web de la empresa Alex-GLuck-Awesome-Company.com.

Si temes no poder hacer un seguimiento de los dominios en tu organización y que esto cause problemas, por un modesto costo de 100 rublos al año, puedes obtener un dominio separado para la infraestructura aglac.com.

Por qué es más conveniente utilizar dominios en zonas públicas:

1. Dentro de tu organización se generan servicios que van al espacio público: VPN, intercambio de archivos (seafile, nextcloud) y otros. Configurar el cifrado del tráfico en tales servicios generalmente parece un trabajo apresurado, y no nos protegeremos del MitM porque es complicado (en realidad no lo es).

O bien, dentro de la oficina tienes una dirección de servicio, y desde internet otra, y hay que mantener estas conexiones, lo que consume nuestros recursos limitados de especialistas. Además, a los empleados les resulta incómodo tener que recordar diferentes direcciones.

2. Puedes utilizar centros de certificación gratuitos para cifrar tus servicios internos.

Un PKI propio es un servicio que hay que mantener; 100 rublos al año por la posibilidad de utilizar PKI de centros de certificación gratuitos compensa con creces el tiempo de los empleados que podrían dedicar a otras tareas.

3. Al usar su propia autoridad de certificación, estará dificultando el trabajo de sus empleados y colegas remotos que desean trabajar con BYOD (traen sus propias laptops, teléfonos y tabletas) y no podrá gestionar sus dispositivos. Ellos traen Macs, Linux, Android, iOS, Windows; mantener tal zoológico no tiene ningún sentido.

Por supuesto, hay excepciones, y los bancos con otras empresas grandes que tienen políticas de seguridad establecidas nunca podrán mejorar el servicio para sus empleados.

Para ellos, existen centros de certificación de pago que por una cierta suma pueden firmar su certificado CA (busque «servicio de firma de root» en Google).

Hay otras razones por las que utilizar un dominio público es más beneficioso (lo más importante es que le pertenezca), pero este artículo no trata sobre eso.

La esencia es...

¡ATENCIÓN! Si agrega un certificado CA de Let's Encrypt a la lista de confianza para ovirt, esto podría afectar la seguridad de sus sistemas.

Lo primero que debe tener en cuenta es que exponer las interfaces de ovirt a Internet es una mala práctica, ya que no tiene sentido práctico y crea amenazas adicionales a la seguridad.

Por lo tanto, es necesario obtener el certificado en algún host bastión nuestro, luego transferir el certificado y la clave a nuestro host con ovirt-engine.

Agregamos la dirección externa de nuestro host bastión al DNS con nuestro nombre de ovirt. ovirtengine.example.com, dejaré la instalación de certbot y nginx fuera de esta conversación (cómo hacerlo ya está descrito en Habr).

Configuramos nginx versión >=1.15.7

/etc/nginx/conf.d/default.conf

servidor {
    server_name _;
    listen 80 default_server;
    location /robots.txt { alias /usr/share/nginx/html/robots.txt; }
    location /.well-known {
        root /usr/share/nginx/html;
    }
    location / {
        return 444;
    }
}

servidor {
    server_name _;
    listen 443 ssl http2 default_server;
    location /robots.txt { alias /usr/share/nginx/html/robots.txt; }
    location /.well-known {
        root /usr/share/nginx/html;
    }

    ssl_certificate /etc/nginx/ssl/$ssl_server_name/fullchain.pem; 
    ssl_certificate_key /etc/nginx/ssl/$ssl_server_name/privkey.pem;

    ssl_protocols TLSv1.2;
    ssl_prefer_server_ciphers on;

    ssl_dhparam /etc/nginx/ssl/dhparam.pem;
    ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA';
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:50m;

    # permite que el servidor adjunte respuestas OCSP, disminuyendo así el tiempo de carga de las páginas para los usuarios
    ssl_stapling on;
    ssl_stapling_verify on;
    add_header Strict-Transport-Security max-age=15768000;

    location / {
        return 444;
    }
}

Luego obtenemos nuestro certificado y clave:

certbot certonly --nginx -d ovirtengine.example.com

Archivamos nuestro certificado y clave:

tar Phczf /tmp/ovirtengine.example.com.tgz /etc/letsencrypt/live/ovirtengine.example.com

Descargamos el archivo desde el host bastión, lo transferimos a nuestro engine ovirt:

scp bastion-host:/tmp/ovirtengine.example.com.tgz /tmp/
scp /tmp/ovirtengine.example.com.tgz ovirtengine.example.com:/

Vamos al objetivo

A continuación, descomprimimos nuestro archivo y creamos enlaces simbólicos para facilitar la comprensión del sistema de ubicación de archivos:

tar Pxzf /ovirtengine.example.com.tgz && rm -f ovirtengine.example.com.tgz
mkdir -p /etc/letsencrypt/live
ln -f -s /etc/letsencrypt/live /etc/pki/letsencrypt

Configuramos el PKI integrado en ovirt para que se use el almacén de certificados de java (openjdk) para la verificación de certificados:

cat < /etc/ovirt-engine/engine.conf.d/99-setup-pki.conf 
ENGINE_HTTPS_PKI_TRUST_STORE="/etc/pki/java/cacerts"
ENGINE_HTTPS_PKI_TRUST_STORE_PASSWORD=""
EOF

Convertimos el CA de Let's Encrypt a formato der y lo agregamos al almacén de confianza de certificados de java en ovirt (es un contenedor que contiene una lista de certificados, este sistema se utiliza en java):

openssl x509 -outform der -in /etc/pki/letsencrypt/ovirtengine.example.com/chain.pem -out /tmp/ovirtengine.example.com.chain.der
keytool -import -alias "Let's Encrypt Authority X3" -file /tmp/ovirtengine.example.com.chain.der -keystore /etc/pki/ovirt-engine/.truststore -storepass $(grep '^ENGINE_PKI_TRUST_STORE_PASSWORD' /etc/ovirt-engine/engine.conf.d/10-setup-pki.conf | cut -f 2 -d '"')
rm -f /tmp/ovirtengine.example.com.chain.der

Editamos la configuración SSL para Apache, añadimos un parámetro para soportar enlaces simbólicos y eliminamos el parámetro para CA que verifica los certificados (por defecto se usará el conjunto de CA de confianza del sistema para la verificación):

sed -r -i 's|^(SSLCACertificateFile.*)|#1|g' /etc/httpd/conf.d/ssl.conf
sed -r -i '0,/^(#?SSLCACertificateFile.*)/ s//1nOptions FollowSymlinks/' /etc/httpd/conf.d/ssl.conf

Después, realizamos una copia de seguridad por si acaso de los archivos originales generados mediante PKI de ovirt automáticamente y reemplazamos los enlaces simbólicos por los archivos de Let's Encrypt:

ln -f -s /etc/pki/letsencrypt/ovirtengine.example.com/fullchain.pem /etc/pki/ovirt-engine/apache-chain.pem
services=( 'apache' 'imageio-proxy' 'websocket-proxy' )
for i in "${services[@]}"; do
cp /etc/pki/ovirt-engine/certs/$i.cer{,."$( date +%F )".bak}
cp /etc/pki/ovirt-engine/keys/$i.key.nopass{,."$( date +%F )".bak}
ln -f -s /etc/pki/letsencrypt/ovirtengine.example.com/privkey.pem /etc/pki/ovirt-engine/keys/$i.key.nopass
ln -f -s /etc/pki/letsencrypt/ovirtengine.example.com/cert.pem /etc/pki/ovirt-engine/certs/{apache,imageio-proxy,websocket-proxy}.cer
done

Restauramos los contextos de SElinux en los archivos y reiniciamos nuestros servicios (httpd, ovirt-engine, ovirt-imageio-proxy, ovirt-websocket-proxy):

restorecon -Rv /etc/pki
systemctl restart httpd ovirt-engine ovirt-imageio-proxy ovirt-websocket-proxy

httpd — servidor web apache
ovirt-engine — interfaz web de ovirt
ovirt-imageio-proxy — demonio para la carga de imágenes de disco
ovirt-websocket-proxy — servicio para trabajar con la consola noVNC

Todo lo mencionado anteriormente ha sido comprobado en la versión de ovirt 4.2.

Autoactualización de certificados en ovirt

De acuerdo con las buenas prácticas de seguridad, no debería haber conexión entre el bastión y ovirt, y el certificado se emite solo por 3 meses. Aquí surge un punto controvertido sobre cómo se ha implementado la actualización de certificados en mi caso.

Tengo un playbook de Ansible que se ejecuta en Foreman diariamente a las 5 a.m. según un horario. Este playbook accede a ovirt, verifica la validez del certificado y si quedan menos de 5 días para su expiración, se dirige al bastión y lanza la actualización del certificado.

Después de la actualización del certificado, archiva la carpeta con los archivos, la descarga en el host de Foreman y descomprime en el host de ovirt. Después, restaura los contextos de SElinux en los archivos y reinicia nuestros servicios.

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster