diff --git a/releasenotes/notes/disable-password-generation-uc-cced193be3d1aa86.yaml b/releasenotes/notes/disable-password-generation-uc-cced193be3d1aa86.yaml new file mode 100644 index 000000000..dc886d573 --- /dev/null +++ b/releasenotes/notes/disable-password-generation-uc-cced193be3d1aa86.yaml @@ -0,0 +1,10 @@ +--- +upgrade: + - | + Instack undercloud legacy passwords should be customized by its original + ``undercloud-passwords.conf`` location, when upgrading from instack UC. + Those passwords will be automatically transitioned to + ``tripleo-undercloud-passwords.yaml`` during upgrade. Changes made to the + legacy location become ignored after that. Use + ``tripleo-undercloud-passwords.yaml`` to manually update UC passwords + further on. diff --git a/tripleoclient/tests/v1/tripleo/test_tripleo_deploy.py b/tripleoclient/tests/v1/tripleo/test_tripleo_deploy.py index b4b1a226b..f3bbaffa2 100644 --- a/tripleoclient/tests/v1/tripleo/test_tripleo_deploy.py +++ b/tripleoclient/tests/v1/tripleo/test_tripleo_deploy.py @@ -131,9 +131,53 @@ class TestDeployUndercloud(TestPluginV1): @mock.patch('subprocess.check_call', autospec=True) @mock.patch('tripleo_common.utils.passwords.generate_passwords') @mock.patch('yaml.safe_dump') - def test_update_passwords_env_update(self, mock_dump, mock_pw, mock_cc, - mock_exists, mock_chmod, mock_user): - pw_dict = {"GeneratedPassword": 123} + def test_update_passwords_env(self, mock_dump, mock_pw, mock_cc, + mock_exists, mock_chmod, mock_user): + pw_dict = {"GeneratedPassword": 123, "LegacyPass": "override me"} + pw_conf_path = os.path.join(self.temp_homedir, + 'undercloud-passwords.conf') + t_pw_conf_path = os.path.join( + self.temp_homedir, 'tripleo-undercloud-passwords.yaml') + + mock_pw.return_value = pw_dict + mock_exists.return_value = True + with open(t_pw_conf_path, 'w') as t_pw: + t_pw.write('parameter_defaults: {ExistingKey: xyz, ' + 'LegacyPass: pick-me-legacy-tht, ' + 'RpcPassword: pick-me-rpc}\n') + + with open(pw_conf_path, 'w') as t_pw: + t_pw.write('[auth]\nundercloud_db_password = ignore-me-mysql\n' + 'undercloud_rabbit_password = ignore-me-rabbit\n' + 'undercloud_rpc_password = ignore-me-rpc\n' + 'undercloud_legacy_pass = ignore-me-legacy\n') + + self.cmd._update_passwords_env(self.temp_homedir, + 'stack', upgrade=False, + passwords={'ADefault': 456, + 'ExistingKey': + 'dontupdate'}) + expected_dict = { + 'parameter_defaults': {'GeneratedPassword': 123, + 'LegacyPass': 'pick-me-legacy-tht', + 'RpcPassword': 'pick-me-rpc', + 'ExistingKey': 'xyz', + 'ADefault': 456}} + mock_dump.assert_called_once_with(expected_dict, + mock.ANY, + default_flow_style=False) + + # TODO(bogdando) drop once we have proper oslo.privsep + @mock.patch('getpass.getuser', return_value='stack') + @mock.patch('os.chmod') + @mock.patch('os.path.exists') + # TODO(bogdando) drop once we have proper oslo.privsep + @mock.patch('subprocess.check_call', autospec=True) + @mock.patch('tripleo_common.utils.passwords.generate_passwords') + @mock.patch('yaml.safe_dump') + def test_update_passwords_env_upgrade(self, mock_dump, mock_pw, mock_cc, + mock_exists, mock_chmod, mock_user): + pw_dict = {"GeneratedPassword": 123, "LegacyPass": "override me"} pw_conf_path = os.path.join(self.temp_homedir, 'undercloud-passwords.conf') t_pw_conf_path = os.path.join( @@ -145,20 +189,29 @@ class TestDeployUndercloud(TestPluginV1): return not file_name.startswith('/etc/keystone') mock_exists.side_effect = mock_file_exists with open(t_pw_conf_path, 'w') as t_pw: - t_pw.write('parameter_defaults: {ExistingKey: xyz}\n') + t_pw.write('parameter_defaults: {ExistingKey: xyz, ' + 'LegacyPass: override-me-legacy, ' + 'RpcPassword: override-me-rpc}\n') with open(pw_conf_path, 'w') as t_pw: - t_pw.write('[auth]\nundercloud_db_password = abc\n') + t_pw.write('[auth]\nundercloud_db_password = pick-me-mysql\n' + 'undercloud_rabbit_password = pick-me-rabbit\n' + 'undercloud_rpc_password = pick-me-rpc\n' + 'undercloud_legacy_pass = pick-me-legacy-instack\n') self.cmd._update_passwords_env(self.temp_homedir, - 'stack', + 'stack', upgrade=True, passwords={'ADefault': 456, 'ExistingKey': 'dontupdate'}) - expected_dict = {'parameter_defaults': {'GeneratedPassword': 123, - 'ExistingKey': 'xyz', - 'MysqlRootPassword': 'abc', - 'ADefault': 456}} + expected_dict = { + 'parameter_defaults': {'GeneratedPassword': 123, + 'ExistingKey': 'xyz', + 'MysqlRootPassword': 'pick-me-mysql', + 'RpcPassword': 'pick-me-rpc', + 'RabbitPassword': 'pick-me-rabbit', + 'LegacyPass': 'pick-me-legacy-instack', + 'ADefault': 456}} mock_dump.assert_called_once_with(expected_dict, mock.ANY, default_flow_style=False) diff --git a/tripleoclient/v1/tripleo_deploy.py b/tripleoclient/v1/tripleo_deploy.py index 0029cc06d..032a20f2b 100644 --- a/tripleoclient/v1/tripleo_deploy.py +++ b/tripleoclient/v1/tripleo_deploy.py @@ -260,84 +260,89 @@ class Deploy(command.Command): constants.PUPPET_MODULES, constants.PUPPET_BASE) - def _update_passwords_env(self, output_dir, user, passwords=None): + def _update_passwords_env(self, output_dir, user, upgrade=None, + passwords=None): pw_file = os.path.join(output_dir, 'tripleo-undercloud-passwords.yaml') undercloud_pw_file = os.path.join(output_dir, 'undercloud-passwords.conf') + + # Generated passwords take the lowest precedence, allowing + # custom overrides stack_env = {'parameter_defaults': {}} - - # Getting passwords that were managed by instack-undercloud so - # we can upgrade to a containerized undercloud and keep old passwords. - legacy_env = {} - if os.path.exists(undercloud_pw_file): - config = configparser.ConfigParser() - config.read(undercloud_pw_file) - for k, v in config.items('auth'): - # Manage exceptions - if k == 'undercloud_db_password': - k = 'MysqlRootPassword' - elif k == 'undercloud_rabbit_username': - k = 'RpcUserName' - elif k == 'undercloud_rabbit_password': - try: - # NOTE(aschultz): Only save rabbit password to rpc - # if it's not already defined for the upgrade case. - # The passwords are usually different so we don't - # want to overwrite it if it already exists because - # we'll end up rewriting the passwords later and - # causing problems. - config.get('auth', 'undercloud_rpc_password') - except Exception: - legacy_env['RpcPassword'] = v - k = 'RabbitPassword' - elif k == 'undercloud_rabbit_cookie': - k = 'RabbitCookie' - elif k == 'undercloud_heat_encryption_key': - k = 'HeatAuthEncryptionKey' - elif k == 'undercloud_libvirt_tls_password': - k = 'LibvirtTLSPassword' - elif k == 'undercloud_ha_proxy_stats_password': - k = 'HAProxyStatsPassword' - else: - k = ''.join(i.capitalize() for i in k.split('_')[1:]) - legacy_env[k] = v - + stack_env['parameter_defaults'] = password_utils.generate_passwords( + stack_env=stack_env) if os.path.exists(pw_file): with open(pw_file) as pf: - stack_env = yaml.safe_load(pf.read()) + stack_env['parameter_defaults'].update( + yaml.safe_load(pf.read())['parameter_defaults']) - # Get the keystone keys before upgrade - keystone_fernet_repo = '/etc/keystone/fernet-keys/' - keystone_credential_repo = '/etc/keystone/credential-keys/' - self._set_data_rights('/etc/keystone', user=user) + if upgrade: + # Getting passwords that were managed by instack-undercloud so + # we can upgrade to a containerized undercloud and keep old + # passwords. + legacy_env = {} + if os.path.exists(undercloud_pw_file): + config = configparser.ConfigParser() + config.read(undercloud_pw_file) + for k, v in config.items('auth'): + # Manage exceptions + if k == 'undercloud_db_password': + k = 'MysqlRootPassword' + elif k == 'undercloud_rabbit_username': + k = 'RpcUserName' + elif k == 'undercloud_rabbit_password': + try: + # NOTE(aschultz): Only save rabbit password to rpc + # if it's not already defined for the upgrade case. + # The passwords are usually different so we don't + # want to overwrite it if it already exists because + # we'll end up rewriting the passwords later and + # causing problems. + config.get('auth', 'undercloud_rpc_password') + except Exception: + legacy_env['RpcPassword'] = v + k = 'RabbitPassword' + elif k == 'undercloud_rabbit_cookie': + k = 'RabbitCookie' + elif k == 'undercloud_heat_encryption_key': + k = 'HeatAuthEncryptionKey' + elif k == 'undercloud_libvirt_tls_password': + k = 'LibvirtTLSPassword' + elif k == 'undercloud_ha_proxy_stats_password': + k = 'HAProxyStatsPassword' + else: + k = ''.join(i.capitalize() for i in k.split('_')[1:]) + legacy_env[k] = v - for key_index in range(0, 2): - file_name = keystone_credential_repo + str(key_index) - key = 'KeystoneCredential' + str(key_index) - if os.path.exists(file_name): - with open(file_name, 'r') as file_content: - content = file_content.read() - legacy_env[key] = content + # Get the keystone keys before upgrade + keystone_fernet_repo = '/etc/keystone/fernet-keys/' + keystone_credential_repo = '/etc/keystone/credential-keys/' + self._set_data_rights('/etc/keystone', user=user) - fernet_keys = {} - file_count = 0 - if os.path.exists(keystone_fernet_repo): - file_count = len(os.listdir(keystone_fernet_repo)) + for key_index in range(0, 2): + file_name = keystone_credential_repo + str(key_index) + key = 'KeystoneCredential' + str(key_index) + if os.path.exists(file_name): + with open(file_name, 'r') as file_content: + content = file_content.read() + legacy_env[key] = content - for key_index in range(0, file_count): - file_name = keystone_fernet_repo + str(key_index) - if os.path.exists(file_name): - with open(file_name, 'r') as file_content: - content = file_content.read() - fernet_keys[file_name] = {'content': content} - if fernet_keys: - legacy_env['KeystoneFernetKeys'] = fernet_keys + fernet_keys = {} + file_count = 0 + if os.path.exists(keystone_fernet_repo): + file_count = len(os.listdir(keystone_fernet_repo)) - pw = password_utils.generate_passwords(stack_env=stack_env) - stack_env['parameter_defaults'].update(pw) - # Override what has been generated by tripleo-common with old passwords - # if any. - stack_env['parameter_defaults'].update(legacy_env) + for key_index in range(0, file_count): + file_name = keystone_fernet_repo + str(key_index) + if os.path.exists(file_name): + with open(file_name, 'r') as file_content: + content = file_content.read() + fernet_keys[file_name] = {'content': content} + if fernet_keys: + legacy_env['KeystoneFernetKeys'] = fernet_keys + + # Override with picked legacy instack-undercloud values + stack_env['parameter_defaults'].update(legacy_env) if passwords: # These passwords are the DefaultPasswords so we only @@ -584,8 +589,12 @@ class Deploy(command.Command): for e in plan_env_data.get('environments', {})] # this will allow the user to overwrite passwords with custom envs - pw_file = self._update_passwords_env(self.output_dir, - parsed_args.deployment_user) + # or pick instack legacy passwords as is, if upgrading from instack + pw_file = self._update_passwords_env( + self.output_dir, + parsed_args.deployment_user, + parsed_args.upgrade, + ) environments.append(pw_file) # use deployed-server because we run os-collect-config locally