Merge "Add documentation of security improvements made to Openstack Ansible"

This commit is contained in:
Zuul 2021-12-14 16:38:11 +00:00 committed by Gerrit Code Review
commit e2921e84a3
5 changed files with 309 additions and 11 deletions

View File

@ -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

View File

@ -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 <YOUR-AUTHORISATION-SERVER-ORIGIN>; 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 }};\""

View File

@ -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.

View File

@ -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

View File

@ -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_<service name>_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;\""