14Abr

Cómo configurar HAProxy con múltiples certificados SSL

En esta guía vamos a configurar un HAProxy que ya esté funcionando con dos webs sin certificados SSL a usar https.

Archivos PEM

Necesitaremos los archivos pem de los certificados. Si no disponemos de ese archivo, podemos generarlo concatenando los contenidos de los archivos key y crt. En caso de disponer de este archivo para los dominios que vamos a configurar podemos ir directamente al siguiente paso de la guía.

Con el siguiente comando podemos crear el archivo pem. Sustituimos el nombre server por el nombre de nuestros archivos de key y crt:

cat server.key > server.pem
cat server.crt >> server.pem

Configuración del HAProxy sin HTTPS

Suponemos que tenemos la siguiente configuración del proxy, con dos webs que no tienen certificado SSL y que funcionan por el puerto 80.

/etc/haproxy/haproxy.cfg

global
    maxconn 2048

defaults
    mode http
    timeout connect 5000ms
    timeout client 90000ms
    timeout server 90000ms

frontend http-in
    bind *:80
    
    acl is_acme_front hdr(host) -i www.acme.com
    acl is_acme_backoffice hdr(host) -i www.admin-acme.com

    use_backend acme_front if is_acme_front
    use_backend acme_backoffice if is_acme_backoffice

backend acme_front
    balance roundrobin
    
    option httpclose
    option forwardfor

    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    server node1 172.17.0.1:12080 check
    server node2 172.17.0.1:12090 check

backend acme_backoffice
    balance roundrobin
    
    option httpclose
    option forwardfor

    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    server node1 172.17.0.1:13080 check
    server node2 172.17.0.1:13090 check

Nuestras webs son www.acme.com y www.admin-acme.com. Queremos aplicar certificado SSL a ambas webs desde nuestro HAProxy.

Añadiendo los certificados

Primer copiamos los archivos pem en alguna carpeta accesible por el servidor HAProxy. En el caso usaremos la carpeta /opt/certs y pondremos los archivos en las siguientes rutas:

  • /opt/certs/www.acme.com.pem
  • /opt/certs/www.admin-acme.com.pem

Ahora modificamos la configuración para que en el puerto 443 sirva las dos webs con los certificados añadiendo un nuevo frontend en el puerto 443, secure-http-in:

/etc/haproxy/haproxy.cfg

global
    maxconn 2048

defaults
    mode http
    timeout connect 5000ms
    timeout client 90000ms
    timeout server 90000ms

frontend secure-http-in
    bind *:443 ssl crt /opt/certs/www.acme.com.pem crt /opt/certs/www.admin-acme.com.pem

    mode http
    option http-server-close
    option forwardfor

    acl is_acme_front hdr(host) -i www.acme.com
    acl is_acme_backoffice hdr(host) -i www.admin-acme.com

    use_backend acme_front if is_acme_front
    use_backend acme_backoffice if is_acme_backoffice

frontend http-in
    bind *:80
    
    acl is_acme_front hdr(host) -i www.acme.com
    acl is_acme_backoffice hdr(host) -i www.admin-acme.com

    use_backend acme_front if is_acme_front
    use_backend acme_backoffice if is_acme_backoffice

backend acme_front
    balance roundrobin
    
    option httpclose
    option forwardfor

    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    server node1 172.17.0.1:12080 check
    server node2 172.17.0.1:12090 check

backend acme_backoffice
    balance roundrobin
    
    option httpclose
    option forwardfor

    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    server node1 172.17.0.1:13080 check
    server node2 172.17.0.1:13090 check

Si reiniciamos el servicio de haproxy:

service haproxy restart

Podremos comprobar que nuestras webs se sirven correctamente con el certificado en:

  • https://www.acme.com
  • https://www.admin-acme.com

Redirección de HTTP a HTTPS

Las webs también se están sirviendo sin el certificado si accedemos a ellas sin HTTPS. Podemos cambiar la configuración del frontend que sirve en el puerto 80 para que haga una redirección a HTTPS como sigue:

global
    maxconn 2048

defaults
    mode http
    timeout connect 5000ms
    timeout client 90000ms
    timeout server 90000ms

frontend secure-http-in
    bind *:443 ssl crt /opt/certs/www.acme.com.pem crt /opt/certs/www.admin-acme.com.pem

    mode http
    option http-server-close
    option forwardfor

    acl is_acme_front hdr(host) -i www.acme.com
    acl is_acme_backoffice hdr(host) -i www.admin-acme.com

    use_backend acme_front if is_acme_front
    use_backend acme_backoffice if is_acme_backoffice


frontend http-in
    bind *:80

    # Redirección a HTTPS en los dominios de acme y admin-acme
    redirect scheme https if { hdr(Host) -i www.acme.com } !{ ssl_fc }
    redirect scheme https if { hdr(Host) -i www.admin-acme.com } !{ ssl_fc }
    
    acl is_acme_front hdr(host) -i www.acme.com
    acl is_acme_backoffice hdr(host) -i www.admin-acme.com

    use_backend acme_front if is_acme_front
    use_backend acme_backoffice if is_acme_backoffice

backend acme_front
    balance roundrobin
    
    option httpclose
    option forwardfor

    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    server node1 172.17.0.1:12080 check
    server node2 172.17.0.1:12090 check

backend acme_backoffice
    balance roundrobin
    
    option httpclose
    option forwardfor

    http-request set-header X-Forwarded-Port %[dst_port]
    http-request add-header X-Forwarded-Proto https if { ssl_fc }

    server node1 172.17.0.1:13080 check
    server node2 172.17.0.1:13090 check

La configuración está accesible en el siguiente Gist:

Leave a comment