diff --git a/ansible-role-requirements.yml b/ansible-role-requirements.yml index d77fa40697..607bbcd464 100644 --- a/ansible-role-requirements.yml +++ b/ansible-role-requirements.yml @@ -318,3 +318,7 @@ scm: git version: master trackbranch: master +- name: pki + src: https://opendev.org/openstack/ansible-role-pki + scm: git + trackbranch: master diff --git a/doc/source/user/security/ssl-certificates.rst b/doc/source/user/security/ssl-certificates.rst index be85fdac37..48bc8f07d8 100644 --- a/doc/source/user/security/ssl-certificates.rst +++ b/doc/source/user/security/ssl-certificates.rst @@ -9,7 +9,8 @@ communication between services: .. _OpenStack Security Guide: https://docs.openstack.org/security-guide/secure-communication.html All public endpoints reside behind haproxy, resulting in the only certificate -management most environments need are those for haproxy. +management for externally visible https services are those for haproxy. +Certain internal services such as RabbitMQ also require proper SSL configuration. When deploying with OpenStack-Ansible, you can either use self-signed certificates that are generated during the deployment process or provide @@ -23,33 +24,47 @@ user-provided certificates for as many services as possible. ``/etc/openstack_deploy/user_variables.yml`` file. Do not edit the playbooks or roles themselves. +Openstack-Ansible uses an ansible role `ansible_role_pki`_ as a general tool to +manage and install self-signed and user provided certificates. + +.. _ansible_role_pki: https://opendev.org/openstack/ansible-role-pki + Self-signed certificates ~~~~~~~~~~~~~~~~~~~~~~~~ Self-signed certificates enable you to start quickly and encrypt data in -transit. However, they do not provide a high level of trust for highly -secure environments. By default, self-signed certificates are used in -OpenStack-Ansible. When self-signed certificates are used, certificate -verification is automatically disabled. +transit. However, they do not provide a high level of trust for public +endpoints in highly secure environments. By default, self-signed certificates +are used in OpenStack-Ansible. When self-signed certificates are used, +certificate verification is automatically disabled. -Setting subject data for self-signed certificates -------------------------------------------------- +Self-signed certificates can play an important role in securing internal +services within the Openstack-Ansible deployment, as they can only be issued +by the private CA associated with the deployment. Using mutual TLS between +backend services such as RabbitMQ and MariaDB with self-signed certificates +and a robust CA setup can ensure that only correctly authenticated clients +can connect to these internal services. -Change the subject data of any self-signed certificate by using -configuration variables. The configuration variable for each service -is formatted as ``_ssl_self_signed_subject``. For example, to -change the SSL certificate subject data for HAProxy, adjust the -``/etc/openstack_deploy/user_variables.yml`` file as follows: +Generating and regenerating self-signed certificate authorities +--------------------------------------------------------------- -.. code-block:: yaml +A self-signed certificate authority is generated on the deploy host +during the first run of the playbook. - haproxy_ssl_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT/CN=haproxy.example.com" +To regenerate the certificate authority you must set the +``openstack_pki_regen_ca`` variable to either the name of the root CA +or intermediate CA you wish or regenerate, or to ``true`` to regenerate +all self-signed certificate authorities. + .. code-block:: shell-session -For more information about the available fields in the certificate subject, -see the OpenSSL documentation for the `req subcommand`_. + # openstack-ansible -e "openstack_pki_regen_ca=ExampleCorpIntermediate" certificate-authority.yml -.. _req subcommand: https://www.openssl.org/docs/manmaster/man1/req.html +Take particular care not to regenerate Root or Intermediate certificate +authorities in a way that may invalidate existing server certificates in the +deployment. It may be preferable to create new Intermediate CA certificates +rather than regenerate existing ones in order to maintain existing chains of +trust. Generating and regenerating self-signed certificates ---------------------------------------------------- @@ -58,7 +73,7 @@ Self-signed certificates are generated for each service during the first run of the playbook. To generate a new self-signed certificate for a service, you must set -the ``_ssl_self_signed_regen`` variable to true in one of the +the ``_pki_regen_cert`` variable to true in one of the following ways: * To force a self-signed certificate to regenerate, you can pass the variable @@ -66,23 +81,18 @@ following ways: .. code-block:: shell-session - # openstack-ansible -e "horizon_ssl_self_signed_regen=true" os-horizon-install.yml + # openstack-ansible -e "haproxy_pki_regen_cert=true" haproxy-install.yml * To force a self-signed certificate to regenerate with every playbook run, set the appropriate regeneration option to ``true``. For example, if you have already run the ``haproxy`` playbook, but you want to regenerate - the self-signed certificate, set the ``haproxy_ssl_self_signed_regen`` + the self-signed certificate, set the ``haproxy_pki_regen_cert`` variable to ``true`` in the ``/etc/openstack_deploy/user_variables.yml`` file: .. code-block:: yaml - haproxy_ssl_self_signed_regen: true - -.. note:: - - Regenerating self-signed certificates replaces the existing - certificates whether they are self-signed or user-provided. + haproxy_pki_regen_cert: true User-provided certificates diff --git a/inventory/group_vars/all/infra.yml b/inventory/group_vars/all/infra.yml index f238f6c132..139b973d92 100644 --- a/inventory/group_vars/all/infra.yml +++ b/inventory/group_vars/all/infra.yml @@ -17,7 +17,7 @@ rabbitmq_host_group: "rabbitmq_all" rabbitmq_port: "{{ (rabbitmq_use_ssl | bool) | ternary(5671, 5672) }}" -rabbitmq_use_ssl: False +rabbitmq_use_ssl: True rabbitmq_servers: >- {{ groups[rabbitmq_host_group] diff --git a/inventory/group_vars/all/ssl.yml b/inventory/group_vars/all/ssl.yml index f214ce76e9..86346d84dd 100644 --- a/inventory/group_vars/all/ssl.yml +++ b/inventory/group_vars/all/ssl.yml @@ -19,3 +19,48 @@ ssl_protocol: "ALL -SSLv2 -SSLv3 -TLSv1.0 -TLSv1.1" # Cipher suite string from https://hynek.me/articles/hardening-your-web-servers-ssl-ciphers/ ssl_cipher_suite: "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:RSA+AESGCM:RSA+AES:!aNULL:!MD5:!DSS" + +#variables used in OSA roles which call the PKI role +openstack_pki_dir: "/etc/openstack_deploy/pki" +openstack_pki_service_intermediate_cert_name: "ExampleCorpIntermediate" + +openstack_pki_service_intermediate_cert_path: "{{ openstack_pki_dir ~ '/roots/' ~ openstack_pki_service_intermediate_cert_name ~ '/certs/' ~ openstack_pki_service_intermediate_cert_name ~ '.crt' }}" + +# regenerate the CA or intermediate CA +openstack_pki_regen_ca: '' + +#example self-signed certificate authority +openstack_pki_authorities: + - name: "ExampleCorpRoot" + provider: selfsigned + basic_constraints: "CA:TRUE" + cn: "Example Corp Root CA" + email_address: "pki@example.com" + country_name: "GB" + state_or_province_name: "England" + organization_name: "Example Corporation" + organizational_unit_name: "IT Security" + key_usage: + - digitalSignature + - cRLSign + - keyCertSign + not_after: "+3650d" + - name: "ExampleCorpIntermediate" + provider: ownca + basic_constraints: "CA:TRUE,pathlen:0" + cn: "Example Corp Openstack Infrastructure Intermediate CA" + email_address: "pki@example.com" + country_name: "GB" + state_or_province_name: "England" + organization_name: "Example Corporation" + organizational_unit_name: "IT Security" + key_usage: + - digitalSignature + - cRLSign + - keyCertSign + not_after: "+3650d" + signed_by: "ExampleCorpRoot" + +#install the root CA certificate on all hosts and containers +openstack_pki_install_ca: + - name: "ExampleCorpRoot" \ No newline at end of file diff --git a/playbooks/certificate-authority.yml b/playbooks/certificate-authority.yml new file mode 100644 index 0000000000..400f03927b --- /dev/null +++ b/playbooks/certificate-authority.yml @@ -0,0 +1,28 @@ +# Copyright 2021, BBC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +- name: Create CA certificates + hosts: "{{ openstack_pki_setup_host | default('localhost') }}" + gather_facts: "{{ osa_gather_facts | default(True) }}" + tags: + - always + tasks: + - name: "Create CA certificates" + include_role: + name: pki + tasks_from: main_ca.yml + vars: + pki_dir: "{{ openstack_pki_dir }}" + pki_create_ca: "{{ openstack_pki_authorities is defined | bool }}" + pki_authorities: "{{ openstack_pki_authorities }}" diff --git a/playbooks/haproxy-install.yml b/playbooks/haproxy-install.yml index 42e93c7311..6e1edaf59d 100644 --- a/playbooks/haproxy-install.yml +++ b/playbooks/haproxy-install.yml @@ -43,6 +43,12 @@ - "item.when | bool" tags: - haproxy-config # this tag is present because the task is ONLY a config task + - name: "Create haproxy certificates" + include_role: + name: pki + tasks_from: main_certs.yml + vars: + pki_search_certificates_pattern: "pki_certificates_haproxy" roles: - role: "keepalived" when: haproxy_use_keepalived | bool diff --git a/playbooks/setup-hosts.yml b/playbooks/setup-hosts.yml index 86bc9b4662..001db9a46a 100644 --- a/playbooks/setup-hosts.yml +++ b/playbooks/setup-hosts.yml @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +- import_playbook: certificate-authority.yml - import_playbook: openstack-hosts-setup.yml - import_playbook: containers-deploy.yml - import_playbook: security-hardening.yml diff --git a/releasenotes/notes/pki-role-4675baf7c0134bfe.yaml b/releasenotes/notes/pki-role-4675baf7c0134bfe.yaml new file mode 100644 index 0000000000..7de9aaef8c --- /dev/null +++ b/releasenotes/notes/pki-role-4675baf7c0134bfe.yaml @@ -0,0 +1,29 @@ +--- +features: + - | + A new ansible role (ansible-role-pki) is introduced to manage the creation + of server certificates and certificate authorities. A self signed Root CA + and Intermediate CA are created on the deploy host and are used to provide + TLS for RabbitMQ, and with the default configuration also a self-signed server + certificate for HAProxy. A set of new variables with the prefix + openstack_pki_* are introduced which allow a deployer to customise and + extend the set of certificate authorities which are created. Root certificate + authorities are installed into the trust store of all hosts and containers + allowing a complete trust chain to be formed across the deployment which + has never previously been possible. +upgrade: + - | + It is now mandatory to use a verifiable SSL certificate and Certificate + Authority trust chain for the RabbitMQ installation. This can be achieved + automatically through the new ansible role ansibe-role-pki with appropriate + addition of openstack_pki_* variables. + Any existing deployments which use the rabbitmq_user_ssl_* variables must + ensure that the supplied certificates can be verified by a CA certificate + installed into the trust store of each host and container. This can be + achieved through supplying the CA certificate on the deploy host and using + overrides from the openstack_hosts role to install it. +deprecations: + - | + The variables `haproxy_ssl_self_signed_regen` and `haproxy_ssl_self_signed_subject` + are removed and the equivalent functionaility from the ansible-role-pki + variables should be used instead. diff --git a/zuul.d/jobs.yaml b/zuul.d/jobs.yaml index b95b5dfb62..f416dbc9b4 100644 --- a/zuul.d/jobs.yaml +++ b/zuul.d/jobs.yaml @@ -98,6 +98,7 @@ - name: openstack/ansible-role-systemd_networkd - name: openstack/ansible-role-python_venv_build - name: openstack/ansible-role-uwsgi + - name: openstack/ansible-role-pki # OpenStack service repos - listed here to make cached repos available in CI - name: openstack/requirements # OpenStack service repos - listed here as the corresponding OSA role cannot do distro install @@ -166,6 +167,7 @@ - name: openstack/ansible-role-systemd_networkd - name: openstack/ansible-role-python_venv_build - name: openstack/ansible-role-uwsgi + - name: openstack/ansible-role-pki # OpenStack service repos - listed here to make cached repos available in CI - name: openstack/requirements - name: openstack/adjutant