Exemple #1
0
def test_global_passphrase_catalog(*_):
    _dir = tempfile.mkdtemp()
    os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True)
    PassphraseGenerator('cicd', _dir, 'test_author').generate()

    for passphrase in TEST_GLOBAL_PASSPHRASES_CATALOG['data']['passphrases']:
        passphrase_file_name = '{}.yaml'.format(passphrase['document_name'])
        passphrase_file_path = os.path.join(_dir, 'site', 'cicd', 'secrets',
                                            'passphrases',
                                            passphrase_file_name)
        assert os.path.isfile(passphrase_file_path)
        with open(passphrase_file_path) as stream:
            doc = yaml.safe_load(stream)
            assert doc['schema'] == 'pegleg/PeglegManagedDocument/v1'
            assert doc['metadata']['storagePolicy'] == 'cleartext'
            assert 'encrypted' in doc['data']
            assert doc['data']['encrypted']['by'] == 'test_author'
            assert 'generated' in doc['data']
            assert doc['data']['generated']['by'] == 'test_author'
            assert 'managedDocument' in doc['data']
            assert doc['data']['managedDocument']['metadata'][
                'storagePolicy'] == 'encrypted'
            decrypted_passphrase = encryption.decrypt(
                doc['data']['managedDocument']['data'],
                os.environ['PEGLEG_PASSPHRASE'].encode(),
                os.environ['PEGLEG_SALT'].encode())
            if passphrase_file_name == "passphrase_from_global.yaml":
                assert len(decrypted_passphrase) == 24
    def get_decrypted_secrets(self):
        """
        Unwrap and decrypt all the pegleg managed documents in a secrets
        file, and return the result as a list of documents.

        The method is idempotent. If the method is called on not
        encrypted files, or documents inside the file, it will return
        the original unwrapped and unencrypted documents.

        """

        doc_list = []
        for doc in self.documents:
            # do not decrypt already decrypted data
            if doc.is_encrypted():

                # Get appropriate encryption keys to use
                if doc.get_layer() == 'site':
                    passphrase = config.get_passphrase()
                    salt = config.get_salt()
                else:
                    passphrase = config.get_global_passphrase()
                    salt = config.get_global_salt()

                doc.set_secret(
                    decrypt(doc.get_secret(), passphrase, salt).decode())
                doc.set_decrypted()
            doc_list.append(doc.embedded_document)
        return doc_list
Exemple #3
0
def test_generate_passphrases_exception(capture):
    unenc_data = uuid.uuid4().bytes
    passphrase1 = uuid.uuid4().bytes
    passphrase2 = uuid.uuid4().bytes
    salt1 = uuid.uuid4().bytes
    salt2 = uuid.uuid4().bytes

    # Generate random data and encrypt it
    enc_data = encryption.encrypt(unenc_data, passphrase1, salt1)

    # Decrypt using the wrong key to see to see the InvalidToken error
    with pytest.raises(fernet.InvalidToken):
        encryption.decrypt(enc_data, passphrase2, salt2)
    capture.check(('pegleg.engine.util.encryption', 'ERROR',
                   ('Signature verification to decrypt secrets failed. '
                    'Please check your provided passphrase and salt and '
                    'try again.')))
Exemple #4
0
def test_encrypt_and_decrypt():
    data = test_utils.rand_name("this is an example of un-encrypted "
                                "data.", "pegleg").encode()
    passphrase = test_utils.rand_name("passphrase1", "pegleg").encode()
    salt = test_utils.rand_name("salt1", "pegleg").encode()
    enc1 = crypt.encrypt(data, passphrase, salt)
    dec1 = crypt.decrypt(enc1, passphrase, salt)
    assert data == dec1
    enc2 = crypt.encrypt(dec1, passphrase, salt)
    dec2 = crypt.decrypt(enc2, passphrase, salt)
    assert data == dec2
    passphrase2 = test_utils.rand_name("passphrase2", "pegleg").encode()
    salt2 = test_utils.rand_name("salt2", "pegleg").encode()
    enc3 = crypt.encrypt(dec2, passphrase2, salt2)
    dec3 = crypt.decrypt(enc3, passphrase2, salt2)
    assert data == dec3
    assert data != enc3
