RabbitMQ TLS support
PROD-13894
Change-Id: I93ead9105820fe7462b7bd9b76d51f89ce5950c6
Releases: Newton, Ocata
diff --git a/ironic/_common.sls b/ironic/_common.sls
index e549ac4..61c587f 100644
--- a/ironic/_common.sls
+++ b/ironic/_common.sls
@@ -1,4 +1,4 @@
-{%- from "ironic/map.jinja" import api,conductor with context %}
+{%- from "ironic/map.jinja" import api,conductor, system_cacerts_file with context %}
{%- if api.get("enabled", False) %}
{%- set ironic = api %}
{%- elif conductor.get('enabled', False) %}
@@ -16,3 +16,17 @@
- template: jinja
- require:
- pkg: ironic_common_pkgs
+
+{%- if ironic.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbitmq_ca:
+{%- if ironic.message_queue.ssl.cacert is defined %}
+ file.managed:
+ - name: {{ ironic.message_queue.ssl.cacert_file }}
+ - contents_pillar: ironic:{{ 'api' if api.get("enabled", False) else 'conductor' }}:message_queue:ssl:cacert
+ - mode: 0444
+ - makedirs: true
+{%- else %}
+ file.exists:
+ - name: {{ ironic.message_queue.ssl.get('cacert_file', system_cacerts_file) }}
+{%- endif %}
+{%- endif %}
diff --git a/ironic/api.sls b/ironic/api.sls
index 75a2f25..cae9009 100644
--- a/ironic/api.sls
+++ b/ironic/api.sls
@@ -22,6 +22,9 @@
- watch:
- file: /etc/ironic/ironic.conf
- file: /etc/ironic/policy.json
+ {%- if api.message_queue.get('ssl',{}).get('enabled', False) %}
+ - file: rabbitmq_ca
+ {%- endif %}
/etc/ironic/policy.json:
file.managed:
diff --git a/ironic/conductor.sls b/ironic/conductor.sls
index b8baa13..9fb0df9 100644
--- a/ironic/conductor.sls
+++ b/ironic/conductor.sls
@@ -14,6 +14,9 @@
- full_restart: true
- watch:
- file: /etc/ironic/ironic.conf
+ {%- if conductor.message_queue.get('ssl',{}).get('enabled', False) %}
+ - file: rabbitmq_ca
+ {%- endif %}
ironic_dirs:
file.directory:
diff --git a/ironic/files/newton/ironic.conf b/ironic/files/newton/ironic.conf
index bd0281e..d558b9e 100644
--- a/ironic/files/newton/ironic.conf
+++ b/ironic/files/newton/ironic.conf
@@ -1,4 +1,4 @@
-{%- from "ironic/map.jinja" import api,conductor with context -%}
+{%- from "ironic/map.jinja" import api,conductor,system_cacerts_file with context -%}
{%- if api.get("enabled", False) %}
{%- set ironic = api %}
{%- elif conductor.get('enabled', False) %}
@@ -472,15 +472,15 @@
# A URL representing the messaging driver to use and its full
# configuration. (string value)
-{%- set mq = ironic.message_queue %}
-{%- set rmq_port = mq.get('port', 5672) %}
-{%- if mq.members is defined %}
-transport_url = rabbit://{% for member in mq.members -%}
- {{ mq.user }}:{{ mq.password }}@{{ member.host }}:{{ member.get('port', rmq_port) }}
- {%- if not loop.last -%},{%- endif -%}
- {%- endfor -%}/{{ mq.virtual_host }}
+{%- set rabbit_port = ironic.message_queue.get('port', 5671 if ironic.message_queue.get('ssl',{}).get('enabled', False) else 5672) %}
+{%- if ironic.message_queue.members is defined %}
+transport_url = rabbit://{% for member in ironic.message_queue.members -%}
+ {{ ironic.message_queue.user }}:{{ ironic.message_queue.password }}@{{ member.host }}:{{ member.get('port', rabbit_port) }}
+ {%- if not loop.last -%},{%- endif -%}
+ {%- endfor -%}
+ /{{ ironic.message_queue.virtual_host }}
{%- else %}
-transport_url = rabbit://{{ mq.user }}:{{ mq.password }}@{{ mq.host }}:{{ rmq_port }}/{{ mq.virtual_host }}
+transport_url = rabbit://{{ ironic.message_queue.user }}:{{ ironic.message_queue.password }}@{{ ironic.message_queue.host }}:{{ rabbit_port }}/{{ ironic.message_queue.virtual_host }}
{%- endif %}
# The default exchange under which topics are scoped. May be
@@ -2733,6 +2733,20 @@
# From oslo.messaging
#
+{%- if ironic.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbit_use_ssl=true
+{%- if ironic.message_queue.ssl.version is defined %}
+kombu_ssl_version = {{ ironic.message_queue.ssl.version }}
+{%- elif salt['grains.get']('pythonversion') > [2,7,8] %}
+kombu_ssl_version = TLSv1_2
+{%- endif %}
+{%- if ironic.message_queue.ssl.cacert_file is defined %}
+kombu_ssl_ca_certs = {{ ironic.message_queue.ssl.cacert_file }}
+{%- else %}
+kombu_ssl_ca_certs={{ system_cacerts_file }}
+{%- 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/ironic/files/ocata/ironic.conf b/ironic/files/ocata/ironic.conf
index ef0db7a..0289f13 100644
--- a/ironic/files/ocata/ironic.conf
+++ b/ironic/files/ocata/ironic.conf
@@ -1,4 +1,4 @@
-{%- from "ironic/map.jinja" import api,conductor with context -%}
+{%- from "ironic/map.jinja" import api,conductor,system_cacerts_file with context -%}
{%- if api.get("enabled", False) %}
{%- set ironic = api %}
{%- elif conductor.get('enabled', False) %}
@@ -770,15 +770,15 @@
# A URL representing the messaging driver to use and its full
# configuration. (string value)
-{%- set mq = ironic.message_queue %}
-{%- set rmq_port = mq.get('port', 5672) %}
-{%- if mq.members is defined %}
-transport_url = rabbit://{% for member in mq.members -%}
- {{ mq.user }}:{{ mq.password }}@{{ member.host }}:{{ member.get('port', rmq_port) }}
- {%- if not loop.last -%},{%- endif -%}
- {%- endfor -%}/{{ mq.virtual_host }}
+{%- set rabbit_port = ironic.message_queue.get('port', 5671 if ironic.message_queue.get('ssl',{}).get('enabled', False) else 5672) %}
+{%- if ironic.message_queue.members is defined %}
+transport_url = rabbit://{% for member in ironic.message_queue.members -%}
+ {{ ironic.message_queue.user }}:{{ ironic.message_queue.password }}@{{ member.host }}:{{ member.get('port', rabbit_port) }}
+ {%- if not loop.last -%},{%- endif -%}
+ {%- endfor -%}
+ /{{ ironic.message_queue.virtual_host }}
{%- else %}
-transport_url = rabbit://{{ mq.user }}:{{ mq.password }}@{{ mq.host }}:{{ rmq_port }}/{{ mq.virtual_host }}
+transport_url = rabbit://{{ ironic.message_queue.user }}:{{ ironic.message_queue.password }}@{{ ironic.message_queue.host }}:{{ rabbit_port }}/{{ ironic.message_queue.virtual_host }}
{%- endif %}
# The default exchange under which topics are scoped. May be
@@ -3065,6 +3065,20 @@
# From oslo.messaging
#
+{%- if ironic.message_queue.get('ssl',{}).get('enabled', False) %}
+rabbit_use_ssl=true
+{%- if ironic.message_queue.ssl.version is defined %}
+kombu_ssl_version = {{ ironic.message_queue.ssl.version }}
+{%- elif salt['grains.get']('pythonversion') > [2,7,8] %}
+kombu_ssl_version = TLSv1_2
+{%- endif %}
+{%- if ironic.message_queue.ssl.cacert_file is defined %}
+kombu_ssl_ca_certs = {{ ironic.message_queue.ssl.cacert_file }}
+{%- else %}
+kombu_ssl_ca_certs={{ system_cacerts_file }}
+{%- 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/ironic/map.jinja b/ironic/map.jinja
index 3a2ad32..09127b7 100644
--- a/ironic/map.jinja
+++ b/ironic/map.jinja
@@ -1,3 +1,8 @@
+{%- set system_cacerts_file = salt['grains.filter_by']({
+ 'Debian': '/etc/ssl/certs/ca-certificates.crt',
+ 'RedHat': '/etc/pki/tls/certs/ca-bundle.crt'
+})%}
+
{% set api = salt['grains.filter_by']({
'Common': {
'pkgs': ['ironic-api'],
diff --git a/tests/pillar/ssl.sls b/tests/pillar/ssl.sls
new file mode 100644
index 0000000..9855e0a
--- /dev/null
+++ b/tests/pillar/ssl.sls
@@ -0,0 +1,19 @@
+# Description:
+# test of SSL enabling for the following communication paths:
+# - messaging (rabbitmq)
+
+include:
+ - .api_single
+ - .conductor_single
+
+ironic:
+ api:
+ message_queue:
+ port: 5671
+ ssl:
+ enabled: True
+ conductor:
+ message_queue:
+ port: 5671
+ ssl:
+ enabled: True