From 4a1d412f8cd715f2829867026b64edabf97ad521 Mon Sep 17 00:00:00 2001 From: Major Hayden Date: Tue, 15 Sep 2015 09:52:19 -0500 Subject: [PATCH] Add SSL/TLS listener to RabbitMQ This patch adds a SSL/TLS listener to RabbitMQ without disrupting the existing plaintext TCP listener. Various services that use RabbitMQ will have the option to encrypt messaging traffic with this change. Documentation is included for this change. By default, it will create a self-signed certificate for the user, but users have the option to specify their own existing certificates as well. This makes it easier to bring RabbitMQ (and the services which talk to it) into compliance with PCI DSS 3.1's Requirement 2.2.3. In addition, this change is recommended within the OpenStack Security Guide. Closes-bug: 1496001 Change-Id: I0d29cbb6e963b24f77a8375eba8a8c6a558aaf81 --- .../install-guide/configure-rabbitmq.rst | 26 +++++++++++ doc/source/install-guide/configure.rst | 1 + doc/source/install-guide/navigation.txt | 1 + etc/openstack_deploy/user_variables.yml | 17 ++++++- .../roles/rabbitmq_server/defaults/main.yml | 17 +++++++ .../roles/rabbitmq_server/tasks/main.yml | 16 +++++++ .../tasks/rabbitmq_ssl_key_create.yml | 37 +++++++++++++++ .../tasks/rabbitmq_ssl_key_distribute.yml | 33 +++++++++++++ .../tasks/rabbitmq_ssl_key_store.yml | 31 +++++++++++++ .../tasks/rabbitmq_ssl_self_signed.yml | 31 +++++++++++++ .../tasks/rabbitmq_ssl_user_provided.yml | 46 +++++++++++++++++++ .../templates/rabbitmq.config.j2 | 9 ++++ 12 files changed, 263 insertions(+), 2 deletions(-) create mode 100644 doc/source/install-guide/configure-rabbitmq.rst create mode 100644 playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_create.yml create mode 100644 playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_distribute.yml create mode 100644 playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_store.yml create mode 100644 playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_self_signed.yml create mode 100644 playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_user_provided.yml diff --git a/doc/source/install-guide/configure-rabbitmq.rst b/doc/source/install-guide/configure-rabbitmq.rst new file mode 100644 index 0000000000..82f2830a6b --- /dev/null +++ b/doc/source/install-guide/configure-rabbitmq.rst @@ -0,0 +1,26 @@ +`Home `__ OpenStack Ansible Installation Guide + +Configuring RabbitMQ (optional) +------------------------------- + +RabbitMQ provides the messaging broker for various OpenStack services. The +openstack-ansible project configures a plaintext listener on port 5672 and +a SSL/TLS encrypted listener on port 5671. + +Customizing the RabbitMQ deployment is done within +``/etc/openstack_deploy/user_variables.yml``. + +Securing RabbitMQ communication with SSL certificates +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The openstack-ansible project provides the ability to secure RabbitMQ +communications with self-signed or user-provided SSL certificates. + +Refer to `Securing services with SSL certificates`_ for available configuration +options. + +.. _Securing services with SSL certificates: configure-sslcertificates.html + +-------------- + +.. include:: navigation.txt diff --git a/doc/source/install-guide/configure.rst b/doc/source/install-guide/configure.rst index 0668642b05..6199550083 100644 --- a/doc/source/install-guide/configure.rst +++ b/doc/source/install-guide/configure.rst @@ -15,6 +15,7 @@ Chapter 5. Deployment configuration configure-swift.rst configure-haproxy.rst configure-horizon.rst + configure-rabbitmq.rst configure-ceilometer.rst configure-keystone.rst configure-sslcertificates.rst diff --git a/doc/source/install-guide/navigation.txt b/doc/source/install-guide/navigation.txt index a2f196d6c2..ffafd61352 100644 --- a/doc/source/install-guide/navigation.txt +++ b/doc/source/install-guide/navigation.txt @@ -69,6 +69,7 @@ - `Configuring HAProxy (optional) `__ - `Configuring Horizon (optional) `__ - `Configuring Keystone (optional) `__ + - `Configuring RabbitMQ (optional) `__ - `Securing services with SSL certificates `__ diff --git a/etc/openstack_deploy/user_variables.yml b/etc/openstack_deploy/user_variables.yml index 8f383aa39c..10245f0934 100644 --- a/etc/openstack_deploy/user_variables.yml +++ b/etc/openstack_deploy/user_variables.yml @@ -101,7 +101,13 @@ glance_swift_store_endpoint_type: internalURL # auth_cluster_required = cephx # auth_service_required = cephx -## Apache SSL Settings + +## SSL Settings +# Adjust these settings to change how SSL connectivity is configured for +# various services. For more information, see the openstack-ansible +# documentation section titled "Securing services with SSL certificates". +# +## SSL: Keystone # These do not need to be configured unless you're creating certificates for # services running behind Apache (currently, Horizon and Keystone). ssl_protocol: "ALL -SSLv2 -SSLv3" @@ -113,7 +119,14 @@ ssl_cipher_suite: "ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AE # To override for Horizon only: # - horizon_ssl_protocol # - horizon_ssl_cipher_suite - +# +## SSL: RabbitMQ +# Set these variables if you prefer to use existing SSL certificates, keys and +# CA certificates with the RabbitMQ SSL/TLS Listener +# +#rabbitmq_user_ssl_cert: +#rabbitmq_user_ssl_key: +#rabbitmq_user_ssl_ca_cert: ## Additional pinning generator that will allow for more packages to be pinned as you see fit. ## All pins allow for package and versions to be defined. Be careful using this as versions diff --git a/playbooks/roles/rabbitmq_server/defaults/main.yml b/playbooks/roles/rabbitmq_server/defaults/main.yml index 70e997aeb1..d93b0953d7 100644 --- a/playbooks/roles/rabbitmq_server/defaults/main.yml +++ b/playbooks/roles/rabbitmq_server/defaults/main.yml @@ -51,3 +51,20 @@ rabbitmq_ulimit: 4096 rabbitmq_plugins: - names: rabbitmq_management state: enabled + +# RabbitMQ SSL support +rabbitmq_ssl_cert: /etc/ssl/certs/rabbitmq.pem +rabbitmq_ssl_key: /etc/ssl/private/rabbitmq.key +rabbitmq_ssl_ca_cert: /etc/ssl/certs/rabbitmq-ca.pem + +# Set rabbitmq_ssl_self_signed_regen to true if you want to generate a new +# SSL certificate for RabbitMQ when this playbook runs. You can also change +# the subject of the self-signed certificate here if you prefer. +rabbitmq_ssl_self_signed_regen: false +rabbitmq_ssl_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT/CN={{ container_name }}" + +# Define user-provided SSL certificates in: +# /etc/openstack_deploy/user_variables.yml +#rabbitmq_user_ssl_cert: +#rabbitmq_user_ssl_key: +#rabbitmq_user_ssl_ca_cert: diff --git a/playbooks/roles/rabbitmq_server/tasks/main.yml b/playbooks/roles/rabbitmq_server/tasks/main.yml index 5f5c4788d9..3f477bb565 100644 --- a/playbooks/roles/rabbitmq_server/tasks/main.yml +++ b/playbooks/roles/rabbitmq_server/tasks/main.yml @@ -20,6 +20,22 @@ - include: rabbitmq_install.yml when: not rabbitmq_ignore_version_state | bool +# RabbitMQ SSL/TLS listener configuration +# +# If the user has not specified a certificate, key and CA certificate, we will +# generate a self-signed SSL certificate and distribute it to each RabbitMQ +# container. +# +# User-provided certificates must be specified within: +# +# playbooks/roles/rabbitmq_server/defaults/main.yml +# +- include: rabbitmq_ssl_self_signed.yml + when: > + rabbitmq_user_ssl_cert is not defined or + rabbitmq_user_ssl_key is not defined +- include: rabbitmq_ssl_user_provided.yml + - include: rabbitmq_set_cookie.yml - include: rabbitmq_post_install.yml - include: rabbitmq_cluster.yml diff --git a/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_create.yml b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_create.yml new file mode 100644 index 0000000000..4fdc3099d1 --- /dev/null +++ b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_create.yml @@ -0,0 +1,37 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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: Remove self signed cert for regen + file: + dest: "{{ rabbitmq_ssl_cert }}" + state: "absent" + when: rabbitmq_ssl_self_signed_regen | bool + tags: + - rabbitmq-ssl + +# See playbooks/roles/rabbitmq_server/defaults/main.yml to provide custom +# subject material for certificates or specify a user-provided certificate and +# key pair. +- name: Create self-signed ssl cert + command: > + openssl req -new -nodes -sha256 -x509 -subj + "{{ rabbitmq_ssl_self_signed_subject }}" + -days 3650 + -keyout {{ rabbitmq_ssl_key }} + -out {{ rabbitmq_ssl_cert }} + -extensions v3_ca + creates={{ rabbitmq_ssl_cert }} + tags: + - rabbitmq-ssl diff --git a/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_distribute.yml b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_distribute.yml new file mode 100644 index 0000000000..70ba0d88d0 --- /dev/null +++ b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_distribute.yml @@ -0,0 +1,33 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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: Distribute self signed ssl + memcached: + name: "{{ item.name }}" + file_path: "{{ item.src }}" + state: "retrieve" + file_mode: "{{ item.file_mode }}" + dir_mode: "{{ item.dir_mode }}" + server: "{{ memcached_servers }}" + encrypt_string: "{{ memcached_encryption_key }}" + with_items: + - { src: "{{ rabbitmq_ssl_cert }}", name: "rabbitmq_ssl_cert", file_mode: "0640", dir_mode: "0750" } + - { src: "{{ rabbitmq_ssl_key }}", name: "rabbitmq_ssl_key", file_mode: "0640", dir_mode: "0750" } + register: memcache_keys + until: memcache_keys|success + retries: 5 + delay: 2 + tags: + - rabbitmq-ssl diff --git a/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_store.yml b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_store.yml new file mode 100644 index 0000000000..8dcf5f9fda --- /dev/null +++ b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_key_store.yml @@ -0,0 +1,31 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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: Store self signed ssl + memcached: + name: "{{ item.name }}" + file_path: "{{ item.src }}" + state: "present" + server: "{{ memcached_servers }}" + encrypt_string: "{{ memcached_encryption_key }}" + with_items: + - { src: "{{ rabbitmq_ssl_cert }}", name: "rabbitmq_ssl_cert" } + - { src: "{{ rabbitmq_ssl_key }}", name: "rabbitmq_ssl_key" } + register: memcache_keys + until: memcache_keys|success + retries: 5 + delay: 2 + tags: + - rabbitmq-ssl diff --git a/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_self_signed.yml b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_self_signed.yml new file mode 100644 index 0000000000..840b381d8f --- /dev/null +++ b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_self_signed.yml @@ -0,0 +1,31 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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. + +# We create the self-signed SSL certificate and key only on the first +# RabbitMQ container. +- include: rabbitmq_ssl_key_create.yml + when: > + inventory_hostname == groups['rabbitmq_all'][0] + +# The certificate and key are stored in memcached for easy distribution. +- include: rabbitmq_ssl_key_store.yml + when: > + inventory_hostname == groups['rabbitmq_all'][0] + +# The additional RabbitMQ nodes will retrieve their SSL certificates and keys +# from memcached. +- include: rabbitmq_ssl_key_distribute.yml + when: > + inventory_hostname != groups['rabbitmq_all'][0] diff --git a/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_user_provided.yml b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_user_provided.yml new file mode 100644 index 0000000000..09714abe91 --- /dev/null +++ b/playbooks/roles/rabbitmq_server/tasks/rabbitmq_ssl_user_provided.yml @@ -0,0 +1,46 @@ +--- +# Copyright 2015, Rackspace US, Inc. +# +# 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. + +# If we have a user-provided SSL certificate from +# /etc/openstack_deploy/user_variables.yml, we should deploy that certificate +# and key to each RabbitMQ container. +- name: Deploy user provided ssl cert and key + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "root" + group: "root" + mode: "{{ item.mode }}" + with_items: + - { src: "{{ rabbitmq_user_ssl_cert }}", dest: "{{ rabbitmq_ssl_cert }}", mode: "0644" } + - { src: "{{ rabbitmq_user_ssl_key }}", dest: "{{ rabbitmq_ssl_key }}", mode: "0640" } + when: rabbitmq_user_ssl_cert is defined and rabbitmq_user_ssl_key is defined + tags: + - rabbitmq-configs + - rabbitmq-ssl + +# Deploy the user provided CA certificate as well (if the user defined it +# within /etc/openstack_deploy/user_variables.yml). +- name: Deploy user provided ssl CA cert + copy: + src: "{{ rabbitmq_user_ssl_ca_cert }}" + dest: "{{ rabbitmq_ssl_ca_cert }}" + owner: "root" + group: "root" + mode: "0644" + when: rabbitmq_user_ssl_ca_cert is defined + tags: + - keystone-configs + - keystone-ssl diff --git a/playbooks/roles/rabbitmq_server/templates/rabbitmq.config.j2 b/playbooks/roles/rabbitmq_server/templates/rabbitmq.config.j2 index 834c5af81f..249142d7ee 100644 --- a/playbooks/roles/rabbitmq_server/templates/rabbitmq.config.j2 +++ b/playbooks/roles/rabbitmq_server/templates/rabbitmq.config.j2 @@ -1,6 +1,15 @@ [ {rabbit, [ {loopback_users, []}, + {ssl_listeners, [5671]}, + {ssl_options, [{certfile,"{{ rabbitmq_ssl_cert }}"}, + {keyfile,"{{ rabbitmq_ssl_key }}"}, + {% if rabbitmq_ssl_ca_cert is defined -%} + {cacertfile,"{{ rabbitmq_ssl_ca_cert }}"}, + {% endif -%} + {versions, ['tlsv1.2', 'tlsv1.1']}, + {verify,verify_none}, + {fail_if_no_peer_cert,false}]}, {% if rabbitmq_cluster_partition_handling != 'ignore' %}{cluster_partition_handling, {{ rabbitmq_cluster_partition_handling }}},{% endif %} {cluster_nodes, { [ {% for host in groups['rabbitmq_all'] %}'rabbit@{{ hostvars[host]['ansible_ssh_host'] }}'{% if not loop.last %}, {% endif %}{% endfor %}], disc}