summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2017-06-15 11:25:22 +0000
committerGerrit Code Review <review@openstack.org>2017-06-15 11:25:22 +0000
commitdea4a8264c3b08cf72325f8c07274318e79b596e (patch)
treeae09a22b6715d66a338bc8df99d8c41e0f132ab5
parentce47e3d408c42c29d2bbef45a5ebcb7ac6f0f8ce (diff)
parent4bc5c71a3e58b4fe834a5de3568b5f3ca2674fb9 (diff)
Merge "Create mistral action to rotate fernet keys from passwords variable"
-rw-r--r--tripleo_common/actions/parameters.py64
-rw-r--r--tripleo_common/tests/actions/test_parameters.py38
-rw-r--r--tripleo_common/utils/passwords.py5
3 files changed, 105 insertions, 2 deletions
diff --git a/tripleo_common/actions/parameters.py b/tripleo_common/actions/parameters.py
index 8e5c8ad..08bc814 100644
--- a/tripleo_common/actions/parameters.py
+++ b/tripleo_common/actions/parameters.py
@@ -454,3 +454,67 @@ class GetProfileOfFlavorAction(base.TripleOAction):
454 except exception.DeriveParamsError as err: 454 except exception.DeriveParamsError as err:
455 LOG.error('Derive Params Error: %s', err) 455 LOG.error('Derive Params Error: %s', err)
456 return mistral_workflow_utils.Result(error=str(err)) 456 return mistral_workflow_utils.Result(error=str(err))
457
458
459class RotateFernetKeysAction(GetPasswordsAction):
460 """Rotate fernet keys from the environment
461
462 This method rotates the fernet keys that are saved in the environment, in
463 the passwords parameter.
464 """
465
466 def __init__(self, container=constants.DEFAULT_CONTAINER_NAME):
467 super(RotateFernetKeysAction, self).__init__()
468 self.container = container
469
470 def run(self, context):
471 swift = self.get_object_client(context)
472
473 try:
474 env = plan_utils.get_env(swift, self.container)
475 except swiftexceptions.ClientException as err:
476 err_msg = ("Error retrieving environment for plan %s: %s" % (
477 self.container, err))
478 LOG.exception(err_msg)
479 return mistral_workflow_utils.Result(error=err_msg)
480
481 parameter_defaults = env.get('parameter_defaults', {})
482 passwords = env.get('passwords', {})
483 for name in constants.PASSWORD_PARAMETER_NAMES:
484 if name in parameter_defaults:
485 passwords[name] = parameter_defaults[name]
486
487 next_index = self.get_next_index(passwords['KeystoneFernetKeys'])
488 keys_map = self.rotate_keys(passwords['KeystoneFernetKeys'],
489 next_index)
490
491 env['passwords']['KeystoneFernetKeys'] = keys_map
492
493 try:
494 plan_utils.put_env(swift, env)
495 except swiftexceptions.ClientException as err:
496 err_msg = "Error uploading to container: %s" % err
497 LOG.exception(err_msg)
498 return mistral_workflow_utils.Result(error=err_msg)
499
500 self.cache_delete(context,
501 self.container,
502 "tripleo.parameters.get")
503
504 return keys_map
505
506 def get_next_index(self, keys_map):
507 def get_index(path):
508 return int(path[path.rfind('/') + 1:])
509 return get_index(max(keys_map, key=get_index)) + 1
510
511 def rotate_keys(self, keys_map, next_index):
512 next_index_path = password_utils.KEYSTONE_FERNET_REPO + str(next_index)
513 zero_index_path = password_utils.KEYSTONE_FERNET_REPO + '0'
514
515 # promote staged key to be new primary
516 keys_map[next_index_path] = keys_map[zero_index_path]
517 # Set new staged key
518 keys_map[zero_index_path] = {
519 'content': password_utils.create_keystone_credential()}
520 return keys_map
diff --git a/tripleo_common/tests/actions/test_parameters.py b/tripleo_common/tests/actions/test_parameters.py
index f155eb2..5ecb5c8 100644
--- a/tripleo_common/tests/actions/test_parameters.py
+++ b/tripleo_common/tests/actions/test_parameters.py
@@ -21,6 +21,7 @@ from tripleo_common.actions import parameters
21from tripleo_common import constants 21from tripleo_common import constants
22from tripleo_common import exception 22from tripleo_common import exception
23from tripleo_common.tests import base 23from tripleo_common.tests import base
24from tripleo_common.utils import passwords as password_utils
24 25
25_EXISTING_PASSWORDS = { 26_EXISTING_PASSWORDS = {
26 'MistralPassword': 'VFJeqBKbatYhQm9jja67hufft', 27 'MistralPassword': 'VFJeqBKbatYhQm9jja67hufft',
@@ -879,3 +880,40 @@ class GetProfileOfFlavorActionTest(base.TestCase):
879 result = action.run(mock_ctx) 880 result = action.run(mock_ctx)
880 self.assertTrue(result.is_error()) 881 self.assertTrue(result.is_error())
881 mock_get_profile_of_flavor.assert_called_once() 882 mock_get_profile_of_flavor.assert_called_once()
883
884
885class RotateFernetKeysActionTest(base.TestCase):
886
887 def test_get_next_index(self):
888 action = parameters.RotateFernetKeysAction()
889 keys_map = {
890 password_utils.KEYSTONE_FERNET_REPO + '0': {
891 'content': 'Some key'},
892 password_utils.KEYSTONE_FERNET_REPO + '1': {
893 'content': 'Some other key'},
894 }
895 next_index = action.get_next_index(keys_map)
896 self.assertEqual(next_index, 2)
897
898 @mock.patch('tripleo_common.utils.passwords.'
899 'create_keystone_credential')
900 def test_rotate_keys(self, mock_keystone_creds):
901 action = parameters.RotateFernetKeysAction()
902 mock_keystone_creds.return_value = 'Some new key'
903
904 staged_key_index = password_utils.KEYSTONE_FERNET_REPO + '0'
905 new_primary_key_index = password_utils.KEYSTONE_FERNET_REPO + '2'
906 keys_map = {
907 password_utils.KEYSTONE_FERNET_REPO + '0': {
908 'content': 'Some key'},
909 password_utils.KEYSTONE_FERNET_REPO + '1': {
910 'content': 'Some other key'},
911 }
912 new_keys_map = action.rotate_keys(keys_map, 2)
913
914 # Staged key should be the new key
915 self.assertEqual('Some new key',
916 new_keys_map[staged_key_index]['content'])
917 # primary key should be the previous staged key
918 self.assertEqual('Some key',
919 new_keys_map[new_primary_key_index]['content'])
diff --git a/tripleo_common/utils/passwords.py b/tripleo_common/utils/passwords.py
index 37c9add..52da657 100644
--- a/tripleo_common/utils/passwords.py
+++ b/tripleo_common/utils/passwords.py
@@ -27,6 +27,7 @@ from tripleo_common import constants
27 27
28 28
29_MIN_PASSWORD_SIZE = 25 29_MIN_PASSWORD_SIZE = 25
30KEYSTONE_FERNET_REPO = '/etc/keystone/fernet-keys/'
30LOG = logging.getLogger(__name__) 31LOG = logging.getLogger(__name__)
31 32
32 33
@@ -80,9 +81,9 @@ def generate_passwords(mistralclient=None, stack_env=None):
80 81
81def create_fernet_keys_repo_structure_and_keys(): 82def create_fernet_keys_repo_structure_and_keys():
82 return { 83 return {
83 '/etc/keystone/fernet-keys/0': { 84 KEYSTONE_FERNET_REPO + '0': {
84 'content': create_keystone_credential()}, 85 'content': create_keystone_credential()},
85 '/etc/keystone/fernet-keys/1': { 86 KEYSTONE_FERNET_REPO + '1': {
86 'content': create_keystone_credential()} 87 'content': create_keystone_credential()}
87 } 88 }
88 89