From d3e7a42cdad6a12d63afd23906cffe081f036745 Mon Sep 17 00:00:00 2001 From: Brent Eagles Date: Fri, 1 Nov 2019 15:36:37 -0230 Subject: [PATCH] Scan existing controllers on update to pick up existing certs/private keys Adds an octavia related role to pick up CA (cert and private key pairs) and client certificate from controllers and modifies existing roles to use them instead of generating new ones. Depends-On: https://review.opendev.org/714982 Change-Id: I5c18a59bf11e3915ef5f88c1eb2af1b4713af35b Co-Authored-By: Gregory Thiemonge Related-Bug: #1849548 Related-Bug: #1849550 --- tripleo_ansible/playbooks/octavia-files.yaml | 17 +++++ .../roles/octavia-controller-check | 1 + .../octavia_controller_check/meta/main.yml | 43 +++++++++++ .../octavia_controller_check/tasks/main.yml | 74 +++++++++++++++++++ .../octavia_controller_config/tasks/main.yml | 19 ++++- .../tasks/check_existing_certs.yml | 69 +++++++++++++++++ .../octavia_overcloud_config/tasks/main.yml | 6 ++ 7 files changed, 226 insertions(+), 3 deletions(-) create mode 120000 tripleo_ansible/roles/octavia-controller-check create mode 100644 tripleo_ansible/roles/octavia_controller_check/meta/main.yml create mode 100644 tripleo_ansible/roles/octavia_controller_check/tasks/main.yml create mode 100644 tripleo_ansible/roles/octavia_overcloud_config/tasks/check_existing_certs.yml diff --git a/tripleo_ansible/playbooks/octavia-files.yaml b/tripleo_ansible/playbooks/octavia-files.yaml index 3b2659b2a..f1e0592e4 100644 --- a/tripleo_ansible/playbooks/octavia-files.yaml +++ b/tripleo_ansible/playbooks/octavia-files.yaml @@ -26,6 +26,22 @@ roles: - octavia_undercloud +- hosts: octavia_nodes + gather_facts: true + vars: + generate_certs: "{{ generate_certs }}" + octavia_confd_prefix: "/var/lib/config-data/puppet-generated/octavia" + ca_cert_path: "{{ ca_cert_path }}" + ca_private_key_path: "{{ ca_private_key_path }}" + client_cert_path: "{{ client_cert_path }}" + stack_action: "{{ stack_action }}" + tasks: + - include_role: + name: octavia-controller-check + when: + - generate_certs | bool + - stack_action == 'UPDATE' + - hosts: octavia_nodes[0] gather_facts: true vars: @@ -66,6 +82,7 @@ private_key_content: "{{ hostvars[groups['octavia_nodes'][0]]['private_key_content'] | default('') }}" ca_cert_content: "{{ hostvars[groups['octavia_nodes'][0]]['ca_cert_content'] | default('') }}" service_pem_content: "{{ hostvars[groups['octavia_nodes'][0]]['service_pem_content'] | default('') }}" + update_certs: "{{ hostvars[groups['octavia_nodes'][0]]['update_certs'] | default(true) }}" generate_certs: "{{ generate_certs }}" ca_cert_path: "{{ ca_cert_path }}" ca_private_key_path: "{{ ca_private_key_path }}" diff --git a/tripleo_ansible/roles/octavia-controller-check b/tripleo_ansible/roles/octavia-controller-check new file mode 120000 index 000000000..0c9321e06 --- /dev/null +++ b/tripleo_ansible/roles/octavia-controller-check @@ -0,0 +1 @@ +octavia_controller_check \ No newline at end of file diff --git a/tripleo_ansible/roles/octavia_controller_check/meta/main.yml b/tripleo_ansible/roles/octavia_controller_check/meta/main.yml new file mode 100644 index 000000000..a105a599f --- /dev/null +++ b/tripleo_ansible/roles/octavia_controller_check/meta/main.yml @@ -0,0 +1,43 @@ +--- +# Copyright 2019 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + + +galaxy_info: + author: OpenStack + description: TripleO OpenStack Role -- octavia_controller_check + company: Red Hat + license: Apache-2.0 + min_ansible_version: 2.7 + # + # Provide a list of supported platforms, and for each platform a list of versions. + # If you don't wish to enumerate all versions for a particular platform, use 'all'. + # To view available platforms and versions (or releases), visit: + # https://galaxy.ansible.com/api/v1/platforms/ + # + platforms: + - name: CentOS + versions: + - 7 + - 8 + + galaxy_tags: + - tripleo + + +# List your role dependencies here, one per line. Be sure to remove the '[]' above, +# if you add dependencies to this list. +dependencies: + - octavia_common diff --git a/tripleo_ansible/roles/octavia_controller_check/tasks/main.yml b/tripleo_ansible/roles/octavia_controller_check/tasks/main.yml new file mode 100644 index 000000000..c86e29421 --- /dev/null +++ b/tripleo_ansible/roles/octavia_controller_check/tasks/main.yml @@ -0,0 +1,74 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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 octavia CA file exists on host + become: true + stat: + path: "{{ octavia_confd_prefix }}/{{ ca_cert_path }}" + register: ca_file_stat + +- name: Get and store CA data + block: + - name: Get CA file if exists + become: true + slurp: + src: "{{ octavia_confd_prefix }}/{{ ca_cert_path }}" + register: ca_file_data + - name: Store CA data + set_fact: + ca_cert: "{{ ca_file_data.content | b64decode }}" + when: + - ca_file_stat.stat.exists | bool + +- name: Check if octavia CA private key exists on host + become: true + stat: + path: "{{ octavia_confd_prefix }}/{{ ca_private_key_path }}" + register: ca_key_file_stat + +- name: Get and store CA private key + block: + - name: Get CA private key file if exists + become: true + slurp: + src: "{{ octavia_confd_prefix }}/{{ ca_private_key_path }}" + register: key_file_data + - name: Store CA data + set_fact: + ca_private_key: "{{ key_file_data.content | b64decode }}" + when: + - ca_key_file_stat.stat.exists | bool + +- name: Check if octavia client certificate exists on host + become: true + stat: + path: "{{ octavia_confd_prefix }}/{{ client_cert_path }}" + register: client_cert_file_stat + +# TODO(gthiemon) Remove those tasks when we support per-controller and +# per-process client certificates for Octavia. +- name: Get and store client certificate + block: + - name: Get client certificate file if exists + become: true + slurp: + src: "{{ octavia_confd_prefix }}/{{ client_cert_path }}" + register: client_file_data + - name: Store client certificate data + set_fact: + service_pem_content: "{{ client_file_data.content | b64decode }}" + when: + - client_cert_file_stat.stat.exists | bool diff --git a/tripleo_ansible/roles/octavia_controller_config/tasks/main.yml b/tripleo_ansible/roles/octavia_controller_config/tasks/main.yml index 5996cbaca..1e5e3a134 100644 --- a/tripleo_ansible/roles/octavia_controller_config/tasks/main.yml +++ b/tripleo_ansible/roles/octavia_controller_config/tasks/main.yml @@ -1,4 +1,18 @@ --- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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: Set node name fact set_fact: @@ -6,9 +20,8 @@ - include_tasks: certificate.yml when: - - private_key_content|length > 0 - - ca_cert_content|length > 0 - - service_pem_content|length > 0 + - generate_certs | bool + - update_certs | bool - include_tasks: netport.yml - include_tasks: netinterface.yml diff --git a/tripleo_ansible/roles/octavia_overcloud_config/tasks/check_existing_certs.yml b/tripleo_ansible/roles/octavia_overcloud_config/tasks/check_existing_certs.yml new file mode 100644 index 000000000..93d3bfefc --- /dev/null +++ b/tripleo_ansible/roles/octavia_overcloud_config/tasks/check_existing_certs.yml @@ -0,0 +1,69 @@ +--- +# Copyright 2020 Red Hat, Inc. +# All Rights Reserved. +# +# 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. + +# TODO(gthiemon) remove service_pem when we support per-controller/per-process +# client certificates. +- name: gather all of the CAs + set_fact: + ca_certs: "{{ groups['octavia_nodes'] | map('extract', hostvars, 'ca_cert') | select('defined') | list }}" + private_keys: "{{ groups['octavia_nodes'] | map('extract', hostvars, 'ca_private_key') | select('defined') | list }}" + service_pems: "{{ groups['octavia_nodes'] | map('extract', hostvars, 'service_pem_content') | select('defined') | list }}" + generate_ca: true + update_certs: true + +- name: grab first values as long as they are unique + block: + - name: count unique CAs and keys + set_fact: + unique_ca_count: "{{ ca_certs | unique | length }}" + unique_pkey_count: "{{ private_keys | unique | length }}" + octavia_node_count: "{{ groups['octavia_nodes'] | list | length }}" + + - name: fail if CA or private key do not match in all Octavia nodes + fail: + msg: | + Inconsistent Octavia configuration detected: + Existing CAs and/or private keys do not match between all Octavia + nodes. To avoid further harm, the deployment will exit with error + now. + when: + - (unique_ca_count | int) > 1 or (unique_pkey_count | int) > 1 + + - name: fail if the number of CA and private key doesn't match + fail: + msg: | + Inconsistent Octavia configuration detected: + Mismatched count for CAs and private keys on controllers. + when: + - (unique_ca_count | int) != (unique_pkey_count | int) + + - name: record cert so others can use it + set_fact: + ca_cert_content: "{{ ca_certs | first }}" + private_key_content: "{{ private_keys | first }}" + service_pem_content: "{{ service_pems | first }}" + + - name: disable CA generation + set_fact: + generate_ca: false + + - name: don't update certificates if CA is present on all octavia nodes + set_fact: + update_certs: false + when: + - (octavia_node_count | int) == (ca_certs | length) + when: + - (ca_certs | length) > 0 diff --git a/tripleo_ansible/roles/octavia_overcloud_config/tasks/main.yml b/tripleo_ansible/roles/octavia_overcloud_config/tasks/main.yml index c3fa50a6a..c08fd1bc1 100644 --- a/tripleo_ansible/roles/octavia_overcloud_config/tasks/main.yml +++ b/tripleo_ansible/roles/octavia_overcloud_config/tasks/main.yml @@ -5,6 +5,12 @@ - include_tasks: quotas.yml +- import_tasks: check_existing_certs.yml + when: + - stack_action == 'UPDATE' + - generate_certs | bool + - include_tasks: certs_gen.yml when: - generate_certs | bool + - (generate_ca | default(true)) | bool