RabbitMQ TLS support
Usage: see README.rst
Releases: Mitaka, Newton, Ocata
OSCORE-383
Change-Id: I5e51d5be3c07415e312d90bb0df89bf9639fcba6
diff --git a/README.rst b/README.rst
index 14403eb..bb7146f 100644
--- a/README.rst
+++ b/README.rst
@@ -305,6 +305,56 @@
virtual_host: '/openstack'
....
+Client-side RabbitMQ TLS configuration:
+
+|
+
+By default system-wide CA certs are used. Nothing should be specified except `ssl.enabled`.
+
+.. code-block:: yaml
+
+ keystone:
+ server:
+ ....
+ message_queue:
+ ssl:
+ enabled: True
+
+Use `cacert_file` option to specify the CA-cert file path explicitly:
+
+.. code-block:: yaml
+
+ keystone:
+ server:
+ ....
+ message_queue:
+ ssl:
+ enabled: True
+ cacert_file: /etc/ssl/rabbitmq-ca.pem
+
+To manage content of the `cacert_file` use the `cacert` option:
+
+.. code-block:: yaml
+
+ keystone:
+ server:
+ ....
+ message_queue:
+ ssl:
+ enabled: True
+ cacert: |
+
+ -----BEGIN CERTIFICATE-----
+ ...
+ -----END CERTIFICATE-------
+
+ cacert_file: /etc/openstack/rabbitmq-ca.pem
+
+
+Notice:
+ * The `message_queue.port` is set to **5671** (AMQPS) by default if `ssl.enabled=True`.
+ * Use `message_queue.ssl.version` if you need to specify protocol version. By default is TLSv1 for python < 2.7.9 and TLSv1_2 for version above.
+
Enable CADF audit notification
.. code-block:: yaml
diff --git a/keystone/files/mitaka/keystone.conf.Debian b/keystone/files/mitaka/keystone.conf.Debian
index e319050..18d6f2b 100644
--- a/keystone/files/mitaka/keystone.conf.Debian
+++ b/keystone/files/mitaka/keystone.conf.Debian
@@ -1577,14 +1577,31 @@
# Allowed values: round-robin, shuffle
#kombu_failover_strategy = round-robin
+{%- set rabbit_port = server.message_queue.get('port', 5671 if server.message_queue.get('ssl',{}).get('enabled', False) else 5672) %}
{%- if server.message_queue.members is defined %}
rabbit_hosts = {% for member in server.message_queue.members -%}
- {{ member.host }}:{{ member.get('port', 5672) }}
+ {{ member.host }}:{{ member.get('port', rabbit_port) }}
{%- if not loop.last -%},{%- endif -%}
{%- endfor -%}
{%- else %}
rabbit_host = {{ server.message_queue.host }}
-rabbit_port = {{ server.message_queue.port }}
+rabbit_port = {{ rabbit_port }}
+{%- endif %}
+
+{%- if server.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbit_use_ssl=true
+
+{%- if server.message_queue.ssl.version is defined %}
+kombu_ssl_version = {{ server.message_queue.ssl.version }}
+{%- elif salt['grains.get']('pythonversion') > [2,7,8] %}
+kombu_ssl_version = TLSv1_2
+{%- endif %}
+
+{%- if server.message_queue.ssl.cacert_file is defined %}
+kombu_ssl_ca_certs = {{ server.message_queue.ssl.cacert_file }}
+{%- else %}
+kombu_ssl_ca_certs={{ system_cacerts_file }}
+{%- endif %}
{%- endif %}
# RabbitMQ HA cluster host:port pairs. (list value)
diff --git a/keystone/files/newton/keystone.conf.Debian b/keystone/files/newton/keystone.conf.Debian
index 95858ed..83f4b13 100644
--- a/keystone/files/newton/keystone.conf.Debian
+++ b/keystone/files/newton/keystone.conf.Debian
@@ -358,14 +358,16 @@
# A URL representing the messaging driver to use and its full configuration.
# (string value)
#transport_url = rabbit://nova:3qVSI7a1m8AdaDQ7BpB0PJu4@192.168.0.4:5673/
+
+{%- set rabbit_port = server.message_queue.get('port', 5671 if server.message_queue.get('ssl',{}).get('enabled', False) else 5672) %}
{%- if server.message_queue.members is defined %}
transport_url = rabbit://{% for member in server.message_queue.members -%}
- {{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ member.host }}:{{ member.get('port', 5672) }}
+ {{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ member.host }}:{{ member.get('port', rabbit_port) }}
{%- if not loop.last -%},{%- endif -%}
{%- endfor -%}
/{{ server.message_queue.virtual_host }}
{%- else %}
-transport_url = rabbit://{{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ server.message_queue.host }}:{{ server.message_queue.port }}/{{ server.message_queue.virtual_host }}
+transport_url = rabbit://{{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ server.message_queue.host }}:{{ rabbit_port }}/{{ server.message_queue.virtual_host }}
{%- endif %}
# DEPRECATED: The messaging driver to use, defaults to rabbit. Other drivers
@@ -374,7 +376,6 @@
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rpc_backend = rabbit
-rpc_backend = rabbit
{%- endif %}
# The default exchange under which topics are scoped. May be overridden by an
@@ -1865,6 +1866,26 @@
# From oslo.messaging
#
+{%- if server.notification %}
+
+{%- if server.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbit_use_ssl=true
+
+{%- if server.message_queue.ssl.version is defined %}
+kombu_ssl_version = {{ server.message_queue.ssl.version }}
+{%- elif salt['grains.get']('pythonversion') > [2,7,8] %}
+kombu_ssl_version = TLSv1_2
+{%- endif %}
+
+{%- if server.message_queue.ssl.cacert_file is defined %}
+kombu_ssl_ca_certs = {{ server.message_queue.ssl.cacert_file }}
+{%- else %}
+kombu_ssl_ca_certs={{ system_cacerts_file }}
+{%- endif %}
+{%- endif %}
+
+{%- endif %}
+
# Use durable queues in AMQP. (boolean value)
# Deprecated group/name - [DEFAULT]/amqp_durable_queues
# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
diff --git a/keystone/files/ocata/keystone.conf.Debian b/keystone/files/ocata/keystone.conf.Debian
index fc04d71..59b1cff 100644
--- a/keystone/files/ocata/keystone.conf.Debian
+++ b/keystone/files/ocata/keystone.conf.Debian
@@ -425,14 +425,15 @@
# A URL representing the messaging driver to use and its full configuration.
# (string value)
#transport_url = rabbit://nova:3qVSI7a1m8AdaDQ7BpB0PJu4@192.168.0.4:5673/
+{%- set rabbit_port = server.message_queue.get('port', 5671 if server.message_queue.get('ssl',{}).get('enabled', False) else 5672) %}
{%- if server.message_queue.members is defined %}
transport_url = rabbit://{% for member in server.message_queue.members -%}
- {{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ member.host }}:{{ member.get('port', 5672) }}
+ {{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ member.host }}:{{ member.get('port', rabbit_port) }}
{%- if not loop.last -%},{%- endif -%}
{%- endfor -%}
/{{ server.message_queue.virtual_host }}
{%- else %}
-transport_url = rabbit://{{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ server.message_queue.host }}:{{ server.message_queue.port }}/{{ server.message_queue.virtual_host }}
+transport_url = rabbit://{{ server.message_queue.user }}:{{ server.message_queue.password }}@{{ server.message_queue.host }}:{{ rabbit_port }}/{{ server.message_queue.virtual_host }}
{%- endif %}
# DEPRECATED: The messaging driver to use, defaults to rabbit. Other drivers
@@ -441,7 +442,6 @@
# Its value may be silently ignored in the future.
# Reason: Replaced by [DEFAULT]/transport_url
#rpc_backend = rabbit
-rpc_backend = rabbit
{%- endif %}
# The default exchange under which topics are scoped. May be overridden by an
# exchange name specified in the transport_url option. (string value)
@@ -1962,6 +1962,27 @@
# From oslo.messaging
#
+
+{%- if server.notification %}
+
+{%- if server.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbit_use_ssl=true
+
+{%- if server.message_queue.ssl.version is defined %}
+kombu_ssl_version = {{ server.message_queue.ssl.version }}
+{%- elif salt['grains.get']('pythonversion') > [2,7,8] %}
+kombu_ssl_version = TLSv1_2
+{%- endif %}
+
+{%- if server.message_queue.ssl.cacert_file is defined %}
+kombu_ssl_ca_certs = {{ server.message_queue.ssl.cacert_file }}
+{%- else %}
+kombu_ssl_ca_certs={{ system_cacerts_file }}
+{%- endif %}
+{%- endif %}
+
+{%- endif %}
+
# Use durable queues in AMQP. (boolean value)
# Deprecated group/name - [DEFAULT]/amqp_durable_queues
# Deprecated group/name - [DEFAULT]/rabbit_durable_queues
diff --git a/keystone/server.sls b/keystone/server.sls
index 2479590..fc29a27 100644
--- a/keystone/server.sls
+++ b/keystone/server.sls
@@ -227,6 +227,9 @@
- onlyif: /bin/false
{%- endif %}
- watch:
+ {%- if server.notification and server.message_queue.get('ssl',{}).get('enabled', False) %}
+ - file: rabbitmq_ca
+ {%- endif %}
- file: /etc/keystone/keystone.conf
{%- endif %}
@@ -445,6 +448,21 @@
- name: {{ server.database.ssl.get('cacert_file', system_cacerts_file) }}
- require_in:
- file: /etc/keystone/keystone.conf
+{% endif %}
+{% endif %}
+
+
+{%- if server.notification and server.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbitmq_ca:
+{%- if server.message_queue.ssl.cacert is defined %}
+ file.managed:
+ - name: {{ server.message_queue.ssl.cacert_file }}
+ - contents_pillar: keystone:server:message_queue:ssl:cacert
+ - mode: 0444
+ - makedirs: true
+{%- else %}
+ file.exists:
+ - name: {{ server.message_queue.ssl.get('cacert_file', system_cacerts_file) }}
{%- endif %}
{%- endif %}
diff --git a/tests/pillar/ssl.sls b/tests/pillar/ssl.sls
new file mode 100644
index 0000000..f60e5ed
--- /dev/null
+++ b/tests/pillar/ssl.sls
@@ -0,0 +1,53 @@
+# Test case with enabled SSL of the following communication paths:
+# - messaging (rabbitmq)
+
+keystone:
+ server:
+ enabled: true
+ version: liberty
+ service_token: token
+ service_tenant: service
+ admin_tenant: admin
+ admin_name: admin
+ admin_password: passw0rd
+ admin_email: root@localhost
+ bind:
+ address: 0.0.0.0
+ private_address: 127.0.0.1
+ private_port: 35357
+ public_address: 127.0.0.1
+ public_port: 5000
+ region: RegionOne
+ database:
+ engine: mysql
+ host: 127.0.0.1
+ name: keystone
+ password: passw0rd
+ user: keystone
+ ssl:
+ enabled: True
+ tokens:
+ engine: cache
+ expiration: 86400
+ location: /etc/keystone/fernet-keys/
+ notification: true
+ notification_format: cadf
+ message_queue:
+ engine: rabbitmq
+ host: 127.0.0.1
+ port: 5671
+ user: openstack
+ password: passw0rd
+ virtual_host: '/openstack'
+ ha_queues: true
+ ssl:
+ enabled: True
+ cache:
+ engine: memcached
+ members:
+ - host: 127.0.0.1
+ port: 11211
+ - host: 127.0.0.1
+ port: 11211
+ - host: 127.0.0.1
+ port: 11211