Merge "Set salt when generating genesis bundle"

This commit is contained in:
Zuul 2019-03-25 16:16:57 +00:00 committed by Gerrit Code Review
commit bc0e420bc4
9 changed files with 82 additions and 37 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

@ -434,26 +434,15 @@ def generate_pki(site_name, author):
'to genesis.sh script.') 'to genesis.sh script.')
@SITE_REPOSITORY_ARGUMENT @SITE_REPOSITORY_ARGUMENT
def genesis_bundle(*, build_dir, validators, site_name): def genesis_bundle(*, build_dir, validators, site_name):
prom_encryption_key = os.environ.get("PROMENADE_ENCRYPTION_KEY") passphrase = os.environ.get("PEGLEG_PASSPHRASE")
peg_encryption_key = os.environ.get("PEGLEG_PASSPHRASE") salt = os.environ.get("PEGLEG_SALT")
encryption_key = None encryption_key = passphrase
if (prom_encryption_key and len(prom_encryption_key) > 24 and if passphrase:
peg_encryption_key and len(peg_encryption_key) > 24): passphrase = passphrase.encode()
click.echo("WARNING: PROMENADE_ENCRYPTION_KEY is deprecated, " if salt:
"using PEGLEG_PASSPHRASE instead", err=True) salt = salt.encode()
config.set_passphrase(peg_encryption_key) config.set_passphrase(passphrase)
encryption_key = peg_encryption_key config.set_salt(salt)
elif prom_encryption_key and len(prom_encryption_key) > 24:
click.echo("ERROR: PROMENADE_ENCRYPTION_KEY is deprecated, "
"use PEGLEG_PASSPHRASE instead", err=True)
raise click.ClickException("ERROR: PEGLEG_PASSPHRASE must be set "
"and at least 24 characters long.")
elif peg_encryption_key and len(peg_encryption_key) > 24:
config.set_passphrase(peg_encryption_key)
encryption_key = peg_encryption_key
else:
raise click.ClickException("ERROR: PEGLEG_PASSPHRASE must be set "
"and at least 24 characters long.")
PeglegSecretManagement.check_environment() PeglegSecretManagement.check_environment()
bundle.build_genesis(build_dir, bundle.build_genesis(build_dir,

View File

@ -16,6 +16,8 @@
# context passing but will require a somewhat heavy code refactor. See: # context passing but will require a somewhat heavy code refactor. See:
# http://click.pocoo.org/5/commands/#nested-handling-and-contexts # http://click.pocoo.org/5/commands/#nested-handling-and-contexts
from pegleg.engine import exceptions
try: try:
if GLOBAL_CONTEXT: if GLOBAL_CONTEXT:
pass pass
@ -28,7 +30,9 @@ except NameError:
'site_rev': None, 'site_rev': None,
'type_path': 'type', 'type_path': 'type',
'passphrase': None, 'passphrase': None,
'salt': None 'salt': None,
'salt_min_length': 24,
'passphrase_min_length': 24
} }
@ -151,9 +155,15 @@ def set_rel_type_path(p):
GLOBAL_CONTEXT['type_path'] = p GLOBAL_CONTEXT['type_path'] = p
def set_passphrase(p): def set_passphrase(passphrase):
"""Set the passphrase for encryption and decryption.""" """Set the passphrase for encryption and decryption."""
GLOBAL_CONTEXT['passphrase'] = p
if not passphrase:
raise exceptions.PassphraseNotFoundException()
elif len(passphrase) < GLOBAL_CONTEXT['passphrase_min_length']:
raise exceptions.PassphraseInsufficientLengthException()
GLOBAL_CONTEXT['passphrase'] = passphrase
def get_passphrase(): def get_passphrase():
@ -161,9 +171,15 @@ def get_passphrase():
return GLOBAL_CONTEXT['passphrase'] return GLOBAL_CONTEXT['passphrase']
def set_salt(p): def set_salt(salt):
"""Set the salt for encryption and decryption.""" """Set the salt for encryption and decryption."""
GLOBAL_CONTEXT['salt'] = p
if not salt:
raise exceptions.SaltNotFoundException()
elif len(salt) < GLOBAL_CONTEXT['salt_min_length']:
raise exceptions.SaltInsufficientLengthException()
GLOBAL_CONTEXT['salt'] = salt
def get_salt(): def get_salt():