Exemple #5
0
def test_uuid_passphrase_catalog(*_):
    _dir = tempfile.mkdtemp()
    os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True)
    PassphraseGenerator('cicd', _dir, 'test_author').generate()

    for passphrase in TEST_TYPES_CATALOG['data']['passphrases']:
        passphrase_file_name = '{}.yaml'.format(passphrase['document_name'])
        passphrase_file_path = os.path.join(_dir, 'site', 'cicd', 'secrets',
                                            'passphrases',
                                            passphrase_file_name)
        assert os.path.isfile(passphrase_file_path)
        with open(passphrase_file_path) as stream:
            doc = yaml.safe_load(stream)
            decrypted_passphrase = encryption.decrypt(
                doc['data']['managedDocument']['data'],
                os.environ['PEGLEG_PASSPHRASE'].encode(),
                os.environ['PEGLEG_SALT'].encode())
            if passphrase_file_name == "uuid_passphrase_doc.yaml":
                assert uuid.UUID(decrypted_passphrase.decode()).version == 4
Exemple #6
0
def test_generate_passphrases_with_overidden_passphrase_catalog(*_):
    _dir = tempfile.mkdtemp()
    os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True)
    PassphraseGenerator('cicd', _dir, 'test_author',
                        [TEST_OVERRIDE_PASSPHRASES_CATALOG]).generate()

    passphrase_dir = os.path.join(_dir, 'site', 'cicd', 'secrets',
                                  'passphrases')
    assert 3 == len(os.listdir(passphrase_dir))

    for passphrase in TEST_OVERRIDE_PASSPHRASES_CATALOG['data']['passphrases']:
        passphrase_file_name = '{}.yaml'.format(passphrase['document_name'])
        passphrase_file_path = os.path.join(_dir, 'site', 'cicd', 'secrets',
                                            'passphrases',
                                            passphrase_file_name)
        assert os.path.isfile(passphrase_file_path)
        with open(passphrase_file_path) as stream:
            doc = yaml.safe_load(stream)
            assert doc['schema'] == 'pegleg/PeglegManagedDocument/v1'
            assert doc['metadata']['storagePolicy'] == 'cleartext'
            assert 'encrypted' in doc['data']
            assert doc['data']['encrypted']['by'] == 'test_author'
            assert 'generated' in doc['data']
            assert doc['data']['generated']['by'] == 'test_author'
            assert 'managedDocument' in doc['data']
            assert doc['data']['managedDocument']['metadata'][
                'storagePolicy'] == 'encrypted'
            decrypted_passphrase = encryption.decrypt(
                doc['data']['managedDocument']['data'],
                os.environ['PEGLEG_PASSPHRASE'].encode(),
                os.environ['PEGLEG_SALT'].encode())
            if passphrase_file_name == 'osh_placement_password.yaml':
                assert len(decrypted_passphrase) == 32
            elif passphrase_file_name == 'osh_cinder_password.yaml':
                assert len(decrypted_passphrase) == 25
            else:
                assert len(decrypted_passphrase) == 24
