diff --git a/defaults/main.yml b/defaults/main.yml index ebbc737..322af2e 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -235,6 +235,19 @@ haproxy_bind_external_lb_vip_address: "{{ external_lb_vip_address }}" # Option to override which address haproxy binds to for internal vip. haproxy_bind_internal_lb_vip_address: "{{ internal_lb_vip_address }}" +# Option to define if you need haproxy to bind on specific interface. +haproxy_bind_external_lb_vip_interface: +haproxy_bind_internal_lb_vip_interface: + +# Option to override haproxy frontend binds +# Example: +# haproxy_tls_vip_binds: +# - address: '*' +# interface: bond0 +# - address: '192.168.0.10' + +haproxy_tls_vip_binds: "{{ _haproxy_tls_vip_binds }}" + # Make the log socket available to the chrooted filesystem haproxy_log_socket: "/dev/log" haproxy_log_mount_point: "/var/lib/haproxy/dev/log" diff --git a/handlers/main.yml b/handlers/main.yml index 36fcbe3..eea7e2c 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -17,9 +17,10 @@ shell: > cat {{ item_base_path ~ '.crt' }} $(test -f {{ item_base_path ~ '-ca.crt' }} && echo {{ item_base_path ~ '-ca.crt' }}) {{ item_base_path ~ '.key' }} > {{ item_base_path ~ '.pem' }} notify: Reload haproxy - with_items: "{{ _haproxy_tls_vip_binds }}" vars: - item_base_path: "{{ haproxy_ssl_cert_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ item }}" + item_name: "{{ ('interface' in item and item['interface'] is truthy) | ternary(item['address'] ~ '-' ~ item['interface'], item['address']) }}" + item_base_path: "{{ haproxy_ssl_cert_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ item_name }}" + with_items: "{{ haproxy_tls_vip_binds }}" listen: - cert installed diff --git a/releasenotes/notes/bind_interface-8f7a123d4ab1219a.yaml b/releasenotes/notes/bind_interface-8f7a123d4ab1219a.yaml new file mode 100644 index 0000000..5802151 --- /dev/null +++ b/releasenotes/notes/bind_interface-8f7a123d4ab1219a.yaml @@ -0,0 +1,12 @@ +--- + +features: + - | + Added variables ``haproxy_bind_external_lb_vip_interface`` and + ``haproxy_bind_internal_lb_vip_interface`` that allows deployer to bind + haproxy on the specific interface only. + - | + Added variable ``haproxy_tls_vip_binds`` that allows to fully override + haproxy bindings, that are generated by the role if some assumptions are + not valid for some scenarios. It is list of mappings, that include address + and interface. Interface key is optional and can be ommited. diff --git a/templates/service.j2 b/templates/service.j2 index 939cf40..4e92c7c 100644 --- a/templates/service.j2 +++ b/templates/service.j2 @@ -15,16 +15,23 @@ {% 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 %} +{% 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 vip_bind is not string and vip_bind is mapping %} +{% set vip_address = vip_bind['address'] %} +{% set vip_interface = vip_bind['interface'] %} +{% else %} +{% set vip_address = vip_bind %} +{% set vip_interface = '' %} +{% endif %} {% 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 }} +bind {{ vip_address }}:{{ item.service.haproxy_redirect_http_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }} mode http redirect scheme {{ item.service.haproxy_redirect_scheme | default('https if !{ ssl_fc }') }} {% if item.service.haproxy_frontend_acls is defined %} @@ -38,11 +45,11 @@ bind {{ vip_bind }}:{{ item.service.haproxy_redirect_http_port }} {# 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)) %} +{% if (item.service.haproxy_tcp_upgrade_frontend | default(false)) and not (loop.index == 1 or vip_address 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 %} + bind {{ vip_address }}:{{ item.service.haproxy_port }}{{ (vip_interface is truthy) | ternary(' interface ' ~ vip_interface, '') }} {% if (item.service.haproxy_ssl | default(false) | bool) and (loop.index == 1 or vip_address in extra_lb_tls_vip_addresses or (item.service.haproxy_ssl_all_vips | default(false) | bool and vip_address not in extra_lb_vip_addresses)) %}ssl crt {{ haproxy_ssl_cert_path }}/haproxy_{{ ansible_facts['hostname'] }}-{{ (vip_interface is truthy) | ternary(vip_address ~ '-' ~ vip_interface, vip_address) }}.pem {% endif %} {% if request_option == "http" %} option httplog @@ -69,7 +76,7 @@ frontend {{ item.service.haproxy_service_name }}-front-{{ loop.index }} {% 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)) %} +{% if (item.service.haproxy_ssl | default(false) | bool) and request_option == 'http' and (loop.index == 1 or vip_address in extra_lb_tls_vip_addresses or (item.service.haproxy_ssl_all_vips | default(false) | bool and vip_address not in extra_lb_vip_addresses)) %} http-request add-header X-Forwarded-Proto https {% endif %} mode {{ item.service.haproxy_balance_type }} diff --git a/vars/main.yml b/vars/main.yml index 9dc4448..d14c02e 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -14,24 +14,24 @@ # limitations under the License. _haproxy_tls_vip_binds: | - {% set vip_binds = [haproxy_bind_external_lb_vip_address] %} - {% if haproxy_bind_internal_lb_vip_address != haproxy_bind_external_lb_vip_address %} - {% set _ = vip_binds.append(haproxy_bind_internal_lb_vip_address) %} + {% set vip_binds = [{'address': haproxy_bind_external_lb_vip_address, 'interface': haproxy_bind_external_lb_vip_interface}] %} + {% if haproxy_bind_internal_lb_vip_address != haproxy_bind_external_lb_vip_address or haproxy_bind_external_lb_vip_interface != haproxy_bind_internal_lb_vip_interface %} + {% set _ = vip_binds.append({'address': haproxy_bind_internal_lb_vip_address, 'interface': haproxy_bind_internal_lb_vip_interface}) %} {% endif %} {% for vip_address in extra_lb_tls_vip_addresses %} - {% set _ = vip_binds.append(vip_address) %} + {% set _ = vip_binds.append({'address': vip_address}) %} {% endfor %} {{ vip_binds }} _haproxy_pki_certificates: | {% set _pki_certs = [] %} - {% for vip in _haproxy_tls_vip_binds %} + {% for vip in haproxy_tls_vip_binds %} {% set _ = _pki_certs.append( { - 'name': 'haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ vip, + 'name': 'haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ ('interface' in vip and vip['interface'] is truthy) | ternary(vip['address'] ~ '-' ~ vip['interface'], vip['address']), 'provider': 'ownca', 'cn': ansible_facts['hostname'], - 'san': 'DNS:' ~ ansible_facts['hostname'] ~ ',DNS:' ~ ansible_facts['fqdn'] ~ ',' ~ (vip | ansible.utils.ipaddr) | ternary('IP:', 'DNS:') ~ vip, + 'san': 'DNS:' ~ ansible_facts['hostname'] ~ ',DNS:' ~ ansible_facts['fqdn'] ~ ',' ~ (vip['address'] | ansible.utils.ipaddr) | ternary('IP:', 'DNS:') ~ vip['address'], 'signed_by': haproxy_pki_intermediate_cert_name, } ) %} @@ -40,8 +40,8 @@ _haproxy_pki_certificates: | _haproxy_pki_install_certificates: | {% set _pki_install = [] %} - {% for vip in _haproxy_tls_vip_binds %} - {% set _cert_basename = '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ vip %} + {% for vip in haproxy_tls_vip_binds %} + {% set _cert_basename = '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ ('interface' in vip and vip['interface'] is truthy) | ternary(vip['address'] ~ '-' ~ vip['interface'], vip['address']) %} {% set _ = _pki_install.append( { 'src': haproxy_user_ssl_cert | default(haproxy_pki_certs_path ~ _cert_basename ~ '.crt'),