View File

@ -102,3 +102,31 @@ class GenesisBundleGenerateException(PeglegBaseException):
""" """
message = 'Bundle generation failed on deckhand validation.' message = 'Bundle generation failed on deckhand validation.'
#
# CREDENTIALS EXCEPTIONS
#
class PassphraseNotFoundException(PeglegBaseException):
"""Exception raised when passphrase is not set."""
message = 'PEGLEG_PASSPHRASE must be set'
class PassphraseInsufficientLengthException(PeglegBaseException):
"""Exception raised when passphrase is too short."""
message = 'PEGLEG_PASSPHRASE must be at least 24 characters long.'
class SaltNotFoundException(PeglegBaseException):
"""Exception raised when salt is not set."""
message = 'PEGLEG_SALT must be set'
class SaltInsufficientLengthException(PeglegBaseException):
"""Exception raised when salt is too short."""
message = 'PEGLEG_SALT must be at least 24 characters long.'

View File

@ -91,7 +91,7 @@ data: ABAgagajajkb839215387
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_no_encryption_key(temp_path): def test_no_encryption_key(temp_path):
# Write the test data to temp file # Write the test data to temp file
@ -119,7 +119,7 @@ def test_no_encryption_key(temp_path):
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_failed_deckhand_validation(temp_path): def test_failed_deckhand_validation(temp_path):
# Write the test data to temp file # Write the test data to temp file

View File

@ -166,7 +166,7 @@ def test_cryptostring_long_len():
'cicd_site_repo/site/cicd/passphrases/passphrase-catalog.yaml', ]) 'cicd_site_repo/site/cicd/passphrases/passphrase-catalog.yaml', ])
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt'}) ENV_SALT: 'MySecretSalt1234567890]['})
def test_generate_passphrases(*_): def test_generate_passphrases(*_):
_dir = tempfile.mkdtemp() _dir = tempfile.mkdtemp()
os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True) os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True)
@ -239,7 +239,7 @@ def test_generate_passphrases_exception(capture):
'cicd_global_repo/site/cicd/passphrases/passphrase-catalog.yaml', ]) 'cicd_global_repo/site/cicd/passphrases/passphrase-catalog.yaml', ])
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt'}) ENV_SALT: 'MySecretSalt1234567890]['})
def test_global_passphrase_catalog(*_): def test_global_passphrase_catalog(*_):
_dir = tempfile.mkdtemp() _dir = tempfile.mkdtemp()
os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True) os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True)

View File

@ -74,7 +74,7 @@ def test_encrypt_and_decrypt():
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'aShortPassphrase', ENV_PASSPHRASE: 'aShortPassphrase',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_short_passphrase(): def test_short_passphrase():
with pytest.raises(click.ClickException, with pytest.raises(click.ClickException,
@ -84,7 +84,7 @@ def test_short_passphrase():
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt'}) ENV_SALT: 'MySecretSalt1234567890]['})
def test_secret_encrypt_and_decrypt(create_tmp_deployment_files, tmpdir): def test_secret_encrypt_and_decrypt(create_tmp_deployment_files, tmpdir):
site_dir = tmpdir.join("deployment_files", "site", "cicd") site_dir = tmpdir.join("deployment_files", "site", "cicd")
passphrase_doc = """--- passphrase_doc = """---
@ -160,7 +160,7 @@ def test_pegleg_secret_management_constructor_with_invalid_arguments():
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_encrypt_decrypt_using_file_path(temp_path): def test_encrypt_decrypt_using_file_path(temp_path):
# write the test data to temp file # write the test data to temp file
@ -190,7 +190,7 @@ def test_encrypt_decrypt_using_file_path(temp_path):
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_encrypt_decrypt_using_docs(temp_path): def test_encrypt_decrypt_using_docs(temp_path):
# write the test data to temp file # write the test data to temp file
@ -226,7 +226,7 @@ def test_encrypt_decrypt_using_docs(temp_path):
reason='cfssl must be installed to execute these tests') reason='cfssl must be installed to execute these tests')
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_generate_pki_using_local_repo_path(create_tmp_deployment_files): def test_generate_pki_using_local_repo_path(create_tmp_deployment_files):
"""Validates ``generate-pki`` action using local repo path.""" """Validates ``generate-pki`` action using local repo path."""
@ -252,7 +252,7 @@ def test_generate_pki_using_local_repo_path(create_tmp_deployment_files):
reason='cfssl must be installed to execute these tests') reason='cfssl must be installed to execute these tests')
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC', ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt' ENV_SALT: 'MySecretSalt1234567890]['
}) })
def test_check_expiry(create_tmp_deployment_files): def test_check_expiry(create_tmp_deployment_files):
""" Validates check_expiry """ """ Validates check_expiry """

