From d51fdc3039a3d7679571911aa832f3ea77e4e56e Mon Sep 17 00:00:00 2001 From: Dmitriy Rabotyagov Date: Fri, 18 Apr 2025 18:03:49 +0200 Subject: [PATCH] Use standalone httpd role In order to unify approach for managing Apache Web server, we migrate to usage of standalone `httpd` role instead of managing apache separately inside service roles. Depends-On: https://review.opendev.org/c/openstack/ansible-role-httpd/+/947678 Change-Id: I4127fd535820c1bae0208cd4a665678a491a37f8 --- defaults/main.yml | 36 ------- handlers/main.yml | 1 - tasks/horizon_apache.yml | 141 ++++++++++--------------- tasks/horizon_pre_install.yml | 12 --- tasks/main.yml | 20 ---- templates/horizon_apache_ports.conf.j2 | 6 -- templates/openstack_dashboard.conf.j2 | 82 -------------- vars/debian.yml | 36 +------ vars/distro_install.yml | 11 +- vars/main.yml | 12 +++ vars/redhat.yml | 16 +-- vars/source_install.yml | 9 +- 12 files changed, 73 insertions(+), 309 deletions(-) delete mode 100644 templates/horizon_apache_ports.conf.j2 delete mode 100644 templates/openstack_dashboard.conf.j2 diff --git a/defaults/main.yml b/defaults/main.yml index 00d31dcb..9a515789 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -166,9 +166,6 @@ horizon_endpoint_type: internalURL horizon_server_name: "{{ ansible_facts['fqdn'] | default('horizon') }}" -horizon_apache_mpm_backend: "{{ openstack_apache_mpm_backend | default('event') }}" -horizon_apache_servertokens: "Prod" -horizon_apache_serversignature: "Off" horizon_log_level: info # It's combined log format without datetime, since it's already present in journald horizon_apache_custom_log_format: '"%h %l %u \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""' @@ -227,9 +224,6 @@ horizon_wsgi_threads_max: 16 horizon_wsgi_threads: "{{ [[ansible_facts['processor_vcpus'] | default(2) // 2, 1] | max, horizon_wsgi_threads_max] | min }}" ## Horizon SSL -horizon_ssl_cert: /etc/ssl/certs/horizon.pem -horizon_ssl_key: /etc/ssl/private/horizon.key -horizon_ssl_ca_cert: /etc/ssl/certs/horizon-ca.pem horizon_ssl_protocol: "{{ ssl_protocol | default('ALL -SSLv2 -SSLv3 -TLSv1 -TLSv1.1') }}" # TLS v1.2 and below horizon_ssl_cipher_suite_tls12: >- @@ -543,38 +537,8 @@ horizon_pki_dir: "{{ openstack_pki_dir | default('/etc/openstack_deploy/pki') }} horizon_pki_setup_host: "{{ openstack_pki_setup_host | default('localhost') }}" # horizon server certificate -horizon_pki_keys_path: "{{ horizon_pki_dir ~ '/certs/private/' }}" -horizon_pki_certs_path: "{{ horizon_pki_dir ~ '/certs/certs/' }}" -horizon_pki_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name | default('ExampleCorpIntermediate') }}" -horizon_pki_intermediate_cert_path: >- - {{ horizon_pki_dir ~ '/roots/' ~ horizon_pki_intermediate_cert_name ~ '/certs/' ~ horizon_pki_intermediate_cert_name ~ '.crt' }} horizon_pki_regen_cert: "" horizon_pki_san: "{{ openstack_pki_san | default('DNS:' ~ ansible_facts['hostname'] ~ ',IP:' ~ management_address) }}" -horizon_pki_certificates: - - name: "horizon_{{ ansible_facts['hostname'] }}" - provider: ownca - cn: "{{ ansible_facts['hostname'] }}" - san: "{{ horizon_pki_san }}" - signed_by: "{{ horizon_pki_intermediate_cert_name }}" - -# Installation details for SSL certificates -horizon_pki_install_certificates: - - src: "{{ horizon_user_ssl_cert | default(horizon_pki_certs_path ~ 'horizon_' ~ ansible_facts['hostname'] ~ '-chain.crt') }}" - dest: "{{ horizon_ssl_cert }}" - owner: "{{ horizon_system_user_name }}" - group: "{{ horizon_system_group_name }}" - mode: "0644" - - src: "{{ horizon_user_ssl_key | default(horizon_pki_keys_path ~ 'horizon_' ~ ansible_facts['hostname'] ~ '.key.pem') }}" - dest: "{{ horizon_ssl_key }}" - owner: "{{ horizon_system_user_name }}" - group: "{{ horizon_system_group_name }}" - mode: "0600" - - src: "{{ horizon_user_ssl_ca_cert | default(horizon_pki_intermediate_cert_path) }}" - dest: "{{ horizon_ssl_ca_cert }}" - owner: "{{ horizon_system_user_name }}" - group: "{{ horizon_system_group_name }}" - mode: "0644" - condition: "{{ horizon_user_ssl_ca_cert is defined }}" # Define user-provided SSL certificates # horizon_user_ssl_cert: diff --git a/handlers/main.yml b/handlers/main.yml index 2d940fe7..e05c2f88 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -31,4 +31,3 @@ daemon_reload: "{{ (ansible_facts['service_mgr'] == 'systemd') | ternary('yes', omit) }}" listen: - "venv changed" - - "cert installed" diff --git a/tasks/horizon_apache.yml b/tasks/horizon_apache.yml index 6a5ce5dc..575ef221 100644 --- a/tasks/horizon_apache.yml +++ b/tasks/horizon_apache.yml @@ -13,93 +13,60 @@ # See the License for the specific language governing permissions and # limitations under the License. -- name: Ensure apache2 MPM for Debian/Ubuntu - community.general.apache2_module: - name: "{{ item.name }}" - state: "{{ item.state }}" - ignore_configcheck: true - warn_mpm_absent: false - with_items: "{{ horizon_apache_mpms | sort(attribute='state') }}" - when: - - ansible_facts['pkg_mgr'] == 'apt' - notify: Restart wsgi process - -- name: Ensure apache2 MPM for EL - ansible.builtin.copy: - content: | - LoadModule mpm_{{ horizon_apache_mpm_backend }}_module modules/mod_mpm_{{ horizon_apache_mpm_backend }}.so - - dest: /etc/httpd/conf.modules.d/00-mpm.conf - mode: "0644" - when: - - ansible_facts['pkg_mgr'] == 'dnf' - notify: Restart wsgi process - -# NOTE(hwoarang): Module enable/disable process is only functional on Debian -- name: Enable apache2 modules - community.general.apache2_module: - name: "{{ item.name }}" - state: "{{ item.state }}" - ignore_configcheck: true - with_items: - - "{{ horizon_apache_modules }}" - when: - - ansible_facts['pkg_mgr'] == 'apt' - notify: Restart wsgi process - -- name: Drop apache2 configs - ansible.builtin.template: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - owner: "{{ item.owner | default(horizon_system_user_name) }}" - group: "{{ item.group | default(horizon_system_group_name) }}" - mode: "0644" - with_items: "{{ horizon_apache_configs }}" - notify: Restart wsgi process - -- name: Disable default apache site +- name: Clean-up old vhost files ansible.builtin.file: path: "{{ item }}" - state: "absent" - with_items: "{{ horizon_apache_default_sites }}" - notify: Restart wsgi process + state: absent + loop: "{{ horizon_deprecated_apache_configs }}" -- name: Enable Horizon Site - ansible.builtin.file: - src: "{{ horizon_apache_site_available }}" - dest: "{{ horizon_apache_site_enabled }}" - state: "link" - when: - - horizon_apache_site_available is defined - - horizon_apache_site_enabled is defined - notify: Restart wsgi process - -- name: Ensure Apache ServerName - ansible.builtin.lineinfile: - dest: "{{ horizon_apache_conf }}" - line: "ServerName {{ horizon_server_name }}" - notify: Restart wsgi process - -- name: Ensure Apache ServerTokens - ansible.builtin.lineinfile: - dest: "{{ horizon_apache_security_conf }}" - regexp: "^ServerTokens" - line: "ServerTokens {{ horizon_apache_servertokens }}" - notify: Restart wsgi process - -- name: Ensure Apache ServerSignature - ansible.builtin.lineinfile: - dest: "{{ horizon_apache_security_conf }}" - regexp: "^ServerSignature" - line: "ServerSignature {{ horizon_apache_serversignature }}" - notify: Restart wsgi process - -# Removing the Listen (or listen.conf inclusion) from apache config to prevent -# conflicts with ports.conf on CentOS and openSUSE -- name: Remove Listen from Apache config - ansible.builtin.lineinfile: - dest: "{{ horizon_apache_security_conf }}" - regexp: "^(Listen.*)" - backrefs: true - line: "#\\1" - notify: Restart wsgi process +- name: Including HTTPD role + ansible.builtin.import_role: + name: httpd + vars: + httpd_pki_dir: "{{ horizon_pki_dir }}" + httpd_pki_setup_host: "{{ horizon_pki_setup_host }}" + httpd_ssl_protocol: "{{ horizon_ssl_protocol }}" + httpd_ssl_cipher_suite_tls12: "{{ horizon_ssl_cipher_suite_tls12 }}" + httpd_ssl_cipher_suite_tls13: "{{ horizon_ssl_cipher_suite_tls13 }}" + httpd_pki_regen_cert: "{{ horizon_pki_regen_cert }}" + httpd_extra_packages: "{{ horizon_apache_distro_packages }}" + httpd_extra_modules: + - name: "wsgi" + state: "present" + httpd_vhosts: + - name: openstack_dashboard + address: "{{ horizon_bind_address }}" + port: "{{ (horizon_backend_ssl | bool) | ternary(horizon_listen_ports.https, horizon_listen_ports.http) }}" + log_level: "{{ horizon_log_level }}" + log_format: "{{ horizon_apache_custom_log_format }}" + server_name: "{{ horizon_server_name }}" + headers: + - 'RequestHeader set {{ horizon_secure_proxy_ssl_header }} "{{ horizon_external_ssl | ternary("https", "http") }}"' + options: + - "WSGIScriptAlias {{ horizon_webroot }} {{ horizon_lib_wsgi_file }}" + - >- + WSGIDaemonProcess horizon user={{ horizon_system_user_name }} group={{ horizon_system_group_name }} processes={{ horizon_wsgi_processes | default( + horizon_wsgi_threads) }} threads={{ horizon_wsgi_threads }} python-path={{ horizon_lib_dir | dirname }}/site-packages + - "WSGIProcessGroup horizon" + - "WSGIApplicationGroup %{GLOBAL}" + - "Alias {{ horizon_webroot }}/static {{ horizon_lib_dir }}/static/" + directories: + - path: "{{ horizon_lib_wsgi_file | dirname }}" + options: + - "" + - " Require all granted" + - "" + - path: "{{ horizon_lib_dir }}/static/" + options: + - Options -FollowSymlinks + - Require all granted + - AddOutputFilterByType DEFLATE application/json + - AddOutputFilterByType DEFLATE text/javascript + - AddOutputFilterByType DEFLATE text/plain + - AddOutputFilterByType DEFLATE text/xml + - AddOutputFilterByType DEFLATE text/html + ssl: "{{ horizon_backend_ssl | ternary(_horizon_httpd_vhost_ssl, false) }}" + tags: + - horizon-install + - horizon-config + - httpd diff --git a/tasks/horizon_pre_install.yml b/tasks/horizon_pre_install.yml index 4f3e6073..16865b5c 100644 --- a/tasks/horizon_pre_install.yml +++ b/tasks/horizon_pre_install.yml @@ -41,15 +41,3 @@ - { path: "/openstack/venvs", mode: "0755", owner: "root", group: "root" } - { path: "/etc/horizon", mode: "2750" } - { path: "{{ horizon_system_user_home }}", mode: "2755" } - - { path: "/etc/pki/tls/certs", owner: "root", group: "root", condition: "{{ (ansible_facts['pkg_mgr'] == 'dnf') }}" } - - { path: "/etc/pki/tls/private", owner: "root", group: "root", condition: "{{ (ansible_facts['pkg_mgr'] == 'dnf') }}" } - -- name: Create system links - ansible.builtin.file: - src: "{{ item.src }}" - dest: "{{ item.dest }}" - state: "link" - with_items: - - { src: "/etc/pki/tls/certs", dest: "/etc/ssl/certs" } - - { src: "/etc/pki/tls/private", dest: "/etc/ssl/private" } - when: ansible_facts['pkg_mgr'] == 'dnf' diff --git a/tasks/main.yml b/tasks/main.yml index a47ce26e..fc8d246c 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -53,26 +53,6 @@ tags: - horizon-install -- name: Create and install SSL certificates - ansible.builtin.include_role: - name: pki - tasks_from: main_certs.yml - apply: - tags: - - horizon-config - - pki - vars: - pki_setup_host: "{{ horizon_pki_setup_host }}" - pki_dir: "{{ horizon_pki_dir }}" - pki_create_certificates: "{{ horizon_user_ssl_cert is not defined and horizon_user_ssl_key is not defined }}" - pki_regen_cert: "{{ horizon_pki_regen_cert }}" - pki_certificates: "{{ horizon_pki_certificates }}" - pki_install_certificates: "{{ horizon_pki_install_certificates }}" - when: - - horizon_backend_ssl - tags: - - always - - name: Importing horizon_post_install tasks ansible.builtin.import_tasks: horizon_post_install.yml tags: diff --git a/templates/horizon_apache_ports.conf.j2 b/templates/horizon_apache_ports.conf.j2 deleted file mode 100644 index 3c32de37..00000000 --- a/templates/horizon_apache_ports.conf.j2 +++ /dev/null @@ -1,6 +0,0 @@ -# {{ ansible_managed }} - -# We place a blank file here -# Listen commands happen inside the individual VHost files -# This allows for multiple services VHosts to exist without -# overwriting Listen lines. diff --git a/templates/openstack_dashboard.conf.j2 b/templates/openstack_dashboard.conf.j2 deleted file mode 100644 index e8e912ee..00000000 --- a/templates/openstack_dashboard.conf.j2 +++ /dev/null @@ -1,82 +0,0 @@ -# {{ ansible_managed }} - -{% for horizon_listen_port in horizon_listen_ports.values() %} -Listen {{ horizon_bind_address }}:{{ horizon_listen_port }} -{% endfor %} - -# If horizon is being served via SSL from this web server, -# then we must redirect HTTP requests to HTTPS. -{% if (horizon_backend_ssl | bool) %} - - ServerName {{ horizon_server_name }} - RewriteEngine On - RewriteCond %{HTTPS} !=on - RewriteRule ^/?(.*) https://%{HTTP_HOST}/$1 [R,L] - -{% endif %} - -# If horizon is being served via SSL via a load balancer, we -# need to listen via HTTP on this web server. If SSL is not -# enabled, then the same applies. - - ServerName {{ horizon_server_name }} - LogLevel {{ horizon_log_level }} - ErrorLog syslog:daemon - CustomLog "|/usr/bin/env logger -p daemon.info -t {{ horizon_system_service_name }}" {{ horizon_apache_custom_log_format }} - Options +FollowSymLinks -{% if horizon_backend_ssl | bool %} - SSLEngine on - SSLCertificateFile {{ horizon_ssl_cert }} - SSLCertificateKeyFile {{ horizon_ssl_key }} - {% if horizon_user_ssl_ca_cert is defined -%} - SSLCACertificateFile {{ horizon_ssl_ca_cert }} - {% endif -%} - SSLCompression Off - SSLProtocol {{ horizon_ssl_protocol }} - SSLHonorCipherOrder On - {% if horizon_ssl_cipher_suite_tls12 != "" -%} - SSLCipherSuite {{ horizon_ssl_cipher_suite_tls12 }} - {% endif -%} - {% if horizon_ssl_cipher_suite_tls13 != "" -%} - SSLCipherSuite TLSv1.3 {{ horizon_ssl_cipher_suite_tls13 }} - {% endif -%} - SetEnvIf User-Agent ".*MSIE.*" nokeepalive ssl-unclean-shutdown -{% endif %} -{% if horizon_external_ssl | bool %} - RequestHeader set {{ horizon_secure_proxy_ssl_header }} "https" -{% else %} - RequestHeader set {{ horizon_secure_proxy_ssl_header }} "http" -{% endif %} - - WSGIScriptAlias {{ horizon_webroot }} {{ horizon_lib_wsgi_file }} - WSGIDaemonProcess horizon user={{ horizon_system_user_name }} group={{ horizon_system_group_name }} processes={{ horizon_wsgi_processes | default(horizon_wsgi_threads) }} threads={{ horizon_wsgi_threads }} python-path={{ horizon_lib_dir | dirname }}/site-packages - - WSGIProcessGroup horizon - WSGIApplicationGroup %{GLOBAL} - - - - - Order allow,deny - Allow from all - - = 2.4> - Require all granted - - - - - Alias {{ horizon_webroot }}/static {{ horizon_lib_dir }}/static/ - - - Options -FollowSymlinks - - AllowOverride None - Order allow,deny - Allow from all - - = 2.4> - Require all granted - - - diff --git a/vars/debian.yml b/vars/debian.yml index fbea8c0a..daea8c6f 100644 --- a/vars/debian.yml +++ b/vars/debian.yml @@ -26,8 +26,6 @@ horizon_devel_distro_packages: - libpcre3-dev horizon_apache_distro_packages: - - apache2 - - apache2-utils - libapache2-mod-wsgi-py3 horizon_distro_packages: @@ -39,34 +37,6 @@ horizon_service_distro_packages: - python3-django-horizon - python3-memcache -horizon_apache_conf: "/etc/apache2/apache2.conf" -horizon_apache_security_conf: "/etc/apache2/conf-available/security.conf" - -horizon_apache_site_available: "/etc/apache2/sites-available/openstack-dashboard.conf" -horizon_apache_site_enabled: "/etc/apache2/sites-enabled/openstack-dashboard.conf" - -horizon_apache_configs: - - { src: "horizon_apache_ports.conf.j2", dest: "/etc/apache2/ports.conf", owner: "root", group: "root" } - - { src: "openstack_dashboard.conf.j2", dest: "{{ horizon_apache_site_available }}", owner: "root", group: "root" } - -horizon_apache_default_sites: - - "/etc/apache2/sites-enabled/000-default.conf" - - "/etc/apache2/conf-enabled/other-vhosts-access-log.conf" - -horizon_apache_mpms: - - name: "mpm_event" - state: "{{ (horizon_apache_mpm_backend == 'event') | ternary('present', 'absent') }}" - - name: "mpm_worker" - state: "{{ (horizon_apache_mpm_backend == 'worker') | ternary('present', 'absent') }}" - - name: "mpm_prefork" - state: "{{ (horizon_apache_mpm_backend == 'prefork') | ternary('present', 'absent') }}" - -horizon_apache_modules: - - name: "wsgi" - state: "present" - - name: "ssl" - state: "present" - - name: "rewrite" - state: "present" - - name: "headers" - state: "present" +horizon_deprecated_apache_configs: + - /etc/apache2/sites-available/openstack-dashboard.conf + - /etc/apache2/sites-enabled/openstack-dashboard.conf diff --git a/vars/distro_install.yml b/vars/distro_install.yml index 5d77abc7..89140b36 100644 --- a/vars/distro_install.yml +++ b/vars/distro_install.yml @@ -13,16 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -horizon_package_list: >- - {{ - horizon_distro_packages | union( - ( - (horizon_use_uwsgi | bool) | ternary([], horizon_apache_distro_packages) - ) - ) | union( - horizon_service_distro_packages - ) - }} +horizon_package_list: "{{ horizon_distro_packages | union(horizon_service_distro_packages) }}" _horizon_bin: "/usr/bin" diff --git a/vars/main.yml b/vars/main.yml index 3c2b9dba..57756ebf 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -42,6 +42,18 @@ horizon_dashboard_panel_dir: "{{ horizon_lib_dir }}/openstack_dashboard/local/en horizon_dashboard_settings_dir: "{{ horizon_lib_dir }}/openstack_dashboard/local/local_settings.d" horizon_manage: "{{ horizon_bin }}/horizon-manage.py" +_horizon_httpd_vhost_ssl: |- + {% set ssl_options = {} %} + {% if (horizon_user_ssl_cert is defined and horizon_user_ssl_cert) and (horizon_user_ssl_key is defined and horizon_user_ssl_key) %} + {% set _ = ssl_options.update({'cert': horizon_user_ssl_cert, 'key': horizon_user_ssl_key}) %} + {% if horizon_user_ssl_ca_cert is defined and horizon_user_ssl_ca_cert %} + {% set _ = ssl_options.update({'ca': horizon_user_ssl_ca_cert}) %} + {% endif %} + {% else %} + {% set _ = ssl_options.update({'san': horizon_pki_san}) %} + {% endif %} + {{ ssl_options }} + _horizon_uwsgi_ini_requirements: uwsgi: static-map: "/static={{ horizon_lib_dir }}/static/" diff --git a/vars/redhat.yml b/vars/redhat.yml index c40177a2..be2d7ed2 100644 --- a/vars/redhat.yml +++ b/vars/redhat.yml @@ -23,9 +23,6 @@ horizon_devel_distro_packages: - pcre-devel horizon_apache_distro_packages: - - httpd - - httpd-tools - - mod_ssl - python3-mod_wsgi horizon_distro_packages: @@ -45,14 +42,5 @@ horizon_service_distro_packages: - python3-django-horizon - python3-memcached -horizon_apache_conf: "/etc/httpd/conf/httpd.conf" -horizon_apache_security_conf: "{{ horizon_apache_conf }}" - -horizon_apache_configs: - - { src: "horizon_apache_ports.conf.j2", dest: "/etc/httpd/conf.d/ports.conf", owner: "root", group: "root" } - - { src: "openstack_dashboard.conf.j2", dest: "/etc/httpd/conf.d/openstack-dashboard.conf", owner: "root", group: "root" } - -horizon_apache_default_sites: - - "/etc/httpd/conf.d/userdir.conf" - - "/etc/httpd/conf.d/welcome.conf" - - "/etc/httpd/conf.d/ssl.conf" +horizon_deprecated_apache_configs: + - /etc/httpd/conf.d/openstack-dashboard.conf diff --git a/vars/source_install.yml b/vars/source_install.yml index 43f8fcb9..8dd32427 100644 --- a/vars/source_install.yml +++ b/vars/source_install.yml @@ -13,14 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -horizon_package_list: >- - {{ - horizon_distro_packages | union( - ( - (horizon_use_uwsgi | bool) | ternary([], horizon_apache_distro_packages) - ) - ) - }} +horizon_package_list: "{{ horizon_distro_packages }}" _horizon_bin: "/openstack/venvs/horizon-{{ horizon_venv_tag }}/bin"