Serve security.txt directly from haproxy

Currently security.txt file is stored and served from keystone.
It's not necessary as haproxy is able to serve static files[1].

This patch creates security_txt haproxy service responsible for
serving security.txt static file using recently implemented maps feature.

[1] https://sleeplessbeastie.eu/2020/05/11/how-to-serve-single-file-using-haproxy/

Depends-On: https://review.opendev.org/c/openstack/openstack-ansible-haproxy_server/+/880088

Change-Id: If0ec375055abedceb13a035b9c8f5107f4659f86
This commit is contained in:
Damian Dabrowski
2023-04-11 23:00:19 +02:00
parent 507cae2465
commit 73a8bdde58
3 changed files with 27 additions and 19 deletions

View File

@@ -9,9 +9,8 @@ legacy compatibility reasons the file might also be placed at "/security.txt".
.. _IETF standard: https://datatracker.ietf.org/doc/html/draft-foudil-securitytxt .. _IETF standard: https://datatracker.ietf.org/doc/html/draft-foudil-securitytxt
In OpenStack-Ansible, ``security.txt`` is implemented in haproxy as all public In OpenStack-Ansible, ``security.txt`` is implemented in haproxy as all public
endpoints reside behind it and the text file is hosted by keystone. It defaults endpoints reside behind it. It defaults to directing any request paths that
to directing any request paths that end with ``/security.txt`` to the text end with ``/security.txt`` to the text file using an ACL rule in haproxy.
file using an ACL rule in haproxy.
Enabling security.txt Enabling security.txt
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
@@ -22,21 +21,15 @@ using OpenStack-Ansible:
#. Write the contents of the ``security.txt`` file in accordance with the #. Write the contents of the ``security.txt`` file in accordance with the
standard. standard.
#. Define the contents of ``security.txt`` in the variable #. Define the contents of ``security.txt`` in the variable
``keystone_security_txt_content`` in the ``haproxy_security_txt_content`` in the
``/etc/openstack_deploy/user_variables.yml`` file: ``/etc/openstack_deploy/user_variables.yml`` file:
.. code-block:: yaml .. code-block:: yaml
keystone_security_txt_content: | haproxy_security_txt_content: |
# This is my example security.txt file # This is my example security.txt file
# Please see https://securitytxt.org/ for details of the specification of this file # Please see https://securitytxt.org/ for details of the specification of this file
#. Update keystone
.. code-block:: shell-session
# openstack-ansible os-keystone-install.yml
#. Update haproxy #. Update haproxy
.. code-block:: shell-session .. code-block:: shell-session
@@ -50,5 +43,4 @@ In some cases you may need to change the haproxy ACL used to redirect requests
to the ``security.txt`` file, such as adding extra domains. to the ``security.txt`` file, such as adding extra domains.
The haproxy ACL is updated by overriding the variable The haproxy ACL is updated by overriding the variable
``haproxy_security_txt_acl`` in the ``haproxy_map_entries`` inside ``haproxy_security_txt_service``.
``/etc/openstack_deploy/user_variables.yml`` file.

View File

