Check for missing/unexpected data in encryption utility
Closes-Bug: #1559302 Change-Id: I753c3e697fdaa4a282d9808035b0e3745914d153
This commit is contained in:
parent
fe57943380
commit
2009e57b4a
|
@ -1233,11 +1233,13 @@ def db_encrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
:param batch_size: number of templates requested from db in each iteration.
|
:param batch_size: number of templates requested from db in each iteration.
|
||||||
50 means that heat requests 50 templates, encrypt them
|
50 means that heat requests 50 templates, encrypt them
|
||||||
and proceed with next 50 items.
|
and proceed with next 50 items.
|
||||||
|
:return: list of exceptions encountered during encryption
|
||||||
"""
|
"""
|
||||||
from heat.engine import template
|
from heat.engine import template
|
||||||
session = get_session()
|
session = get_session()
|
||||||
with session.begin():
|
with session.begin():
|
||||||
query = session.query(models.RawTemplate)
|
query = session.query(models.RawTemplate)
|
||||||
|
excs = []
|
||||||
for raw_template in _get_batch(
|
for raw_template in _get_batch(
|
||||||
session=session, ctxt=ctxt, query=query,
|
session=session, ctxt=ctxt, query=query,
|
||||||
model=models.RawTemplate, batch_size=batch_size):
|
model=models.RawTemplate, batch_size=batch_size):
|
||||||
|
@ -1247,15 +1249,21 @@ def db_encrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
param_schemata = tmpl.param_schemata()
|
param_schemata = tmpl.param_schemata()
|
||||||
env = raw_template.environment
|
env = raw_template.environment
|
||||||
|
|
||||||
|
if (not env or
|
||||||
|
'parameters' not in env or
|
||||||
|
not tmpl.param_schemata()):
|
||||||
|
continue
|
||||||
if 'encrypted_param_names' in env:
|
if 'encrypted_param_names' in env:
|
||||||
encrypted_params = env['encrypted_param_names']
|
encrypted_params = env['encrypted_param_names']
|
||||||
else:
|
else:
|
||||||
encrypted_params = []
|
encrypted_params = []
|
||||||
|
|
||||||
for param_name, param_val in env['parameters'].items():
|
for param_name, param_val in env['parameters'].items():
|
||||||
if ((param_name in encrypted_params) or
|
if ((param_name in encrypted_params) or
|
||||||
(not param_schemata[param_name].hidden)):
|
(not param_schemata[param_name].hidden)):
|
||||||
continue
|
continue
|
||||||
encrypted_val = crypt.encrypt(param_val, encryption_key)
|
encrypted_val = crypt.encrypt(six.text_type(param_val),
|
||||||
|
encryption_key)
|
||||||
env['parameters'][param_name] = encrypted_val
|
env['parameters'][param_name] = encrypted_val
|
||||||
encrypted_params.append(param_name)
|
encrypted_params.append(param_name)
|
||||||
|
|
||||||
|
@ -1264,9 +1272,10 @@ def db_encrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
environment['encrypted_param_names'] = encrypted_params
|
environment['encrypted_param_names'] = encrypted_params
|
||||||
raw_template_update(ctxt, raw_template.id,
|
raw_template_update(ctxt, raw_template.id,
|
||||||
{'environment': environment})
|
{'environment': environment})
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
LOG.exception(_LE('Failed to encrypt parameters of raw '
|
LOG.exception(_LE('Failed to encrypt parameters of raw '
|
||||||
'template %(id)d'), {'id': raw_template.id})
|
'template %(id)d'), {'id': raw_template.id})
|
||||||
|
excs.append(exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
query = session.query(models.Resource).filter(
|
query = session.query(models.Resource).filter(
|
||||||
|
@ -1277,6 +1286,8 @@ def db_encrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
batch_size=batch_size):
|
batch_size=batch_size):
|
||||||
try:
|
try:
|
||||||
result = {}
|
result = {}
|
||||||
|
if not resource.properties_data:
|
||||||
|
continue
|
||||||
for prop_name, prop_value in resource.properties_data.items():
|
for prop_name, prop_value in resource.properties_data.items():
|
||||||
prop_string = jsonutils.dumps(prop_value)
|
prop_string = jsonutils.dumps(prop_value)
|
||||||
encrypted_value = crypt.encrypt(prop_string,
|
encrypted_value = crypt.encrypt(prop_string,
|
||||||
|
@ -1288,10 +1299,12 @@ def db_encrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
{'properties_data': result,
|
{'properties_data': result,
|
||||||
'properties_data_encrypted': True},
|
'properties_data_encrypted': True},
|
||||||
resource.atomic_key)
|
resource.atomic_key)
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
LOG.exception(_LE('Failed to encrypt properties_data of '
|
LOG.exception(_LE('Failed to encrypt properties_data of '
|
||||||
'resource %(id)d'), {'id': resource.id})
|
'resource %(id)d'), {'id': resource.id})
|
||||||
|
excs.append(exc)
|
||||||
continue
|
continue
|
||||||
|
return excs
|
||||||
|
|
||||||
|
|
||||||
def db_decrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
def db_decrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
|
@ -1303,8 +1316,10 @@ def db_decrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
:param batch_size: number of templates requested from db in each iteration.
|
:param batch_size: number of templates requested from db in each iteration.
|
||||||
50 means that heat requests 50 templates, encrypt them
|
50 means that heat requests 50 templates, encrypt them
|
||||||
and proceed with next 50 items.
|
and proceed with next 50 items.
|
||||||
|
:return: list of exceptions encountered during decryption
|
||||||
"""
|
"""
|
||||||
session = get_session()
|
session = get_session()
|
||||||
|
excs = []
|
||||||
with session.begin():
|
with session.begin():
|
||||||
query = session.query(models.RawTemplate)
|
query = session.query(models.RawTemplate)
|
||||||
for raw_template in _get_batch(
|
for raw_template in _get_batch(
|
||||||
|
@ -1324,9 +1339,10 @@ def db_decrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
environment['encrypted_param_names'] = []
|
environment['encrypted_param_names'] = []
|
||||||
raw_template_update(ctxt, raw_template.id,
|
raw_template_update(ctxt, raw_template.id,
|
||||||
{'environment': environment})
|
{'environment': environment})
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
LOG.exception(_LE('Failed to decrypt parameters of raw '
|
LOG.exception(_LE('Failed to decrypt parameters of raw '
|
||||||
'template %(id)d'), {'id': raw_template.id})
|
'template %(id)d'), {'id': raw_template.id})
|
||||||
|
excs.append(exc)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
query = session.query(models.Resource).filter(
|
query = session.query(models.Resource).filter(
|
||||||
|
@ -1349,10 +1365,12 @@ def db_decrypt_parameters_and_properties(ctxt, encryption_key, batch_size=50):
|
||||||
{'properties_data': result,
|
{'properties_data': result,
|
||||||
'properties_data_encrypted': False},
|
'properties_data_encrypted': False},
|
||||||
resource.atomic_key)
|
resource.atomic_key)
|
||||||
except Exception:
|
except Exception as exc:
|
||||||
LOG.exception(_LE('Failed to decrypt properties_data of '
|
LOG.exception(_LE('Failed to decrypt properties_data of '
|
||||||
'resource %(id)d'), {'id': resource.id})
|
'resource %(id)d'), {'id': resource.id})
|
||||||
|
excs.append(exc)
|
||||||
continue
|
continue
|
||||||
|
return excs
|
||||||
|
|
||||||
|
|
||||||
def _get_batch(session, ctxt, query, model, batch_size=50):
|
def _get_batch(session, ctxt, query, model, batch_size=50):
|
||||||
|
|
|
@ -2928,7 +2928,7 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
|
|
||||||
def _create_template(self):
|
def _create_template(self):
|
||||||
"""Initialize sample template."""
|
"""Initialize sample template."""
|
||||||
t = template_format.parse('''
|
self.t = template_format.parse('''
|
||||||
heat_template_version: 2013-05-23
|
heat_template_version: 2013-05-23
|
||||||
parameters:
|
parameters:
|
||||||
param1:
|
param1:
|
||||||
|
@ -2973,7 +2973,7 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
type: GenericResourceType
|
type: GenericResourceType
|
||||||
''')
|
''')
|
||||||
template = {
|
template = {
|
||||||
'template': t,
|
'template': self.t,
|
||||||
'files': {'foo': 'bar'},
|
'files': {'foo': 'bar'},
|
||||||
'environment': {
|
'environment': {
|
||||||
'parameters': {
|
'parameters': {
|
||||||
|
@ -2996,7 +2996,7 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
'param_comma_list': '[\"Hola\", \"Senor\"]'}
|
'param_comma_list': '[\"Hola\", \"Senor\"]'}
|
||||||
|
|
||||||
raw_templates = session.query(models.RawTemplate).all()
|
raw_templates = session.query(models.RawTemplate).all()
|
||||||
self.assertTrue(raw_templates)
|
self.assertNotEqual([], raw_templates)
|
||||||
for r_tmpl in raw_templates:
|
for r_tmpl in raw_templates:
|
||||||
for param_name, param_value in hidden_params_dict.items():
|
for param_name, param_value in hidden_params_dict.items():
|
||||||
self.assertEqual(param_value,
|
self.assertEqual(param_value,
|
||||||
|
@ -3004,18 +3004,18 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
self.assertEqual('foo',
|
self.assertEqual('foo',
|
||||||
r_tmpl.environment['parameters']['param1'])
|
r_tmpl.environment['parameters']['param1'])
|
||||||
resources = session.query(models.Resource).all()
|
resources = session.query(models.Resource).all()
|
||||||
self.assertTrue(resources)
|
self.assertNotEqual([], resources)
|
||||||
for resource in resources:
|
for resource in resources:
|
||||||
self.assertEqual('bar1', resource.properties_data['foo1'])
|
self.assertEqual('bar1', resource.properties_data['foo1'])
|
||||||
|
|
||||||
def encrypt(enc_key=None):
|
def encrypt(enc_key=None):
|
||||||
if enc_key is None:
|
if enc_key is None:
|
||||||
enc_key = cfg.CONF.auth_encryption_key
|
enc_key = cfg.CONF.auth_encryption_key
|
||||||
db_api.db_encrypt_parameters_and_properties(
|
self.assertEqual([], db_api.db_encrypt_parameters_and_properties(
|
||||||
self.ctx, enc_key, batch_size=batch_size)
|
self.ctx, enc_key, batch_size=batch_size))
|
||||||
session = db_api.get_session()
|
session = db_api.get_session()
|
||||||
enc_raw_templates = session.query(models.RawTemplate).all()
|
enc_raw_templates = session.query(models.RawTemplate).all()
|
||||||
self.assertTrue(enc_raw_templates)
|
self.assertNotEqual([], enc_raw_templates)
|
||||||
for enc_tmpl in enc_raw_templates:
|
for enc_tmpl in enc_raw_templates:
|
||||||
for param_name in hidden_params_dict.keys():
|
for param_name in hidden_params_dict.keys():
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
|
@ -3029,7 +3029,7 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
|
|
||||||
encrypt_value = enc_tmpl.environment['parameters']['param2'][1]
|
encrypt_value = enc_tmpl.environment['parameters']['param2'][1]
|
||||||
enc_resources = session.query(models.Resource).all()
|
enc_resources = session.query(models.Resource).all()
|
||||||
self.assertTrue(enc_resources)
|
self.assertNotEqual([], enc_resources)
|
||||||
for enc_prop in enc_resources:
|
for enc_prop in enc_resources:
|
||||||
self.assertEqual('cryptography_decrypt_v1',
|
self.assertEqual('cryptography_decrypt_v1',
|
||||||
enc_prop.properties_data['foo1'][0])
|
enc_prop.properties_data['foo1'][0])
|
||||||
|
@ -3045,11 +3045,11 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
def decrypt(enc_key=None):
|
def decrypt(enc_key=None):
|
||||||
if enc_key is None:
|
if enc_key is None:
|
||||||
enc_key = cfg.CONF.auth_encryption_key
|
enc_key = cfg.CONF.auth_encryption_key
|
||||||
db_api.db_decrypt_parameters_and_properties(
|
self.assertEqual([], db_api.db_decrypt_parameters_and_properties(
|
||||||
self.ctx, enc_key, batch_size=batch_size)
|
self.ctx, enc_key, batch_size=batch_size))
|
||||||
session = db_api.get_session()
|
session = db_api.get_session()
|
||||||
dec_templates = session.query(models.RawTemplate).all()
|
dec_templates = session.query(models.RawTemplate).all()
|
||||||
self.assertTrue(dec_templates)
|
self.assertNotEqual([], dec_templates)
|
||||||
for dec_tmpl in dec_templates:
|
for dec_tmpl in dec_templates:
|
||||||
self.assertNotEqual(
|
self.assertNotEqual(
|
||||||
encrypt_value,
|
encrypt_value,
|
||||||
|
@ -3073,7 +3073,7 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
|
|
||||||
decrypt_value = dec_tmpl.environment['parameters']['param2'][1]
|
decrypt_value = dec_tmpl.environment['parameters']['param2'][1]
|
||||||
dec_resources = session.query(models.Resource).all()
|
dec_resources = session.query(models.Resource).all()
|
||||||
self.assertTrue(dec_resources)
|
self.assertNotEqual([], dec_resources)
|
||||||
for dec_prop in dec_resources:
|
for dec_prop in dec_resources:
|
||||||
self.assertEqual('bar1', dec_prop.properties_data['foo1'])
|
self.assertEqual('bar1', dec_prop.properties_data['foo1'])
|
||||||
return decrypt_value
|
return decrypt_value
|
||||||
|
@ -3152,8 +3152,10 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
self.assertEqual('', r_tmpls[1].environment)
|
self.assertEqual('', r_tmpls[1].environment)
|
||||||
|
|
||||||
# Test encryption
|
# Test encryption
|
||||||
db_api.db_encrypt_parameters_and_properties(
|
enc_result = db_api.db_encrypt_parameters_and_properties(
|
||||||
self.ctx, cfg.CONF.auth_encryption_key, batch_size=50)
|
self.ctx, cfg.CONF.auth_encryption_key, batch_size=50)
|
||||||
|
self.assertEqual(1, len(enc_result))
|
||||||
|
self.assertIs(AttributeError, type(enc_result[0]))
|
||||||
session = db_api.get_session()
|
session = db_api.get_session()
|
||||||
enc_tmpls = session.query(models.RawTemplate).all()
|
enc_tmpls = session.query(models.RawTemplate).all()
|
||||||
self.assertEqual('', enc_tmpls[1].environment)
|
self.assertEqual('', enc_tmpls[1].environment)
|
||||||
|
@ -3161,10 +3163,85 @@ class DBAPICryptParamsPropsTest(common.HeatTestCase):
|
||||||
enc_tmpls[2].environment['parameters']['param2'][0])
|
enc_tmpls[2].environment['parameters']['param2'][0])
|
||||||
|
|
||||||
# Test decryption
|
# Test decryption
|
||||||
db_api.db_decrypt_parameters_and_properties(
|
dec_result = db_api.db_decrypt_parameters_and_properties(
|
||||||
self.ctx, cfg.CONF.auth_encryption_key, batch_size=50)
|
self.ctx, cfg.CONF.auth_encryption_key, batch_size=50)
|
||||||
|
self.assertEqual(len(dec_result), 1)
|
||||||
|
self.assertIs(TypeError, type(dec_result[0]))
|
||||||
session = db_api.get_session()
|
session = db_api.get_session()
|
||||||
dec_tmpls = session.query(models.RawTemplate).all()
|
dec_tmpls = session.query(models.RawTemplate).all()
|
||||||
self.assertEqual('', dec_tmpls[1].environment)
|
self.assertEqual('', dec_tmpls[1].environment)
|
||||||
self.assertEqual('bar',
|
self.assertEqual('bar',
|
||||||
dec_tmpls[2].environment['parameters']['param2'])
|
dec_tmpls[2].environment['parameters']['param2'])
|
||||||
|
|
||||||
|
def test_db_encrypt_no_env(self):
|
||||||
|
template = {
|
||||||
|
'template': self.t,
|
||||||
|
'files': {'foo': 'bar'},
|
||||||
|
'environment': None}
|
||||||
|
db_api.raw_template_create(self.ctx, template)
|
||||||
|
self.assertEqual([], db_api.db_encrypt_parameters_and_properties(
|
||||||
|
self.ctx, cfg.CONF.auth_encryption_key))
|
||||||
|
|
||||||
|
def test_db_encrypt_no_env_parameters(self):
|
||||||
|
template = {
|
||||||
|
'template': self.t,
|
||||||
|
'files': {'foo': 'bar'},
|
||||||
|
'environment': {'encrypted_param_names': ['a']}}
|
||||||
|
db_api.raw_template_create(self.ctx, template)
|
||||||
|
self.assertEqual([], db_api.db_encrypt_parameters_and_properties(
|
||||||
|
self.ctx, cfg.CONF.auth_encryption_key))
|
||||||
|
|
||||||
|
def test_db_encrypt_no_properties_data(self):
|
||||||
|
ctx = utils.dummy_context()
|
||||||
|
template = self._create_template()
|
||||||
|
user_creds = create_user_creds(ctx)
|
||||||
|
stack = create_stack(ctx, template, user_creds)
|
||||||
|
resources = [create_resource(ctx, stack, name='res1')]
|
||||||
|
resources[0].properties_data = None
|
||||||
|
self.assertEqual([], db_api.db_encrypt_parameters_and_properties(
|
||||||
|
ctx, cfg.CONF.auth_encryption_key))
|
||||||
|
|
||||||
|
def test_db_encrypt_non_string_param_type(self):
|
||||||
|
t = template_format.parse('''
|
||||||
|
heat_template_version: 2013-05-23
|
||||||
|
parameters:
|
||||||
|
param1:
|
||||||
|
type: string
|
||||||
|
description: value1.
|
||||||
|
param2:
|
||||||
|
type: string
|
||||||
|
description: value2.
|
||||||
|
hidden: true
|
||||||
|
param3:
|
||||||
|
type: string
|
||||||
|
description: value3
|
||||||
|
hidden: true
|
||||||
|
default: 1234
|
||||||
|
resources:
|
||||||
|
a_resource:
|
||||||
|
type: GenericResourceType
|
||||||
|
''')
|
||||||
|
template = {
|
||||||
|
'template': t,
|
||||||
|
'files': {},
|
||||||
|
'environment': {'parameters': {
|
||||||
|
'param1': 'foo',
|
||||||
|
'param2': 'bar',
|
||||||
|
'param3': 12345}}}
|
||||||
|
db_api.raw_template_create(self.ctx, template)
|
||||||
|
self.assertEqual([], db_api.db_encrypt_parameters_and_properties(
|
||||||
|
self.ctx, cfg.CONF.auth_encryption_key))
|
||||||
|
session = db_api.get_session()
|
||||||
|
enc_raw_templates = session.query(models.RawTemplate).all()
|
||||||
|
self.assertNotEqual([], enc_raw_templates)
|
||||||
|
enc_params = enc_raw_templates[1].environment['parameters']
|
||||||
|
|
||||||
|
self.assertEqual([], db_api.db_decrypt_parameters_and_properties(
|
||||||
|
self.ctx, cfg.CONF.auth_encryption_key, batch_size=50))
|
||||||
|
session = db_api.get_session()
|
||||||
|
dec_tmpls = session.query(models.RawTemplate).all()
|
||||||
|
dec_params = dec_tmpls[1].environment['parameters']
|
||||||
|
|
||||||
|
self.assertNotEqual(enc_params['param3'], dec_params['param3'])
|
||||||
|
self.assertEqual('bar', dec_params['param2'])
|
||||||
|
self.assertEqual('12345', dec_params['param3'])
|
||||||
|
|
Loading…
Reference in New Issue