From 8389140f0581b6c32c5ee8c7adb9d9f42bb5e321 Mon Sep 17 00:00:00 2001
From: Mark Goddard <mark@stackhpc.com>
Date: Thu, 13 Aug 2020 09:57:00 +0100
Subject: [PATCH] Prevent overwriting existing Keystone Fernet keys

Steps to reproduce:

* Deploy a cloud
* Add another controller to the inventory
* Deploy to the new controller using --limit:

kolla-ansible deploy --limit new-controller

Expected results:

The new controller uses the cluster's existing fernet keys.

Actual results:

New fernet keys are generated on the new controller, and pushed out to
the existing controllers. This invalidates tokens created from those
keys.

This change prevents the above scenario from happening, by failing the
deployment if there are no hosts with existing Ferney keys to
distribute, and not all Keystone hosts are in the target host list.

Closes-Bug: #1891364

Change-Id: If0c0e038b77fc010a3a017f9841a674d53b16457
---
 .../roles/keystone/tasks/bootstrap_service.yml | 18 ++++++++++++++++++
 ...stone-bootstrap-limit-f0250725633c16de.yaml |  7 +++++++
 2 files changed, 25 insertions(+)
 create mode 100644 releasenotes/notes/prevent-keystone-bootstrap-limit-f0250725633c16de.yaml

diff --git a/ansible/roles/keystone/tasks/bootstrap_service.yml b/ansible/roles/keystone/tasks/bootstrap_service.yml
index 8a20685edd..da27564019 100644
--- a/ansible/roles/keystone/tasks/bootstrap_service.yml
+++ b/ansible/roles/keystone/tasks/bootstrap_service.yml
@@ -6,10 +6,28 @@
       - keystone_fernet
   register: container_facts
 
+# FIXME(mgoddard): This does not catch some cases we might consider
+# bootstrapped:
+# * the keystone_fernet container is created but not running
+# * the keystone_fernet volume exists but no container
+# Probably what we care about is the existence of Fernet key 0.
 - name: Group nodes where keystone_fernet is running
   group_by:
     key: keystone_fernet_{{ container_facts['keystone_fernet'].State | default('bootstrap') }}
 
+# NOTE(mgoddard): If we bootstrap Fernet keys on an existing cluster, this
+# would overwrite existing keys, and invalidate tokens created from them.
+- name: Fail if any hosts need bootstrapping and not all hosts targeted
+  fail:
+    msg: >
+      Some hosts ({{ groups['keystone_fernet_bootstrap'] | join(', ') }}) need
+      Fernet key bootstrapping, but not all Keystone hosts are in the target
+      list. Stopping as it may be unsafe to proceed. Please run without --limit
+      or --serial to bootstrap these hosts.
+  when:
+    - groups['keystone_fernet_running'] is not defined
+    - groups['keystone'] | difference(ansible_play_batch) | list | length > 0
+
 - name: Running Keystone bootstrap container
   vars:
     keystone: "{{ keystone_services.keystone }}"
diff --git a/releasenotes/notes/prevent-keystone-bootstrap-limit-f0250725633c16de.yaml b/releasenotes/notes/prevent-keystone-bootstrap-limit-f0250725633c16de.yaml
new file mode 100644
index 0000000000..90f35d520e
--- /dev/null
+++ b/releasenotes/notes/prevent-keystone-bootstrap-limit-f0250725633c16de.yaml
@@ -0,0 +1,7 @@
+---
+fixes:
+  - |
+    Prevents adding a new Keystone host to an existing cluster when not
+    targeting all Keystone hosts (e.g. due to ``--limit`` or ``--serial``
+    arguments), to avoid overwriting existing Fernet keys. `LP#1891364
+    <https://bugs.launchpad.net/kolla-ansible/+bug/1891364>`__