From fffeb4bb6639ae231b899f439128565b2ad887b7 Mon Sep 17 00:00:00 2001 From: Andrey Date: Thu, 26 Jan 2017 18:37:11 -0600 Subject: [PATCH] Added Galera SSL support MySQL SSL connections allowed. Self-signed SSL bundle created and placed to the deployment host, or user-provided SSL bundle (CA, cert and the key) is used. Change-Id: Ibac61d45cea67123fe61a6de4f906b4bd1949a34 Partial-Bug: #1667789 (cherry picked from commit eb5fc9c1e852866bc5e332a697bfeb86dfc44047) --- defaults/main.yml | 20 ++++++ .../notes/implement-ssl-dd42ad2ff91af0bd.yaml | 6 ++ tasks/galera_post_install.yml | 7 ++ tasks/galera_ssl.yml | 54 +++++++++++++++ tasks/galera_ssl_key_create.yml | 65 +++++++++++++++++++ templates/my.cnf.j2 | 5 ++ tox.ini | 9 +++ 7 files changed, 166 insertions(+) create mode 100644 releasenotes/notes/implement-ssl-dd42ad2ff91af0bd.yaml create mode 100644 tasks/galera_ssl.yml create mode 100644 tasks/galera_ssl_key_create.yml diff --git a/defaults/main.yml b/defaults/main.yml index a6c14fbd..d130b9cf 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -117,3 +117,23 @@ qpress_package_download_validate_certs: yes qpress_package_url: "{{ qpress_arch_url.get( galera_package_arch | lower ) }}" qpress_package_sha256: "{{ qpress_arch_sha256.get( galera_package_arch | lower ) }}" qpress_package_path: "/opt/{{ qpress_package_url | basename }}" + +# Galera Server SSL functionality. + +galera_use_ssl: false +galera_ssl_cert: /etc/mysql/ssl/galera.pem +galera_ssl_key: /etc/mysql/ssl/galera.key +galera_ssl_ca_cert: /etc/mysql/ssl/galera-ca.pem +# These options should be specified in user_variables if necessary, otherwise self-signed certs are used. +galera_user_ssl_cert: /etc/openstack_deploy/self_signed_certs/galera.pem +galera_user_ssl_key: /etc/openstack_deploy/self_signed_certs/galera.key +galera_user_ssl_ca_cert: /etc/openstack_deploy/self_signed_certs/galera-ca.pem +# Set galera_ssl_self_signed_regen to true if you want to generate a new +# SSL certificate for Galera when this playbook runs. You can also change +# the subject of the self-signed certificate here if you prefer. +galera_ssl_self_signed_regen: false +galera_ssl_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT/CN={{ galera_ssl_address }}" +galera_ssl_ca_self_signed_subject: "/C=US/ST=Texas/L=San Antonio/O=IT" +# This option is used for creating the CA and overriding the Galera address on the clients side. +# Should be set to either public VIP of VIP FQDN, depending on what is currently used in the env. +galera_ssl_address: "{{ ansible_host }}" diff --git a/releasenotes/notes/implement-ssl-dd42ad2ff91af0bd.yaml b/releasenotes/notes/implement-ssl-dd42ad2ff91af0bd.yaml new file mode 100644 index 00000000..96017400 --- /dev/null +++ b/releasenotes/notes/implement-ssl-dd42ad2ff91af0bd.yaml @@ -0,0 +1,6 @@ +--- +features: + - Implements SSL connection ability to MySQL. ``galera_use_ssl`` option has to + be set to ``true`` (default), in this case playbooks create self-signed + SSL bundle and sets up MySQL configs to use it or distributes user-provided + bundle throughout Galera nodes. diff --git a/tasks/galera_post_install.yml b/tasks/galera_post_install.yml index cb60bac9..68d2722f 100644 --- a/tasks/galera_post_install.yml +++ b/tasks/galera_post_install.yml @@ -29,6 +29,13 @@ tags: - galera-config +- include: galera_ssl.yml + when: + - galera_use_ssl | bool + tags: + - galera-config + - galera-ssl + - name: Drop mariadb config(s) config_template: src: "{{ item.src }}" diff --git a/tasks/galera_ssl.yml b/tasks/galera_ssl.yml new file mode 100644 index 00000000..d16096ed --- /dev/null +++ b/tasks/galera_ssl.yml @@ -0,0 +1,54 @@ +--- +# Copyright 2015, Rackspace US, Inc., Mirantis 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: Check if SSL bundle exists + stat: + path: "{{ item }}" + delegate_to: localhost + register: res + with_items: + - "{{ galera_user_ssl_ca_cert }}" + - "{{ galera_user_ssl_cert }}" + - "{{ galera_user_ssl_key }}" + +- include: galera_ssl_key_create.yml + when: > + ( not res.results[0].stat.exists or + not res.results[1].stat.exists or + not res.results[2].stat.exists ) + +- name: Create ssl directory + file: + path: "/etc/mysql/ssl" + state: "directory" + owner: "mysql" + group: "mysql" + mode: "0750" + +- name: Copy CA cert and key + copy: + src: "{{ item.src }}" + dest: "{{ item.dest }}" + owner: "mysql" + group: "mysql" + mode: "{{ item.mode|default('0640') }}" + with_items: + - src: "{{ galera_user_ssl_ca_cert }}" + dest: "{{ galera_ssl_ca_cert }}" + - src: "{{ galera_user_ssl_cert }}" + dest: "{{ galera_ssl_cert }}" + - src: "{{ galera_user_ssl_key }}" + dest: "{{ galera_ssl_key }}" + mode: "0600" diff --git a/tasks/galera_ssl_key_create.yml b/tasks/galera_ssl_key_create.yml new file mode 100644 index 00000000..5372cf39 --- /dev/null +++ b/tasks/galera_ssl_key_create.yml @@ -0,0 +1,65 @@ +--- +# Copyright 2015, Rackspace US, Inc., Mirantis 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: Create ssl directory + file: + path: "{{ galera_user_ssl_ca_cert | dirname }}" + state: "directory" + delegate_to: localhost + +- name: Remove self signed cert for regen + file: + dest: "{{ item }}" + state: "absent" + with_items: + - "{{ galera_user_ssl_ca_cert }}" + - "{{ galera_user_ssl_cert }}" + - "{{ galera_user_ssl_key }}" + - "{{ galera_user_ssl_ca_cert | dirname }}/galera-ca.key " + - "{{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem " + delegate_to: localhost + when: galera_ssl_self_signed_regen | bool + +- name: Create galera CA cert + command: > + openssl req -new -nodes -x509 -subj + "{{ galera_ssl_ca_self_signed_subject }}" + -keyout {{ galera_user_ssl_ca_cert | dirname }}/galera-ca.key + -out {{ galera_user_ssl_ca_cert }} + creates={{ galera_user_ssl_ca_cert }} + delegate_to: localhost + +- name: Create galera ssl request + command: > + openssl req -new -nodes -sha256 -subj + "{{ galera_ssl_self_signed_subject }}" + -days 3650 + -keyout {{ galera_user_ssl_key }} + -out {{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem + -extensions v3_ca + creates={{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem + delegate_to: localhost + +- name: Create galera ssl cert + command: > + openssl x509 -req + -days 3650 + -in {{ galera_user_ssl_ca_cert | dirname }}/galera-req.pem + -CA {{ galera_user_ssl_ca_cert }} + -CAkey {{ galera_user_ssl_ca_cert | dirname }}/galera-ca.key + -out {{ galera_user_ssl_cert }} + -set_serial 01 + creates={{ galera_user_ssl_cert }} + delegate_to: localhost diff --git a/templates/my.cnf.j2 b/templates/my.cnf.j2 index ed089ed0..3677fa75 100644 --- a/templates/my.cnf.j2 +++ b/templates/my.cnf.j2 @@ -33,6 +33,11 @@ bind-address = :: {% if galera_server_id is defined %} server-id = {{ galera_server_id }} {% endif %} +{% if galera_use_ssl | bool %} +ssl-ca = {{ galera_ssl_ca_cert }} +ssl-cert = {{ galera_ssl_cert }} +ssl-key = {{ galera_ssl_key }} +{% endif %} # LOGGING # log-queries-not-using-indexes = {{ galera_unindexed_query_logging }} diff --git a/tox.ini b/tox.ini index 0e8bcaef..6b618254 100644 --- a/tox.ini +++ b/tox.ini @@ -109,6 +109,15 @@ commands = {[testenv:tests_clone]commands} bash -c "{toxinidir}/tests/common/test-ansible-functional.sh" +[testenv:ssl] +deps = + {[testenv:ansible]deps} +setenv = + {[testenv]setenv} + ANSIBLE_PARAMETERS=-vvv -e galera_use_ssl=True -e galera_user_ssl_ca_cert="/tmp/self-signed-certs/galera-ca.crt" -e galera_user_ssl_cert="/tmp/self-signed-certs/galera.crt" -e galera_user_ssl_key="/tmp/self-signed-certs/galera.key" +commands = + {[testenv:tests_clone]commands} + bash -c "{toxinidir}/tests/common/test-ansible-functional.sh" [testenv:linters] deps =