@@ -35,11 +35,6 @@ haproxy_stick_table_allowlist_networks: "{{ haproxy_allowlist_networks }}"
haproxy_ironic_allowlist_networks: "{{ haproxy_allowlist_networks }}" haproxy_ironic_allowlist_networks: "{{ haproxy_allowlist_networks }}"
haproxy_ironic_inspector_allowlist_networks: "{{ haproxy_allowlist_networks }}" haproxy_ironic_inspector_allowlist_networks: "{{ haproxy_allowlist_networks }}"
haproxy_security_txt_acl:
keystone-security-txt-acl:
rule: "path_end /security.txt"
backend_name: keystone_service
# Variables to set security headers used by browsers # Variables to set security headers used by browsers
haproxy_security_headers_max_age: 31536000 haproxy_security_headers_max_age: 31536000
# Set CSP headers to report only for testing # Set CSP headers to report only for testing
@@ -88,6 +83,21 @@ openstack_haproxy_horizon_stick_table:
- "http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 } { path_beg /auth } !{ src {{haproxy_stick_table_allowlist_networks | join(' } !{ src ') }} }" - "http-request deny deny_status 429 if { sc_http_req_rate(0) gt 20 } { path_beg /auth } !{ src {{haproxy_stick_table_allowlist_networks | join(' } !{ src ') }} }"
- "http-request deny deny_status 429 if { sc_http_err_rate(0) gt 20 } !{ src {{haproxy_stick_table_allowlist_networks | join(' } !{ src ') }} }" - "http-request deny deny_status 429 if { sc_http_err_rate(0) gt 20 } !{ src {{haproxy_stick_table_allowlist_networks | join(' } !{ src ') }} }"
haproxy_security_txt_service:
haproxy_backend_only: true
haproxy_service_name: security_txt
haproxy_backend_nodes: []
haproxy_balance_type: http
haproxy_service_enabled: "{{ haproxy_security_txt_content is truthy }}"
# https://sleeplessbeastie.eu/2020/05/11/how-to-serve-single-file-using-haproxy/
haproxy_backend_arguments:
- 'errorfile 503 /etc/haproxy/security.txt'
haproxy_map_entries:
- name: base_regex
entries:
- '.*/security.txt security_txt-back'
# haproxy 'base' frontend-only service that is used always deployed for port 80 redirect and 443 # haproxy 'base' frontend-only service that is used always deployed for port 80 redirect and 443
# this potentially supports horizon dashboard, security.txt and certbot # this potentially supports horizon dashboard, security.txt and certbot
# plus any other user defined custom backend # plus any other user defined custom backend
@@ -102,7 +112,6 @@ haproxy_base_service:
haproxy_service_enabled: true haproxy_service_enabled: true
haproxy_redirect_scheme: "{{ (haproxy_ssl_letsencrypt_enable | bool and haproxy_ssl | bool) | ternary('https if !{ ssl_fc } !{ path_beg /.well-known/acme-challenge/ }', 'https if !{ ssl_fc }') }}" haproxy_redirect_scheme: "{{ (haproxy_ssl_letsencrypt_enable | bool and haproxy_ssl | bool) | ternary('https if !{ ssl_fc } !{ path_beg /.well-known/acme-challenge/ }', 'https if !{ ssl_fc }') }}"
haproxy_frontend_acls: "{{ (haproxy_ssl_letsencrypt_enable | bool and haproxy_ssl | bool) | ternary(haproxy_ssl_letsencrypt_acl, {}) }}" haproxy_frontend_acls: "{{ (haproxy_ssl_letsencrypt_enable | bool and haproxy_ssl | bool) | ternary(haproxy_ssl_letsencrypt_acl, {}) }}"
haproxy_acls: "{{ keystone_security_txt_content is defined | ternary(haproxy_security_txt_acl, {}) }}"
haproxy_frontend_raw: "{{ (haproxy_ssl | bool and haproxy_security_headers is defined) | ternary( haproxy_security_headers + [ haproxy_horizon_csp | default(haproxy_security_headers_csp)], []) }}" haproxy_frontend_raw: "{{ (haproxy_ssl | bool and haproxy_security_headers is defined) | ternary( haproxy_security_headers + [ haproxy_horizon_csp | default(haproxy_security_headers_csp)], []) }}"
haproxy_maps: haproxy_maps:
- 'use_backend %[path,map_reg(/etc/haproxy/base_regex.map)]' - 'use_backend %[path,map_reg(/etc/haproxy/base_regex.map)]'
@@ -634,6 +643,7 @@ haproxy_zun_console_service:
haproxy_service_enabled: "{{ groups['zun_api'] is defined and groups['zun_api'] | length > 0 }}" haproxy_service_enabled: "{{ groups['zun_api'] is defined and groups['zun_api'] | length > 0 }}"
haproxy_default_services: haproxy_default_services:
- service: "{{ haproxy_security_txt_service | combine(haproxy_security_txt_service_overrides | default({})) }}"
- service: "{{ haproxy_base_service | combine(haproxy_base_service_overrides | default({})) }}" - service: "{{ haproxy_base_service | combine(haproxy_base_service_overrides | default({})) }}"
- service: "{{ haproxy_adjutant_api_service | combine(haproxy_adjutant_api_service_overrides | default({})) }}" - service: "{{ haproxy_adjutant_api_service | combine(haproxy_adjutant_api_service_overrides | default({})) }}"
- service: "{{ haproxy_aodh_api_service | combine(haproxy_aodh_api_service_overrides | default({})) }}" - service: "{{ haproxy_aodh_api_service | combine(haproxy_aodh_api_service_overrides | default({})) }}"

View File

@@ -0,0 +1,6 @@
---
upgrade:
- |
``keystone_security_txt_content`` variable name has changed to
``haproxy_security_txt_content``. Security.txt file is now served
directly from haproxy.