diff --git a/doc/source/user/security/index.rst b/doc/source/user/security/index.rst index 185bc2837d..7c725cd902 100644 --- a/doc/source/user/security/index.rst +++ b/doc/source/user/security/index.rst @@ -11,4 +11,6 @@ For understanding security design, please see :ref:`security-design`. .. include:: ssl-certificates.rst +.. include:: security-headers.rst +.. include:: security-txt.rst .. include:: hardening.rst diff --git a/doc/source/user/security/security-headers.rst b/doc/source/user/security/security-headers.rst new file mode 100644 index 0000000000..781ce910df --- /dev/null +++ b/doc/source/user/security/security-headers.rst @@ -0,0 +1,127 @@ +Security Headers +================ + +Security headers are HTTP headers that can be used to increase the security of +a web application by restricting what modern browsers are able to run. + +In OpenStack-Ansible, security headers are implemented in haproxy as all the +public endpoints reside behind it. + +The following headers are enabled by default on all the haproxy interfaces +that implement TLS, but only for the Horizon service. The security headers can +be implemented on other haproxy services, but only services used by +browsers will make use of the headers. + +HTTP Strict Transport Security +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The `OpenStack TLS Security Guide`_ recommends that all production deployments use +HTTP strict transport security (HSTS). + +.. _OpenStack TLS Security Guide: https://docs.openstack.org/security-guide/secure-communication/tls-proxies-and-http-services.html#http-strict-transport-security + +By design, this header is difficult to disable once set. It is recommended that +during testing you set a short time of 1 day and after testing increase the time +to 1 year. + +To change the default max age to 1 day, override the variable +``haproxy_security_headers_max_age`` in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + haproxy_security_headers_max_age: 86400 + +If you would like your domain included in the HSTS preload list, which is built +into browsers, before submitting your request to be added to the HSTS preload +list you must add the ``preload`` token to your response header. The ``preload`` +token indicates to the maintainers of HSTS preload list that you are happy to +have your site included. + +.. code-block:: yaml + + - "http-response set-header Strict-Transport-Security \"max-age={{ haproxy_security_headers_max_age }}; includeSubDomains; preload;\"" + +X-Content-Type-Options +~~~~~~~~~~~~~~~~~~~~~~ + +The ``X-Content-Type-Options`` header prevents MIME type sniffing. + +This functionality can be changed by overriding the list of headers in +``haproxy_security_headers`` variable in the +``/etc/openstack_deploy/user_variables.yml`` file. + +Referrer Policy +~~~~~~~~~~~~~~~ + +The ``Referrer-Policy`` header controls how much referrer information is sent +with requests. It defaults to ``same-origin``, which does not send the origin +path for cross-origin requests. + +This functionality can be changed by overriding the list of headers in +``haproxy_security_headers`` variable in the +``/etc/openstack_deploy/user_variables.yml`` file. + +Permission Policy +~~~~~~~~~~~~~~~~~ + +The ``Permissions-Policy`` header allows you to selectively enable, disable or +modify the use of browser features and APIs, previously known as Feature Policy. + +By default this header is set to block access to all features apart from the +following from the same origin; fullscreen, clipboard read, clipboard +write and spatial navigation. + +This functionality can be changed by overriding the list of headers in +``haproxy_security_headers`` variable in the +``/etc/openstack_deploy/user_variables.yml`` file. + + +Content Security Policy (CSP) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +The ``Content-Security-Policy`` header allows you to control what resources a +browser is allowed to load for a given page, which helps to mitigate the risks +from Cross-Site Scripting (XSS) and data injection attacks. + +By default, the Content Security Policy (CSP) enables a minimum set of resources +to allow Horizon to work, which includes access the Nova console. If you require +access to other resources these can be set by overriding the +``haproxy_security_headers_csp`` variable in the +``/etc/openstack_deploy/user_variables.yml`` file. + +Report Only +----------- + +Implementing CSP could lead to broken content if a browser is blocked from +accessing certain resources, therefore it is recommended that when testing CSP +you use the ``Content-Security-Policy-Report-Only`` header, instead of +``Content-Security-Policy``, this reports CSP violations to the browser console, +but does not enforce the policy. + +To set the CSP policy to report only by overriding the +``haproxy_security_headers_csp_report_only`` variable to ``True`` in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + haproxy_security_headers_csp_report_only: True + + +Reporting Violations +-------------------- + +It is recommended that you monitor attempted CSP violations in production, this +is achieved by setting the ``report-uri`` and ``report-to`` tokens. + +Federated Login +--------------- + +When using federated login you will need to override the default Content +Security Policy to allow access to your authorisation server by overriding the +``haproxy_horizon_csp`` variable in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + haproxy_horizon_csp: "http-response set-header Content-Security-Policy \"default-src 'self'; frame-ancestors 'self'; form-action 'self' {{ external_lb_vip_address }}:5000 ; upgrade-insecure-requests; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self' {{ external_lb_vip_address }}:{{ nova_console_port }}; frame-src 'self' {{ external_lb_vip_address }}:{{ nova_console_port }};\"" diff --git a/doc/source/user/security/security-txt.rst b/doc/source/user/security/security-txt.rst new file mode 100644 index 0000000000..6b94340724 --- /dev/null +++ b/doc/source/user/security/security-txt.rst @@ -0,0 +1,54 @@ +Security.txt +============ + +security.txt is a proposed `IETF standard`_ to allow independent security +researchers to easily report vulnerabilities. The standard defines that a text +file called ``security.txt`` should be found at "/.well-known/security.txt". For +legacy compatibility reasons the file might also be placed at "/security.txt". + +.. _IETF standard: https://datatracker.ietf.org/doc/html/draft-foudil-securitytxt + +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 +to directing any request paths that end with ``/security.txt`` to the text +file using an ACL rule in haproxy. + +Enabling security.txt +~~~~~~~~~~~~~~~~~~~~~ + +Use the following process to add a ``security.txt`` file to your deployment +using OpenStack-Ansible: + +#. Write the contents of the ``security.txt`` file in accordance with the + standard. +#. Define the contents of ``security.txt`` in the variable + ``keystone_security_txt_content`` in the + ``/etc/openstack_deploy/user_variables.yml`` file: + + .. code-block:: yaml + + keystone_security_txt_content: | + # This is my example security.txt 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 + + .. code-block:: shell-session + + # openstack-ansible haproxy-install.yml + +Advanced security.txt ACL +~~~~~~~~~~~~~~~~~~~~~~~~~ + +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. + +The haproxy ACL is updated by overriding the variable +``haproxy_security_txt_acl`` in the +``/etc/openstack_deploy/user_variables.yml`` file. diff --git a/doc/source/user/security/ssl-certificates.rst b/doc/source/user/security/ssl-certificates.rst index 57337aa5f7..42eb395b3d 100644 --- a/doc/source/user/security/ssl-certificates.rst +++ b/doc/source/user/security/ssl-certificates.rst @@ -202,25 +202,34 @@ the preceding configuration variables with `horizon`, `haproxy`, or `keystone`, and then run the playbook for that service to deploy user-provided certificates to those services. -LetsEncrypt certificates -~~~~~~~~~~~~~~~~~~~~~~~~ +Certbot certificates +~~~~~~~~~~~~~~~~~~~~ -The HAProxy ansible role supports using LetsEncrypt to automatically deploy +The HAProxy ansible role supports using certbot to automatically deploy trusted SSL certificates for the public endpoint. Each HAProxy server will -individually request a LetsEncrypt certificate. +individually request a SSL certificate using certbot. + +Certbot defaults to using LetsEncrypt as the Certificate Authority, other +Certificate Authorities can be used by setting the +``haproxy_ssl_letsencrypt_certbot_server`` variable in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + haproxy_ssl_letsencrypt_certbot_server: "https://acme-staging-v02.api.letsencrypt.org/directory" The http-01 type challenge is used by certbot to deploy certificates so -it is required that the public endpoint is accessible directly on the -internet. +it is required that the public endpoint is accessible directly by the +Certificate Authority. -Deployment of certificates using LetsEncrypt has been validated for +Deployment of certificates using certbot has been validated for openstack-ansible using Ubuntu Bionic. Other distributions should work but are not tested. -To deploy certificates with LetsEncrypt, add the following to +To deploy certificates with certbot, add the following to ``/etc/openstack_deploy/user_variables.yml`` to enable the -letsencrypt function in the haproxy ansible role, and to -create a new backend service called ``letsencrypt`` to service +certbot function in the haproxy ansible role, and to +create a new backend service called ``certbot`` to service http-01 challenge requests. .. code-block:: shell-session @@ -253,3 +262,107 @@ backend is certbot on the haproxy host: haproxy_backend_port: 80 haproxy_backend_options: - "httpchk HEAD /" # request to use for health check for the example service + +TLS for Haproxy Internal VIP +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +As well as load balancing public endpoints, haproxy is also used to load balance +internal connections. + +By default, OpenStack-Ansible does not secure connections to the internal VIP. +To enable this you must set the following variables in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + openstack_service_adminuri_proto: https + openstack_service_internaluri_proto: https + + haproxy_ssl_all_vips: true + +Run all playbooks to configure haproxy and openstack services. + +When enabled haproxy will use the same TLS certificate on all interfaces +(internal and external). It is not currently possible in OpenStack-Ansible to +use different self-signed or user-provided TLS certificates on different haproxy +interfaces. + +The only way to use a different TLS certificates on the internal and external +VIP is to use certbot. + +Enabling TLS on the internal VIP for existing deployments will cause some +downtime, this is because haproxy only listens on a single well known port for +each OpenStack service and OpenStack services are configured to use http or +https. This means once haproxy is updated to only accept HTTPS connections, the +OpenStack services will stop working until they are updated to use HTTPS. + +For this reason it is recommended that TLS for haproxy internal VIP on existing +deployments is deployed at the same time as enabling TLS for Haproxy backends, +as this may also cause downtime. For new deployments this should be enabled from +the start. + +TLS for Haproxy Backends +~~~~~~~~~~~~~~~~~~~~~~~~ + +Securing the internal communications from haproxy to backend services is +currently work in progress. + +TLS for Live Migrations +~~~~~~~~~~~~~~~~~~~~~~~ + +Live migration of VM's using SSH is deprecated and the `OpenStack Nova Docs`_ +recommends using the more secure native TLS method supported by QEMU. The +default live migration method used by OpenStack-Ansible has been updated to +use TLS migrations. + +.. _OpenStack Nova Docs: https://docs.openstack.org/nova/latest/admin/secure-live-migration-with-qemu-native-tls.html + +QEMU-native TLS requires all compute hosts to accept TCP connections on +port 16514 and port range 49152 to 49261. + +It is not possible to have a mixed estate of some compute nodes using SSH and +some using TLS for live migrations, as this would prevent live migrations +between the compute nodes. + +There are no issues enabling TLS live migration during an OpenStack upgrade, as +long as you do not need to live migrate instances during the upgrade. If you +you need to live migrate instances during an upgrade, enable TLS live migrations +before or after the upgrade. + +To force the use of SSH instead of TLS for live migrations you must set the +``nova_libvirtd_listen_tls`` variable to ``0`` in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + nova_libvirtd_listen_tls: 0 + +TLS for VNC +~~~~~~~~~~~ + +When using VNC for console access there are 3 connections to secure, client to +haproxy, haproxy to noVNC Proxy and noVNC Proxy to Compute nodes. The `OpenStack +Nova Docs for remote console access`_ cover console security in much more +detail. + +.. _OpenStack Nova Docs for remote console access: https://docs.openstack.org/nova/latest/admin/remote-console-access.html#vnc-proxy-security + +In OpenStack-Ansible TLS to haproxy is configured in haproxy, TLS to noVNC is +not currently enabled and TLS to Compute nodes is enabled by default. + +To help with the transition from unencrypted VNC to VeNCrypt, +initially noVNC proxy auth scheme allows for both encrypted and +unencrypted sessions using the variable `nova_vencrypt_auth_scheme`. This will +be restricted to VeNCrypt only in future versions of OpenStack-Ansible. + +.. code-block:: yaml + + nova_vencrypt_auth_scheme: "vencrypt,none" + +To not encrypt data from noVNC proxy to Compute nodes you must set the +``nova_qemu_vnc_tls`` variable to ``0`` in the +``/etc/openstack_deploy/user_variables.yml`` file: + +.. code-block:: yaml + + nova_qemu_vnc_tls: 0 diff --git a/inventory/group_vars/haproxy/haproxy.yml b/inventory/group_vars/haproxy/haproxy.yml index c04134334a..78601245cc 100644 --- a/inventory/group_vars/haproxy/haproxy.yml +++ b/inventory/group_vars/haproxy/haproxy.yml @@ -39,8 +39,10 @@ haproxy_security_txt_acl: # Variables to set security headers used by browsers haproxy_security_headers_max_age: 31536000 +# Set CSP headers to report only for testing +haproxy_security_headers_csp_report_only: False # To override the CSP used by a specific service define a variable haproxy__csp -haproxy_security_headers_csp: "http-response set-header Content-Security-Policy \"default-src 'self'; frame-ancestors 'none'; form-action 'self'; upgrade-insecure-requests; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self' {{ external_lb_vip_address }}:{{ nova_console_port }}; frame-src 'self' {{ external_lb_vip_address }}:{{ nova_console_port }};\"" +haproxy_security_headers_csp: "http-response set-header {{ haproxy_security_headers_csp_report_only | ternary('Content-Security-Policy-Report-Only', 'Content-Security-Policy') }} \"default-src 'self'; frame-ancestors 'none'; form-action 'self'; upgrade-insecure-requests; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self' {{ external_lb_vip_address }}:{{ nova_console_port }}; frame-src 'self' {{ external_lb_vip_address }}:{{ nova_console_port }};\"" # To disable security headers set to [] haproxy_security_headers: - "http-response set-header Strict-Transport-Security \"max-age={{ haproxy_security_headers_max_age }}; includeSubDomains;\""