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 <gthiemon@redhat.com>
Related-Bug: #1849548
Related-Bug: #1849550
This commit is contained in:
Brent Eagles 2019-11-01 15:36:37 -02:30 committed by Gregory Thiemonge
parent b2b5a76231
commit d3e7a42cda
7 changed files with 226 additions and 3 deletions

View File

@ -26,6 +26,22 @@
roles: roles:
- octavia_undercloud - 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] - hosts: octavia_nodes[0]
gather_facts: true gather_facts: true
vars: vars:
@ -66,6 +82,7 @@
private_key_content: "{{ hostvars[groups['octavia_nodes'][0]]['private_key_content'] | default('') }}" private_key_content: "{{ hostvars[groups['octavia_nodes'][0]]['private_key_content'] | default('') }}"
ca_cert_content: "{{ hostvars[groups['octavia_nodes'][0]]['ca_cert_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('') }}" 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 }}" generate_certs: "{{ generate_certs }}"
ca_cert_path: "{{ ca_cert_path }}" ca_cert_path: "{{ ca_cert_path }}"
ca_private_key_path: "{{ ca_private_key_path }}" ca_private_key_path: "{{ ca_private_key_path }}"

View File

@ -0,0 +1 @@
octavia_controller_check

View File

@ -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

View File

@ -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

View File

@ -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 - name: Set node name fact
set_fact: set_fact:
@ -6,9 +20,8 @@
- include_tasks: certificate.yml - include_tasks: certificate.yml
when: when:
- private_key_content|length > 0 - generate_certs | bool
- ca_cert_content|length > 0 - update_certs | bool
- service_pem_content|length > 0
- include_tasks: netport.yml - include_tasks: netport.yml
- include_tasks: netinterface.yml - include_tasks: netinterface.yml

View File

@ -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

View File

@ -5,6 +5,12 @@
- include_tasks: quotas.yml - include_tasks: quotas.yml
- import_tasks: check_existing_certs.yml
when:
- stack_action == 'UPDATE'
- generate_certs | bool
- include_tasks: certs_gen.yml - include_tasks: certs_gen.yml
when: when:
- generate_certs | bool - generate_certs | bool
- (generate_ca | default(true)) | bool