View File

@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import os
import json import json
import mock import mock
import pytest import pytest
@ -20,6 +22,8 @@ from tests.unit import test_utils
from mock import ANY from mock import ANY
from pegleg.engine import util from pegleg.engine import util
from pegleg.engine.util.pegleg_secret_management import ENV_PASSPHRASE
from pegleg.engine.util.pegleg_secret_management import ENV_SALT
from pegleg.engine.util.shipyard_helper import ShipyardHelper from pegleg.engine.util.shipyard_helper import ShipyardHelper
from pegleg.engine.util.shipyard_helper import ShipyardClient from pegleg.engine.util.shipyard_helper import ShipyardClient
@ -102,6 +106,10 @@ def test_shipyard_helper_init_():
return_value=DATA) return_value=DATA)
@mock.patch.object(ShipyardHelper, 'formatted_response_handler', @mock.patch.object(ShipyardHelper, 'formatted_response_handler',
autospec=True, return_value=None) autospec=True, return_value=None)
@mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt1234567890]['
})
def test_upload_documents(*args): def test_upload_documents(*args):
""" Tests upload document """ """ Tests upload document """
# Scenario: # Scenario:
@ -128,6 +136,10 @@ def test_upload_documents(*args):
return_value=DATA) return_value=DATA)
@mock.patch.object(ShipyardHelper, 'formatted_response_handler', @mock.patch.object(ShipyardHelper, 'formatted_response_handler',
autospec=True, return_value=None) autospec=True, return_value=None)
@mock.patch.dict(os.environ, {
ENV_PASSPHRASE: 'ytrr89erARAiPE34692iwUMvWqqBvC',
ENV_SALT: 'MySecretSalt1234567890]['
})
def test_upload_documents_fail(*args): def test_upload_documents_fail(*args):
""" Tests Document upload error """ """ Tests Document upload error """
# Scenario: # Scenario:

View File

@ -459,7 +459,7 @@ class TestSiteSecretsActions(BaseCLIActionTest):
super(TestSiteSecretsActions, cls).setup_class() super(TestSiteSecretsActions, cls).setup_class()
cls.runner = CliRunner(env={ cls.runner = CliRunner(env={
"PEGLEG_PASSPHRASE": 'ytrr89erARAiPE34692iwUMvWqqBvC', "PEGLEG_PASSPHRASE": 'ytrr89erARAiPE34692iwUMvWqqBvC',
"PEGLEG_SALT": "MySecretSalt" "PEGLEG_SALT": "MySecretSalt1234567890]["
}) })
def _validate_generate_pki_action(self, result): def _validate_generate_pki_action(self, result):
@ -514,7 +514,7 @@ class TestSiteSecretsActions(BaseCLIActionTest):
reason='cfssl must be installed to execute these tests') reason='cfssl must be installed to execute these tests')
@mock.patch.dict(os.environ, { @mock.patch.dict(os.environ, {
"PEGLEG_PASSPHRASE": "123456789012345678901234567890", "PEGLEG_PASSPHRASE": "123456789012345678901234567890",
"PEGLEG_SALT": "123456" "PEGLEG_SALT": "MySecretSalt1234567890]["
}) })
def test_site_secrets_encrypt_and_decrypt_local_repo_path(self): def test_site_secrets_encrypt_and_decrypt_local_repo_path(self):
"""Validates ``generate-pki`` action using local repo path.""" """Validates ``generate-pki`` action using local repo path."""