JamesGibo d30bb2e6d1 Add functionality to accept both HTTP and HTTPS during upgrade
Enable TLS on internal communication has 2 parts
* Enabling TLS on the internal VIPs for haproxy frontends
* Enabling TLS on the service backends
Haproxy has support for enabling TLS on frontends and backends,
but doing so would cause downtime.

In the case of upgrading frontends, enabling TLS would prevent
openstack services from working until their config is changed
from http to https, as they do not follow redirects.

In the case of backends haproxy would mark each backend as down
because if could not initiate a HTTPS connection to the backend
until the backend is updated.

This patch fixes this and allows haproxy to accept both HTTP and
HTTPS on the same well known port for each service. It also
allows for both HTTP and HTTPS backends.

Support for HTTP and HTTPS on the frontend is enabled by setting
haproxy_tcp_upgrade_frontend: true

Support for HTTP and HTTPS on the backend is enabled by setting
haproxy_tcp_upgrade_backend: true

This is a temporary patch and will be removed once instances have
been upgraded to HTTPS for internal communications in a future
release of OSA.

Change-Id: I4279005d5b4e6133cf85ba43379b51149c838f17
2022-02-18 14:40:14 +00:00

224 lines
10 KiB
Django/Jinja

# {{ ansible_managed }}
{% set request_option = item.service.haproxy_balance_type | default("http") -%}
{% if item.service.haproxy_backend_port is not defined %}
{% set haproxy_backend_port = item.service.haproxy_port %}
{% else %}
{% set haproxy_backend_port = item.service.haproxy_backend_port %}
{% endif -%}
{% if item.service.haproxy_check_port is not defined %}
{% set haproxy_check_port = haproxy_backend_port %}
{% else %}
{% set haproxy_check_port = item.service.haproxy_check_port %}
{% endif -%}
{% if item.service.haproxy_bind is defined %}
{% set vip_binds = item.service.haproxy_bind %}
{% else %}
{% set vip_binds = _haproxy_tls_vip_binds + extra_lb_vip_addresses %}
{% endif %}
{% if not item.service.haproxy_backend_only | default(false) %}
{% for vip_bind in vip_binds %}
{% if item.service.haproxy_redirect_http_port is defined and item.service.haproxy_ssl %}
{% if (loop.index == 1 or item.service.haproxy_ssl_all_vips | default(false) | bool) %}
frontend {{ item.service.haproxy_service_name }}-redirect-front-{{ loop.index }}
bind {{ vip_bind }}:{{ item.service.haproxy_redirect_http_port }}
mode http
redirect scheme {{ item.service.haproxy_redirect_scheme | default('https if !{ ssl_fc }') }}
{% if item.service.haproxy_frontend_acls is defined %}
{% for key, value in item.service.haproxy_frontend_acls.items() %}
acl {{ key }} {{ value.rule }}
use_backend {{ value.backend_name | default(item.service.haproxy_service_name) }}-back if {{ key }}
{% endfor %}
{% endif %}
{% endif %}
{% endif %}
{# TODO: remove if and section inside if after HTTPS upgrade #}
{# During an upgrade of internal frontends from HTTP to HTTPS, need to accept both HTTP and HTTPS until client config has been changed #}
{% if (item.service.haproxy_tcp_upgrade_frontend | default(false)) and not (loop.index == 1 or vip_bind in extra_lb_tls_vip_addresses) and (item.service.haproxy_ssl_all_vips | default(false)) %}
{% include 'service-redirect.j2' %}
{% else %}
frontend {{ item.service.haproxy_service_name }}-front-{{ loop.index }}
bind {{ vip_bind }}:{{ item.service.haproxy_port }} {% if (item.service.haproxy_ssl | default(false) | bool) and (loop.index == 1 or vip_bind in extra_lb_tls_vip_addresses or (item.service.haproxy_ssl_all_vips | default(false) | bool and vip_bind not in extra_lb_vip_addresses)) %}ssl crt {{ haproxy_ssl_cert_path }}/haproxy_{{ ansible_facts['hostname'] }}-{{ vip_bind }}.pem {% endif %}
{% if request_option == "http" %}
option httplog
option forwardfor except 127.0.0.0/8
{% if item.service.haproxy_http_keepalive_mode is defined %}
option {{ item.service.haproxy_http_keepalive_mode }}
{% endif %}
{% elif request_option == "tcp" %}
option tcplog
{% endif %}
{% if item.service.haproxy_timeout_client is defined %}
timeout client {{ item.service.haproxy_timeout_client }}
{% endif %}
{% if item.service.haproxy_allowlist_networks is defined %}
acl allow_list src 127.0.0.1/8 {{ item.service.haproxy_allowlist_networks | join(' ') }}
tcp-request content accept if allow_list
tcp-request content reject
{% endif %}
{% if item.service.haproxy_acls is defined %}
{% for key, value in item.service.haproxy_acls.items() %}
acl {{ key }} {{ value.rule }}
{% if not item.service.haproxy_frontend_only | default(false) %}
use_backend {{ value.backend_name | default(item.service.haproxy_service_name) }}-back if {{ key }}
{% endif %}
{% endfor %}
{% endif %}
{% if (item.service.haproxy_ssl | default(false) | bool) and request_option == 'http' and (loop.index == 1 or vip_bind in extra_lb_tls_vip_addresses or (item.service.haproxy_ssl_all_vips | default(false) | bool and vip_bind not in extra_lb_vip_addresses)) %}
http-request add-header X-Forwarded-Proto https
{% endif %}
mode {{ item.service.haproxy_balance_type }}
{% if not item.service.haproxy_frontend_only | default(false) %}
default_backend {{ item.service.haproxy_service_name }}-back
{% endif %}
{% for entry in item.service.haproxy_frontend_raw|default([]) %}
{{ entry }}
{% endfor %}
{% endif %}
{% endfor %}
{% endif %}
{% if not item.service.haproxy_frontend_only | default(false) %}
{% set backend_options = item.service.haproxy_backend_options|default([]) %}
{% set backend_arguments = item.service.haproxy_backend_arguments|default([]) %}
backend {{ item.service.haproxy_service_name }}-back
mode {{ item.service.haproxy_balance_type }}
balance {{ item.service.haproxy_balance_alg|default("leastconn") }}
{% if item.service.haproxy_timeout_server is defined %}
timeout server {{ item.service.haproxy_timeout_server }}
{% endif %}
{% if (item.service.haproxy_stick_table_enabled | default(true) | bool) %}
stick store-request src
stick-table type ip size 256k expire 30m
{% endif %}
{% if request_option == "http" %}
option forwardfor
{% elif request_option == "tcp" %}
option tcplog
{% endif %}
{% for option in backend_options %}
option {{ option }}
{% endfor %}
{% for argument in backend_arguments %}
{{ argument }}
{% endfor %}
{% set backend_httpcheck_options = item.service.haproxy_backend_httpcheck_options|default([]) %}
{% for option in backend_httpcheck_options %}
http-check {{ option }}
{% endfor %}
{% for host_name in item.service.haproxy_backend_nodes %}
{% if hostvars[host_name] is defined %}
{% set ip_addr = hostvars[host_name]['ansible_host'] %}
{% endif %}
{% set entry = [] %}
{% set _ = entry.append("server") %}
{% set _ = entry.append((host_name.name | default(host_name)) | string) %}
{% set _ = entry.append((host_name.ip_addr | default(ip_addr)) + ":" + haproxy_backend_port | string) %}
{% set _ = entry.append("check") %}
{% set _ = entry.append("port") %}
{% set _ = entry.append(haproxy_check_port | string) %}
{% set _ = entry.append("inter") %}
{% set _ = entry.append(item.service.interval|default(haproxy_interval) | string) %}
{% set _ = entry.append("rise") %}
{% set _ = entry.append(item.service.backend_rise|default(item.service.haproxy_backend_nodes | count | string)) %}
{% set _ = entry.append("fall") %}
{% set _ = entry.append(item.service.backend_fall|default(item.service.haproxy_backend_nodes | count | string)) %}
{% if item.service.haproxy_backend_ssl | default(False) %}
{% set _ = entry.append("ssl") %}
{% if item.service.haproxy_backend_ssl_check | default(item.service.haproxy_backend_ssl) %}
{% set _ = entry.append("check-ssl") %}
{% endif %}
{% if item.service.haproxy_backend_ca %}
{% set _ = entry.append("ca-file") %}
{% set _ = entry.append(item.service.haproxy_backend_ca is string | ternary(item.service.haproxy_backend_ca, haproxy_system_ca)) %}
{% else %}
{% set _ = entry.append("verify none") %}
{% endif %}
{% endif %}
{% set backend_server_options = item.service.haproxy_backend_server_options|default([]) %}
{% for option in backend_server_options %}
{% set _ = entry.append(option) %}
{% endfor %}
{% set backend_per_server_options = host_name.backend_server_options|default([]) %}
{% for option in backend_per_server_options %}
{% set _ = entry.append(option) %}
{% endfor %}
{{ entry | join(' ') }}
{# TODO: remove if and section inside if after HTTPS upgrade #}
{# During an upgrade of backends from HTTP to HTTPS, need to uses both HTTP and HTTPS backends until backends have been changed #}
{% if item.service.haproxy_tcp_upgrade_backend | default(false) and item.service.haproxy_backend_ssl | default(false) %}
{% set entry = [] %}
{% set _ = entry.append("server") %}
{% set _ = entry.append((host_name.name | default(host_name)) + "-http" | string) %}
{% set _ = entry.append((host_name.ip_addr | default(ip_addr)) + ":" + haproxy_backend_port | string) %}
{% set _ = entry.append("check") %}
{% set _ = entry.append("port") %}
{% set _ = entry.append(haproxy_check_port | string) %}
{% set _ = entry.append("inter") %}
{% set _ = entry.append(item.service.interval|default(haproxy_interval) | string) %}
{% set _ = entry.append("rise") %}
{% set _ = entry.append(item.service.backend_rise|default(item.service.haproxy_backend_nodes | count | string)) %}
{% set _ = entry.append("fall") %}
{% set _ = entry.append(item.service.backend_fall|default(item.service.haproxy_backend_nodes | count | string)) %}
{% set backend_server_options = item.service.haproxy_backend_server_options|default([]) %}
{% for option in backend_server_options %}
{% set _ = entry.append(option) %}
{% endfor %}
{% set backend_per_server_options = host_name.backend_server_options|default([]) %}
{% for option in backend_per_server_options %}
{% set _ = entry.append(option) %}
{% endfor %}
{{ entry | join(' ') }}
{% endif %}
{% endfor %}
{% for host_name in item.service.haproxy_backup_nodes|default([]) %}
{% if hostvars[host_name] is defined %}
{% set ip_addr = hostvars[host_name]['ansible_host'] %}
{% endif %}
{% set entry = [] %}
{% set _ = entry.append("server") %}
{% set _ = entry.append((host_name.name | default(host_name)) | string) %}
{% set _ = entry.append((host_name.ip_addr | default(ip_addr)) + ":" + haproxy_backend_port | string) %}
{% set _ = entry.append("check") %}
{% set _ = entry.append("port") %}
{% set _ = entry.append(haproxy_check_port | string) %}
{% set _ = entry.append("inter") %}
{% set _ = entry.append(haproxy_interval | string) %}
{% set _ = entry.append("rise") %}
{% set _ = entry.append(item.service.backup_rise|default(item.service.haproxy_backup_nodes | count | string)) %}
{% set _ = entry.append("fall") %}
{% set _ = entry.append(item.service.backup_fall|default(item.service.haproxy_backup_nodes | count | string)) %}
{% set _ = entry.append("backup") %}
{% if item.service.haproxy_backend_ssl | default(False) %}
{% set _ = entry.append("ssl") %}
{% if item.service.haproxy_backend_ssl_check | default(item.service.haproxy_backend_ssl) %}
{% set _ = entry.append("check-ssl") %}
{% endif %}
{% if item.service.haproxy_backend_ca %}
{% set _ = entry.append("ca-file") %}
{% set _ = entry.append(item.service.haproxy_backend_ca is string | ternary(item.service.haproxy_backend_ca, haproxy_system_ca)) %}
{% else %}
{% set _ = entry.append("verify none") %}
{% endif %}
{% endif %}
{% set backend_server_options = item.service.haproxy_backend_server_options|default([]) %}
{% for option in backend_server_options %}
{% set _ = entry.append(option) %}
{% endfor %}
{% set backend_per_server_options = host_name.backend_server_options|default([]) %}
{% for option in backend_per_server_options %}
{% set _ = entry.append(option) %}
{% endfor %}
{{ entry | join(' ') }}
{% endfor %}
{% endif %}