diff --git a/defaults/main.yml b/defaults/main.yml index 921409d..4f6a2ce 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -145,7 +145,8 @@ haproxy_ssl_cert_path: /etc/haproxy/ssl haproxy_ssl_bind_options: "ssl-min-ver TLSv1.2 prefer-client-ciphers" haproxy_ssl_server_options: "ssl-min-ver TLSv1.2" # TLS v1.2 and below -haproxy_ssl_cipher_suite_tls12: "{{ haproxy_ssl_cipher_suite | default(ssl_cipher_suite_tls12 | default('ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES256:ECDH+AES128:!aNULL:!SHA1:!AESCCM')) }}" +haproxy_ssl_cipher_suite_tls12: >- + {{ haproxy_ssl_cipher_suite | default(ssl_cipher_suite_tls12 | default('ECDH+AESGCM:ECDH+CHACHA20:ECDH+AES256:ECDH+AES128:!aNULL:!SHA1:!AESCCM')) }} # TLS v1.3 haproxy_ssl_cipher_suite_tls13: "{{ ssl_cipher_suite_tls13 | default('TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256') }}" @@ -198,7 +199,8 @@ haproxy_pki_install_ca: haproxy_pki_keys_path: "{{ haproxy_pki_dir ~ '/certs/private/' }}" haproxy_pki_certs_path: "{{ haproxy_pki_dir ~ '/certs/certs/' }}" haproxy_pki_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name | default('HAProxyIntermediate') }}" -haproxy_pki_intermediate_cert_path: "{{ haproxy_pki_dir ~ '/roots/' ~ haproxy_pki_intermediate_cert_name ~ '/certs/' ~ haproxy_pki_intermediate_cert_name ~ '.crt' }}" +haproxy_pki_intermediate_cert_path: >- + {{ haproxy_pki_dir ~ '/roots/' ~ haproxy_pki_intermediate_cert_name ~ '/certs/' ~ haproxy_pki_intermediate_cert_name ~ '.crt' }} haproxy_pki_regen_cert: '' haproxy_pki_certificates: "{{ _haproxy_pki_certificates }}" @@ -255,15 +257,15 @@ haproxy_keepalive_mode: 'httpclose' haproxy_maxconn: 4096 # Parameters below should only be specified if necessary, defaults are programmed in the template -#haproxy_tuning_params: -# nbproc: 1 -# tune.bufsize: 384000 -# tune.chksize: 16384 -# tune.comp_maxlevel: 1 -# tune.http_maxhdr: 101 -# tune.maxaccept: 64 -# tune.ssl_cachesize: 20000 -# tune.ssl_lifetime: 300 +# haproxy_tuning_params: +# nbproc: 1 +# tune.bufsize: 384000 +# tune.chksize: 16384 +# tune.comp_maxlevel: 1 +# tune.http_maxhdr: 101 +# tune.maxaccept: 64 +# tune.ssl_cachesize: 20000 +# tune.ssl_lifetime: 300 haproxy_tuning_params: {} # Add extra VIPs to all services diff --git a/handlers/main.yml b/handlers/main.yml index 8418f7b..b736435 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -13,9 +13,10 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: regen pem - 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' }} +- name: Regen pem # noqa: no-changed-when + 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 vars: item_interface: "{{ item['interface'] | default('') }}" @@ -25,12 +26,15 @@ listen: - haproxy cert installed -- name: regenerate maps +- name: Regenerate maps vars: all_changed_results: "{{ (map_create.results + map_delete.results) | select('changed') }}" assemble: src: "/etc/haproxy/map.conf.d/{{ item }}" dest: "/etc/haproxy/{{ item }}.map" + mode: "0640" + owner: haproxy + group: haproxy notify: Reload haproxy with_items: "{{ all_changed_results | map(attribute='item') | flatten | selectattr('name', 'defined') | map(attribute='name') | unique }}" @@ -39,6 +43,9 @@ src: "/etc/haproxy/conf.d" dest: "/etc/haproxy/haproxy.cfg" validate: /usr/sbin/haproxy -c -f %s + mode: "0640" + owner: haproxy + group: haproxy notify: Reload haproxy tags: - haproxy-general-config diff --git a/meta/main.yml b/meta/main.yml index 1f6e307..7e1103f 100644 --- a/meta/main.yml +++ b/meta/main.yml @@ -16,21 +16,23 @@ galaxy_info: author: rcbops description: Installation and setup of HAProxy + role_name: haproxy_server + namespace: openstack company: Rackspace license: Apache2 - min_ansible_version: 2.2 + min_ansible_version: "2.10" platforms: - name: Debian versions: - - buster + - bullseye - name: Ubuntu versions: - - bionic - focal + - jammy - name: EL versions: - - 8 - categories: + - "9" + galaxy_tags: - cloud - python - development diff --git a/tasks/haproxy_install.yml b/tasks/haproxy_install.yml index bb7e457..cc50471 100644 --- a/tasks/haproxy_install.yml +++ b/tasks/haproxy_install.yml @@ -30,6 +30,7 @@ file: path: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}" state: directory + mode: "0755" - name: Download hatop package get_url: @@ -37,6 +38,7 @@ dest: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename }}" validate_certs: "{{ haproxy_hatop_download_validate_certs }}" checksum: "{{ haproxy_hatop_download_checksum }}" + mode: "0644" register: fetch_url until: fetch_url is success retries: 3 @@ -44,17 +46,16 @@ - name: Unarchive HATop unarchive: - src: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename }}" - dest: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}" - remote_src: yes - extra_opts: - - --strip-components=1 + src: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename }}" + dest: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}" + remote_src: yes + extra_opts: + - --strip-components=1 - name: Copy HATop binary copy: src: "{{ haproxy_hatop_download_path }}/{{ haproxy_hatop_download_url | basename | replace('.tar.gz', '') }}/bin/hatop" dest: /usr/local/bin/hatop - mode: 0755 + mode: "0755" remote_src: yes when: haproxy_hatop_install | bool - diff --git a/tasks/haproxy_post_install.yml b/tasks/haproxy_post_install.yml index 72db060..90b92f1 100644 --- a/tasks/haproxy_post_install.yml +++ b/tasks/haproxy_post_install.yml @@ -45,11 +45,15 @@ template: src: "haproxy.cfg.j2" dest: "/etc/haproxy/conf.d/00-haproxy" + mode: "0640" + owner: haproxy + group: haproxy notify: Regenerate haproxy configuration tags: - haproxy-base-config -- include_tasks: haproxy_service_config.yml +- name: Including haproxy_service_config tasks + include_tasks: haproxy_service_config.yml tags: - haproxy-service-config @@ -61,14 +65,15 @@ owner: 'haproxy' group: 'haproxy' -#NOTE(jrosser) The next task fails on Centos without this, -#an empty directory rather than a file is made and the bind mount fails +# NOTE(jrosser) The next task fails on Centos without this, +# an empty directory rather than a file is made and the bind mount fails - name: Ensure empty file is availble to bind mount log socket file: state: touch path: "{{ haproxy_log_mount_point }}" access_time: preserve modification_time: preserve + mode: "0755" - name: Make log socket available to chrooted filesystem mount: diff --git a/tasks/haproxy_pre_install.yml b/tasks/haproxy_pre_install.yml index ebc7298..37f17db 100644 --- a/tasks/haproxy_pre_install.yml +++ b/tasks/haproxy_pre_install.yml @@ -48,6 +48,8 @@ path: "{{ item }}" state: directory mode: "0755" + owner: haproxy + group: haproxy with_items: - /etc/haproxy/conf.d - "{{ haproxy_ssl_cert_path }}" @@ -56,6 +58,9 @@ copy: content: "{{ item.content }}" dest: "{{ item.dest }}" + mode: "0644" + owner: haproxy + group: haproxy when: - (item.condition | default(True)) loop: "{{ haproxy_static_files }}" diff --git a/tasks/haproxy_service_config.yml b/tasks/haproxy_service_config.yml index d65e08d..950a2c9 100644 --- a/tasks/haproxy_service_config.yml +++ b/tasks/haproxy_service_config.yml @@ -21,7 +21,7 @@ - name: Append services to _haproxy_service_configs_simplified list set_fact: - _haproxy_service_configs_simplified: "{{ _haproxy_service_configs_simplified + [ (item.service is defined) | ternary(item.service, item) ] }}" + _haproxy_service_configs_simplified: "{{ _haproxy_service_configs_simplified + [(item.service is defined) | ternary(item.service, item)] }}" loop: "{{ haproxy_service_configs }}" ########################################################################### @@ -32,6 +32,9 @@ template: src: service.j2 dest: "/etc/haproxy/conf.d/{{ service.haproxy_service_name }}" + owner: root + group: haproxy + mode: "0640" # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced # with haproxy_service_configs in 2024.1. loop: "{{ _haproxy_service_configs_simplified }}" @@ -73,9 +76,16 @@ file: state: directory path: "/etc/haproxy/map.conf.d/{{ item }}" + owner: root + group: haproxy + mode: "0750" # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced # with haproxy_service_configs in 2024.1. - loop: "{{ _haproxy_service_configs_simplified | selectattr('haproxy_map_entries', 'defined') | map(attribute='haproxy_map_entries') | flatten | map(attribute='name') | unique }}" + loop: >- + {{ + _haproxy_service_configs_simplified | selectattr('haproxy_map_entries', 'defined') | map(attribute='haproxy_map_entries') | flatten | + map(attribute='name') | unique + }} # create map entries when the service is enabled and an existing map fragment is not absent - name: Create haproxy map files @@ -84,6 +94,9 @@ template: src: map.j2 dest: "{{ map_file }}" + owner: root + group: haproxy + mode: "0640" # NOTE(damiandabrowski): _haproxy_service_configs_simplified should be replaced # with haproxy_service_configs in 2024.1. with_subelements: @@ -92,7 +105,7 @@ when: - (item.0.haproxy_service_enabled | default(True)) | bool - item.1.state | default('present') != 'absent' - notify: regenerate maps + notify: Regenerate maps register: map_create # remove map entries when the service is not enabled, the service is absent or the map is absent @@ -109,5 +122,5 @@ with_subelements: - "{{ _haproxy_service_configs_simplified | selectattr('haproxy_map_entries', 'defined') }}" - haproxy_map_entries - notify: regenerate maps + notify: Regenerate maps register: map_delete diff --git a/tasks/haproxy_service_config_external.yml b/tasks/haproxy_service_config_external.yml index 289f9c1..8515028 100644 --- a/tasks/haproxy_service_config_external.yml +++ b/tasks/haproxy_service_config_external.yml @@ -26,7 +26,8 @@ paths: - "{{ role_path }}/vars" -- include_tasks: haproxy_service_config.yml +- name: Including haproxy_service_config tasks + include_tasks: haproxy_service_config.yml args: apply: tags: diff --git a/tasks/haproxy_ssl_letsencrypt.yml b/tasks/haproxy_ssl_letsencrypt.yml index cb26294..4bebf86 100644 --- a/tasks/haproxy_ssl_letsencrypt.yml +++ b/tasks/haproxy_ssl_letsencrypt.yml @@ -48,7 +48,7 @@ template: src: letsencrypt_pre_hook_certbot_distro.j2 dest: /etc/letsencrypt/renewal-hooks/pre/haproxy-pre - mode: 0755 + mode: "0755" when: - haproxy_ssl_letsencrypt_certbot_challenge == 'http-01' @@ -56,14 +56,17 @@ template: src: letsencrypt_renew_certbot_distro.j2 dest: /etc/letsencrypt/renewal-hooks/post/haproxy-renew - mode: 0755 + mode: "0755" - name: Create new pem file for haproxy assemble: src: "{{ haproxy_ssl_letsencrypt_config_path }}/{{ haproxy_ssl_letsencrypt_domains | first }}" dest: "{{ haproxy_ssl_cert_path ~ '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ item ~ '.pem' }}" regexp: '(privkey|fullchain).pem$' + owner: haproxy + group: haproxy + mode: "0640" with_items: - - "{{ [ haproxy_bind_external_lb_vip_address ] + extra_lb_tls_vip_addresses }}" + - "{{ [haproxy_bind_external_lb_vip_address] + extra_lb_tls_vip_addresses }}" notify: - Reload haproxy diff --git a/tasks/main.yml b/tasks/main.yml index 70b151b..dcb92a2 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -28,19 +28,21 @@ tags: - always -- import_tasks: haproxy_pre_install.yml +- name: Importing haproxy_pre_install tasks + import_tasks: haproxy_pre_install.yml tags: - haproxy_server-install -- import_tasks: haproxy_install.yml +- name: Importing haproxy_install tasks + import_tasks: haproxy_install.yml tags: - haproxy_server-install - #NOTE (jrosser) the self signed certificate is also needed for bootstrapping - #letsencrypt, as haproxy will not start with ssl config but a missing certificate + # NOTE (jrosser) the self signed certificate is also needed for bootstrapping + # letsencrypt, as haproxy will not start with ssl config but a missing certificate - name: Create and install SSL certificates include_role: - name: pki + name: pki vars: pki_setup_host: "{{ haproxy_pki_setup_host }}" pki_dir: "{{ haproxy_pki_dir }}" @@ -56,14 +58,17 @@ when: - haproxy_ssl | bool -- import_tasks: haproxy_post_install.yml +- name: Importing haproxy_post_install tasks + import_tasks: haproxy_post_install.yml tags: - haproxy_server-config # NOTE(jrosser) we must reload the haproxy config before doing the first time certbot setup to ensure the letsencypt backend is configured -- meta: flush_handlers +- name: Flush handlers + meta: flush_handlers -- include_tasks: haproxy_ssl_letsencrypt.yml +- name: Including haproxy_ssl_letsencrypt tasks + include_tasks: haproxy_ssl_letsencrypt.yml when: - haproxy_ssl | bool - haproxy_ssl_letsencrypt_enable | bool diff --git a/vars/main.yml b/vars/main.yml index ad10d4d..a621287 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -15,7 +15,8 @@ _haproxy_tls_vip_binds: | {% 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 %} + {% 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 %} @@ -27,7 +28,8 @@ _haproxy_pki_certificates: | {% set _pki_certs = [] %} {% for vip in haproxy_tls_vip_binds %} {% set _vip_interface = vip['interface'] | default('') %} - {% set san = 'DNS:' ~ ansible_facts['hostname'] ~ ',DNS:' ~ ansible_facts['fqdn'] ~ ',' ~ (vip['address'] | ansible.utils.ipaddr) | ternary('IP:', 'DNS:') ~ vip['address'] %} + {% set san = 'DNS:' ~ ansible_facts['hostname'] ~ ',DNS:' ~ ansible_facts['fqdn'] ~ ',' ~ ( + vip['address'] | ansible.utils.ipaddr) | ternary('IP:', 'DNS:') ~ vip['address'] %} {% if vip['address'] == haproxy_bind_internal_lb_vip_address %} {% set san = san ~ (internal_lb_vip_address | ansible.utils.ipaddr) | ternary('', ',DNS:' ~ internal_lb_vip_address) %} {% endif %} @@ -50,7 +52,9 @@ _haproxy_pki_install_certificates: | {% set _pki_install = [] %} {% for vip in haproxy_tls_vip_binds %} {% set _vip_interface = vip['interface'] | default('') %} - {% set _cert_basename = '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ (_vip_interface is truthy) | ternary(vip['address'] ~ '-' ~ _vip_interface, vip['address']) %} + {% set _cert_basename = '/haproxy_' ~ ansible_facts['hostname'] ~ '-' ~ (_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'),