From 6bc6929d09a31e91ef962519bf5284620747e441 Mon Sep 17 00:00:00 2001 From: Dmitriy Rabotyagov Date: Tue, 7 Sep 2021 15:55:20 +0300 Subject: [PATCH] Use ansible-role-pki to generate SSL certificates Supports two scenarios: 1) variables defined in defaults/main.yml are sufficient to create a root/intermediate CA certificate for mariadb when this role is used outside openstack-ansible. 2) when: openstack_pki_dir openstack_pki_setup_host openstack_pki_authorities openstack_pki_service_intermediate_cert_name are defined, an external CA already created on the deploy host with a previous run of ansible-role-pki will be used as the CA. Server certificates for the galera instances are created from the data in galera_pki_certificates in both situations Depends-On: https://review.opendev.org/c/openstack/ansible-role-pki/+/807771 Change-Id: I72738e4f8bd2233dedbed4428baafd4436de84b5 --- defaults/main.yml | 87 +++++++++-- handlers/main.yml | 4 +- .../notes/galera_pki-2d6d77a86e8475cd.yaml | 34 +++++ tasks/galera_client_main.yml | 11 +- tasks/galera_client_ssl.yml | 53 ------- tasks/galera_server_post_install.yml | 16 +- tasks/galera_server_ssl.yml | 50 ------- tasks/galera_server_ssl_self_signed.yml | 139 ------------------ templates/client.my.cnf.j2 | 6 + 9 files changed, 143 insertions(+), 257 deletions(-) create mode 100644 releasenotes/notes/galera_pki-2d6d77a86e8475cd.yaml delete mode 100644 tasks/galera_client_ssl.yml delete mode 100644 tasks/galera_server_ssl.yml delete mode 100644 tasks/galera_server_ssl_self_signed.yml diff --git a/defaults/main.yml b/defaults/main.yml index 0ea34744..64c484b2 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -164,7 +164,62 @@ galera_distro_package_pins: # Galera Server SSL functionality. +# Storage location for SSL certificate authority +galera_pki_dir: "{{ openstack_pki_dir | default('/etc/pki/galera-ca') }}" + +# Create a certificate authority if one does not already exist +galera_pki_create_ca: "{{ openstack_pki_authorities is not defined | bool }}" +galera_pki_regen_ca: '' + +galera_pki_authorities: + - name: "MariaDBRoot" + country: "GB" + state_or_province_name: "England" + organization_name: "Example Corporation" + organizational_unit_name: "IT Security" + cn: "MariaDB Root CA" + provider: selfsigned + basic_constraints: "CA:TRUE" + key_usage: + - digitalSignature + - cRLSign + - keyCertSign + not_after: "+3650d" + - name: "MariaDBIntermediate" + country: "GB" + state_or_province_name: "England" + organization_name: "Example Corporation" + organizational_unit_name: "IT Security" + cn: "MariaDB Intermediate CA" + provider: ownca + basic_constraints: "CA:TRUE,pathlen:0" + key_usage: + - digitalSignature + - cRLSign + - keyCertSign + not_after: "+3650d" + signed_by: "MariaDBRoot" + +# Installation details for certificate authorities +galera_pki_install_ca: + - name: "MariaDBRoot" + condition: "{{ galera_pki_create_ca }}" + +# Galera server certificate +galera_pki_keys_path: "{{ galera_pki_dir ~ '/certs/private/' }}" +galera_pki_certs_path: "{{ galera_pki_dir ~ '/certs/certs/' }}" +galera_pki_intermediate_cert_name: "{{ openstack_pki_service_intermediate_cert_name | default('MariaDBIntermediate') }}" +galera_pki_intermediate_cert_path: "{{ galera_pki_dir ~ '/roots/' ~ galera_pki_intermediate_cert_name ~ '/certs/' ~ galera_pki_intermediate_cert_name ~ '.crt' }}" +galera_pki_regen_cert: '' +galera_pki_certificates: + - name: "galera_{{ ansible_facts['hostname'] }}" + provider: ownca + cn: "{{ ansible_facts['hostname'] }}" + san: "{{ 'DNS:' ~ ansible_facts['hostname'] ~ ',IP:' ~ galera_address }}" + signed_by: "{{ galera_pki_intermediate_cert_name }}" + galera_use_ssl: false +galera_ssl_verify: true galera_ssl_cert: /etc/ssl/certs/galera.pem galera_ssl_key: /etc/mysql/ssl/galera.key galera_ssl_ca_cert: /etc/ssl/certs/galera-ca.pem @@ -174,17 +229,29 @@ galera_ssl_ca_cert: /etc/ssl/certs/galera-ca.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_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_address: "{{ ansible_host }}" +# Installation details for SSL certificates +galera_pki_install_certificates: + - src: "{{ galera_user_ssl_cert | default(galera_pki_certs_path ~ 'galera_' ~ ansible_facts['hostname'] ~ '-chain.crt') }}" + dest: "{{ galera_ssl_cert }}" + owner: "root" + group: "root" + mode: "0644" + - src: "{{ galera_user_ssl_key | default(galera_pki_keys_path ~ 'galera_' ~ ansible_facts['hostname'] ~ '.key.pem') }}" + dest: "{{ galera_ssl_key }}" + owner: "mysql" + group: "root" + mode: "0600" + - src: "{{ galera_user_ssl_ca_cert | default(galera_pki_intermediate_cert_path) }}" + dest: "{{ galera_ssl_ca_cert }}" + owner: "root" + group: "root" + mode: "0644" + + # MariaDB 10.1+ ships with 'PrivateDevices=True' in the systemd unit file. This # provides some additional security, but it causes problems with systemd 219. # While the security enhancements are helpful on bare metal hosts with multiple @@ -206,10 +273,8 @@ galera_client_package_state: "latest" galera_client_drop_config_file: "true" galera_client_my_cnf_overrides: {} -# This server is used when pulling an ssl cert onto a given host when a user -# defined key is not present. By default this will try and pull from the -# "galera_server" group and fall back to localhost. -galera_ssl_server: "{{ (galera_cluster_members | default(['localhost']))[0] }}" +# Delegated host for operating the certificate authority +galera_ssl_server: "{{ openstack_pki_setup_host | default('localhost') }}" ## Database info galera_db_setup_host: "{{ openstack_db_setup_host | default(galera_cluster_members[0] | default('localhost')) }}" diff --git a/handlers/main.yml b/handlers/main.yml index 1deb13df..bb071ac1 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -25,7 +25,9 @@ failed_when: false changed_when: true register: node_status - listen: Restart all mysql + listen: + - Restart all mysql + - cert installed notify: - Bootstrap cluster - Restart mysql (All) diff --git a/releasenotes/notes/galera_pki-2d6d77a86e8475cd.yaml b/releasenotes/notes/galera_pki-2d6d77a86e8475cd.yaml new file mode 100644 index 00000000..334c46d8 --- /dev/null +++ b/releasenotes/notes/galera_pki-2d6d77a86e8475cd.yaml @@ -0,0 +1,34 @@ +--- +features: + - | + Galera role now leverages PKI role for creation and distribution of the + certificates and certificate authorities. + This introduces bunch of new variables which controls CA and certificates + generation details. + If user SSL certificates are provided - they would be used instead of + the generated ones. + + The following new variables were introduced: + + - galera_ssl_verify + - galera_pki_dir + - galera_pki_create_ca + - galera_pki_regen_ca + - galera_pki_certificates + - galera_pki_regen_cert + - galera_pki_authorities + - galera_pki_install_ca + - galera_pki_keys_path + - galera_pki_certs_path + - galera_pki_intermediate_cert_name + - galera_pki_intermediate_cert_path + - galera_pki_install_certificates + +deprecations: + - | + Following variables were removed in favor of PKI ones + and have no effect anymore: + + - galera_ssl_self_signed_regen + - galera_ssl_self_signed_subject + - galera_ssl_ca_self_signed_subject diff --git a/tasks/galera_client_main.yml b/tasks/galera_client_main.yml index 97778823..b49afad0 100644 --- a/tasks/galera_client_main.yml +++ b/tasks/galera_client_main.yml @@ -23,6 +23,13 @@ - include_tasks: galera_client_post_install.yml -- include_tasks: galera_client_ssl.yml - when: +- name: Create and install SSL certificates + include_role: + name: pki + tasks_from: "main_certs.yml" + vars: + pki_setup_host: "{{ galera_ssl_server }}" + pki_dir: "{{ galera_pki_dir }}" + pki_install_ca: "{{ galera_pki_install_ca }}" + when: - galera_use_ssl | bool diff --git a/tasks/galera_client_ssl.yml b/tasks/galera_client_ssl.yml deleted file mode 100644 index 8232569d..00000000 --- a/tasks/galera_client_ssl.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- -# Copyright 2017, 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: Get Galera ssl CA cert contents - slurp: - src: "{{ galera_ssl_ca_cert }}" - register: galera_ca - failed_when: false - delegate_to: "{{ galera_ssl_server }}" - when: - - galera_user_ssl_ca_cert is not defined - -- name: Check for Galera ssl CA cert get failure - debug: - msg: > - The cert retrieval task failed or no CA cert was found. Check the file - "{{ galera_ssl_ca_cert }}" on server "{{ galera_ssl_server }}" before - trying again. - when: - - galera_ca.content is not defined - -- name: Distribute Galera ssl CA cert (SERVER) - copy: - content: "{{ galera_ca.content | b64decode }}" - dest: "{{ galera_ssl_ca_cert }}" - owner: "root" - group: "root" - mode: "0644" - when: - - galera_user_ssl_ca_cert is not defined - - galera_ca.content is defined - -- name: Distribute Galera ssl CA cert (USER) - copy: - src: "{{ galera_user_ssl_ca_cert }}" - dest: "{{ galera_ssl_ca_cert }}" - owner: "root" - group: "root" - mode: "0644" - when: - - galera_user_ssl_ca_cert is defined diff --git a/tasks/galera_server_post_install.yml b/tasks/galera_server_post_install.yml index 8398b401..56eeb4c9 100644 --- a/tasks/galera_server_post_install.yml +++ b/tasks/galera_server_post_install.yml @@ -76,7 +76,21 @@ - { path: "/var/lib/mysql", owner: "mysql", mode: "02755" } - { path: "/etc/mysql/conf.d" } -- include_tasks: galera_server_ssl.yml +- name: Create and install SSL certificates + include_role: + name: pki + tasks_from: "{{ galera_pki_create_ca | ternary('main.yml', 'main_certs.yml') }}" + vars: + pki_setup_host: "{{ galera_ssl_server }}" + pki_dir: "{{ galera_pki_dir }}" + pki_create_ca: "{{ galera_pki_create_ca }}" + pki_regen_ca: "{{ galera_pki_regen_ca }}" + pki_authorities: "{{ galera_pki_authorities }}" + pki_install_ca: "{{ galera_pki_install_ca }}" + pki_create_certificates: "{{ galera_user_ssl_cert is not defined and galera_user_ssl_key is not defined }}" + pki_regen_cert: "{{ galera_pki_regen_cert }}" + pki_certificates: "{{ galera_pki_certificates }}" + pki_install_certificates: "{{ galera_pki_install_certificates }}" when: - galera_use_ssl | bool diff --git a/tasks/galera_server_ssl.yml b/tasks/galera_server_ssl.yml deleted file mode 100644 index 27022a93..00000000 --- a/tasks/galera_server_ssl.yml +++ /dev/null @@ -1,50 +0,0 @@ ---- -# 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: "/etc/mysql/ssl" - state: "directory" - owner: "mysql" - group: "mysql" - mode: "0755" - -- include_tasks: galera_server_ssl_self_signed.yml - when: - - not galera_user_ssl_cert is defined - - not galera_user_ssl_key is defined - - not galera_user_ssl_ca_cert is defined - -- name: Copy CA cert and key (USER) - 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 }}" - mode: "0644" - - src: "{{ galera_user_ssl_cert }}" - dest: "{{ galera_ssl_cert }}" - - src: "{{ galera_user_ssl_key }}" - dest: "{{ galera_ssl_key }}" - mode: "0600" - when: - - galera_user_ssl_cert is defined - - galera_user_ssl_key is defined - - galera_user_ssl_ca_cert is defined - notify: Restart all mysql diff --git a/tasks/galera_server_ssl_self_signed.yml b/tasks/galera_server_ssl_self_signed.yml deleted file mode 100644 index 164df87e..00000000 --- a/tasks/galera_server_ssl_self_signed.yml +++ /dev/null @@ -1,139 +0,0 @@ ---- -# 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: Remove self signed cert for regen - file: - dest: "{{ item }}" - state: "absent" - with_items: - - "{{ galera_ssl_ca_cert }}" - - "{{ galera_ssl_cert }}" - - "{{ galera_ssl_key }}" - - "{{ galera_ssl_ca_cert | dirname }}/galera-csr.pem" - when: - - galera_ssl_self_signed_regen | bool - - inventory_hostname == galera_server_bootstrap_node - -- name: Create Galera CA cert - command: > - openssl req -new -nodes -x509 -subj - "{{ galera_ssl_ca_self_signed_subject }}" - -days 3650 - -keyout {{ galera_ssl_key | dirname }}/galera-ca.key - -out {{ galera_ssl_ca_cert }} - creates={{ galera_ssl_ca_cert }} - when: - - inventory_hostname == galera_server_bootstrap_node - notify: Restart all mysql - -- name: Get CA cert contents and store as var - slurp: - src: "{{ galera_ssl_ca_cert }}" - register: galera_ca - changed_when: false - when: - - inventory_hostname == galera_server_bootstrap_node - -- name: Register a fact for the CA cert - set_fact: - galera_server_ca_cert: "{{ galera_ca.content }}" - when: - - inventory_hostname == galera_server_bootstrap_node - -- name: Create Galera SSL CSR - command: > - openssl req -new -nodes -sha256 -subj - "{{ galera_ssl_self_signed_subject }}" - -days 3650 - -keyout {{ galera_ssl_key }} - -out {{ galera_ssl_ca_cert | dirname }}/galera-csr.pem - -extensions v3_ca - creates={{ galera_ssl_ca_cert | dirname }}/galera-csr.pem - register: create_galera_ssl_request - when: - - inventory_hostname == galera_server_bootstrap_node - notify: Restart all mysql - -- name: Convert generated SSL key to valid format for Galera - command: > - openssl rsa - -in {{ galera_ssl_key }} - -out {{ galera_ssl_key }} - when: - - create_galera_ssl_request is changed - - inventory_hostname == galera_server_bootstrap_node - notify: Restart all mysql - -- name: Get CSR private key contents and store as var - slurp: - src: "{{ galera_ssl_key }}" - register: galera_private_key - changed_when: false - when: - - inventory_hostname == galera_server_bootstrap_node - -- name: Register a fact for the CSR private key - set_fact: - galera_server_private_key: "{{ galera_private_key.content }}" - when: - - inventory_hostname == galera_server_bootstrap_node - -- name: Create Galera SSL signed cert - command: > - openssl x509 -req - -days 3650 - -in {{ galera_ssl_ca_cert | dirname }}/galera-csr.pem - -CA {{ galera_ssl_ca_cert }} - -CAkey {{ galera_ssl_key | dirname }}/galera-ca.key - -out {{ galera_ssl_cert }} - -set_serial 01 - creates={{ galera_ssl_cert }} - when: - - inventory_hostname == galera_server_bootstrap_node - notify: Restart all mysql - -- name: Get signed cert contents and store as var - slurp: - src: "{{ galera_ssl_cert }}" - register: galera_cert - changed_when: false - when: - - inventory_hostname == galera_server_bootstrap_node - -- name: Register a fact for the signed cert contents - set_fact: - galera_server_cert: "{{ galera_cert.content }}" - when: - - inventory_hostname == galera_server_bootstrap_node - -- name: Copy CA cert, private key, and signed cert (SELF) - copy: - content: "{{ hostvars[galera_server_bootstrap_node][item.key] | b64decode }}" - dest: "{{ item.dest }}" - owner: "mysql" - group: "mysql" - mode: "{{ item.mode | default('0640') }}" - with_items: - - key: "galera_server_ca_cert" - dest: "{{ galera_ssl_ca_cert }}" - mode: "0644" - - key: "galera_server_private_key" - dest: "{{ galera_ssl_key }}" - - key: "galera_server_cert" - dest: "{{ galera_ssl_cert }}" - mode: "0600" - when: - - inventory_hostname != galera_server_bootstrap_node - notify: Restart all mysql diff --git a/templates/client.my.cnf.j2 b/templates/client.my.cnf.j2 index ccd7b3ba..c54aa4ec 100644 --- a/templates/client.my.cnf.j2 +++ b/templates/client.my.cnf.j2 @@ -8,3 +8,9 @@ localhost {% endif %} user={{ galera_root_user }} password={{ galera_root_password }} +{% if galera_use_ssl %} +ssl +{% if galera_ssl_verify %} +ssl-verify-server-cert +{% endif %} +{% endif %}