Exemple #7
0
def test_profiles_catalog(*_):
    _dir = tempfile.mkdtemp()
    os.makedirs(os.path.join(_dir, 'cicd_site_repo'), exist_ok=True)
    PassphraseGenerator('cicd', _dir, 'test_author').generate()
    s_util = CryptoString()

    for passphrase in TEST_PROFILES_CATALOG['data']['passphrases']:
        passphrase_file_name = '{}.yaml'.format(passphrase['document_name'])
        passphrase_file_path = os.path.join(_dir, 'site', 'cicd', 'secrets',
                                            'passphrases',
                                            passphrase_file_name)
        assert os.path.isfile(passphrase_file_path)
        with open(passphrase_file_path) as stream:
            doc = yaml.safe_load(stream)
            decrypted_passphrase = encryption.decrypt(
                doc['data']['managedDocument']['data'],
                os.environ['PEGLEG_PASSPHRASE'].encode(),
                os.environ['PEGLEG_SALT'].encode()).decode()
            assert len(decrypted_passphrase) == 24
            if passphrase_file_name == "default_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is True
                assert s_util.has_upper(decrypted_passphrase) is True
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is True
                bad_symbols = any(char in '!"$%()*,./:;<>[]^_`{|}~\''
                                  for char in decrypted_passphrase)
                assert not bad_symbols
            elif passphrase_file_name == "alphanumeric_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is True
                assert s_util.has_upper(decrypted_passphrase) is True
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is False
            elif passphrase_file_name == "alphanumeric_lower_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is True
                assert s_util.has_upper(decrypted_passphrase) is False
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is False
            elif passphrase_file_name == "alphanumeric_upper_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is False
                assert s_util.has_upper(decrypted_passphrase) is True
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is False
            elif passphrase_file_name == "all_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is True
                assert s_util.has_upper(decrypted_passphrase) is True
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is True
            elif passphrase_file_name == "hex_lower_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is True
                assert s_util.has_upper(decrypted_passphrase) is False
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is False
                bad_letters = any(char in 'ghijklmnopqrstuvwxyz'
                                  for char in decrypted_passphrase)
                assert not bad_letters
            elif passphrase_file_name == "hex_upper_passphrase.yaml":
                assert s_util.has_lower(decrypted_passphrase) is False
                assert s_util.has_upper(decrypted_passphrase) is True
                assert s_util.has_number(decrypted_passphrase) is True
                assert s_util.has_symbol(decrypted_passphrase) is False
                bad_letters = any(char in 'GHIJKLMNOPQRSTUVWXYZ'
                                  for char in decrypted_passphrase)
                assert not bad_letters
Exemple #8
0
def get_global_creds(site_name):
    """Determine which credentials to use for global secrets.

    If a user desires to encrypt site secrets with one set of credentials but
    global secrets with a different set of credentials (in the case of
    multiple sites) Pegleg needs a way to handle a two-step encryption or
    decryption chain. This is accomplished by storing global credentials at
    the site level and encrypting them with site credentials. Pegleg will
    attempt to find both the global_salt and global_passphrase, decrypt them
    then use these credentials for any global encrypt/decrypt operations.
    If both global_salt and global_passphrase are found return both.
    If only one global credential is found, raise an error with the assumption
    the user wishes to use global credentials but does not have both.
    If neither are found, return the site credentials with the assumption
    the user wishes to encrypt the global documents with the site credentials.

    :param str site_name: The target site
    :return: Either the global, or site level - passphrase and salt
    """

    config.set_passphrase()
    config.set_salt()
    global_passphrase = None
    global_salt = None
    docs = definition.documents_for_site(site_name)

    for doc in docs:
        if doc['schema'] == 'pegleg/PeglegManagedDocument/v1':
            try:
                name = doc['data']['managedDocument']['metadata']['name']
                schema = doc['data']['managedDocument']['schema']
                data = doc['data']['managedDocument']['data']
                if schema == 'deckhand/Passphrase/v1':
                    if name == 'global_passphrase':
                        global_passphrase = encryption.decrypt(
                            data, config.get_passphrase(), config.get_salt())
                    elif name == 'global_salt':
                        global_salt = encryption.decrypt(
                            data, config.get_passphrase(), config.get_salt())
            except KeyError:
                continue
        else:
            try:
                name = doc['metadata']['name']
                schema = doc['schema']
                data = doc['data']
                if name == 'global_passphrase':
                    global_passphrase = data.encode()
                elif name == 'global_salt':
                    global_salt = data.encode()
            except KeyError:
                continue
        # Break out of search if both passphrase and salt are found
        if global_passphrase and global_salt:
            return (global_passphrase, global_salt)

    # End of search, determine if we should use site keys or raise an error
    if global_passphrase or global_salt:
        raise exceptions.GlobalCredentialsNotFound()
    else:
        return (config.get_passphrase(), config.get_salt())