From 3695d8a7ad53fa8fe8922203f2bf19ee512aeeab Mon Sep 17 00:00:00 2001 From: alisa Date: Mon, 26 Feb 2018 21:10:48 +0100 Subject: [PATCH 01/10] integrities --- multivault/integrities/__init__.py | 4 ++++ multivault/integrities/check.py | 0 2 files changed, 4 insertions(+) create mode 100644 multivault/integrities/__init__.py create mode 100644 multivault/integrities/check.py diff --git a/multivault/integrities/__init__.py b/multivault/integrities/__init__.py new file mode 100644 index 0000000..82cd94e --- /dev/null +++ b/multivault/integrities/__init__.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python3 +''' + The integrities module of multivault +''' diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py new file mode 100644 index 0000000..e69de29 From 14d94863f48b08beae97c800f1f619f37330e282 Mon Sep 17 00:00:00 2001 From: alisa Date: Mon, 26 Feb 2018 21:12:39 +0100 Subject: [PATCH 02/10] changed to multivault --- multivault/__init__.py | 2 +- multivault/base/__init__.py | 2 +- multivault/integrities/check.py | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/multivault/__init__.py b/multivault/__init__.py index 2670090..933a6c7 100644 --- a/multivault/__init__.py +++ b/multivault/__init__.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 ''' - This is the ansible-multivault package + This is the multivault package ''' __version__ = "0.5.0.0" diff --git a/multivault/base/__init__.py b/multivault/base/__init__.py index ad561e7..efde4db 100644 --- a/multivault/base/__init__.py +++ b/multivault/base/__init__.py @@ -1,4 +1,4 @@ #!/usr/bin/env python3 ''' - The base module of ansible_multivault + The base module of multivault ''' diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index e69de29..9ac8d5c 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -0,0 +1 @@ +import gpg \ No newline at end of file From dc205cd043a05570f2436f5e2b3ac4a48a4a074f Mon Sep 17 00:00:00 2001 From: alisa Date: Mon, 12 Mar 2018 21:23:55 +0100 Subject: [PATCH 03/10] ADD read and parse function --- multivault/integrities/check.py | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index 9ac8d5c..59eab77 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -1 +1,22 @@ -import gpg \ No newline at end of file +import pgpy +from ansible.parsing.dataloader import DataLoader +from ansible.inventory.manager import InventoryManager + + +def read_message(file_to_read): + message = pgpy.PGPMessage.from_file(file_to_read) + #print (dir(message)) + dir(message) + print(message.encrypters) + +def parse_ansible(inventory_file): + + data_loader = DataLoader() + inventory = InventoryManager(loader = data_loader, + sources=[inventory_file]) + + print(inventory.get_groups_dict()['testgroup1']) + +if __name__ == '__main__': + read_message('/home/alisa/Downloads/test.pw.gpg') + parse_ansible('/home/alisa/Downloads/inventory_test') \ No newline at end of file From a46adca6b2143aeba38e649d685b7472776953f9 Mon Sep 17 00:00:00 2001 From: alisa Date: Thu, 22 Mar 2018 20:15:42 +0100 Subject: [PATCH 04/10] comment --- multivault/integrities/check.py | 1 - 1 file changed, 1 deletion(-) diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index 59eab77..789e9fa 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -5,7 +5,6 @@ def read_message(file_to_read): message = pgpy.PGPMessage.from_file(file_to_read) - #print (dir(message)) dir(message) print(message.encrypters) From 03a8c0e32bf24a43afab912f2a18c761952aa1be Mon Sep 17 00:00:00 2001 From: alisa Date: Thu, 22 Mar 2018 22:09:34 +0100 Subject: [PATCH 05/10] add smt --- multivault/integrities/check.py | 43 ++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 6 deletions(-) diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index 789e9fa..18b6e1f 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -2,20 +2,51 @@ from ansible.parsing.dataloader import DataLoader from ansible.inventory.manager import InventoryManager +import ansible.playbook.play as play +import yaml +from multivault.utilities import util_crypt + +INVENTORY_FILE = '/home/alisa/git/playbooks/inventory.ini' +IGNORED = ['ubuntu', 'debian', 'ubuntu_host', 'debian_host'] +INVENTORY = InventoryManager(loader=DataLoader(), + sources=[INVENTORY_FILE]) + def read_message(file_to_read): message = pgpy.PGPMessage.from_file(file_to_read) dir(message) print(message.encrypters) + + + +def parse_play(play_file): + + with open(play_file, mode = "r") as playbook: + playbook=yaml.load(playbook) + # print(playbook) + for task in playbook: + # print(task["hosts"]) + hosts=task['hosts'].lower().split(',') + hosts=[host.strip() for host in hosts] + div=set(hosts)-set(IGNORED) + div=list(div) + print(match(div)) +def match(groups): + hosts = [] + for group in groups : + if group.startswith('!'): + pass + else : + try: + hosts.append(INVENTORY.get_groups_dict()[group]) + except Exception: + pass -def parse_ansible(inventory_file): + return util_crypt.flatten(hosts) - data_loader = DataLoader() - inventory = InventoryManager(loader = data_loader, - sources=[inventory_file]) - print(inventory.get_groups_dict()['testgroup1']) + if __name__ == '__main__': read_message('/home/alisa/Downloads/test.pw.gpg') - parse_ansible('/home/alisa/Downloads/inventory_test') \ No newline at end of file + parse_play('/home/alisa/git/playbooks/all.yml') From a371736b812777fe93cc71d11e80f31c80fb657f Mon Sep 17 00:00:00 2001 From: Cellebyte Date: Sun, 13 May 2018 02:25:04 +0200 Subject: [PATCH 06/10] Added utitlities for the new check module and added the check moduel --- multivault/integrities/check.py | 233 +++++++++++++++++++++++------ multivault/utilities/util_check.py | 127 ++++++++++++++++ 2 files changed, 316 insertions(+), 44 deletions(-) create mode 100644 multivault/utilities/util_check.py diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index 18b6e1f..1cf93ab 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -1,52 +1,197 @@ -import pgpy -from ansible.parsing.dataloader import DataLoader -from ansible.inventory.manager import InventoryManager - -import ansible.playbook.play as play +import configparser import yaml +import os +from multivault.utilities import util_check from multivault.utilities import util_crypt +from multivault.utilities import util_ldap +from multivault.base import config +from multivault.base import crypter +from pprint import pprint +try: + from ansible.parsing.dataloader import DataLoader + from ansible.inventory.manager import InventoryManager + import ansible.playbook.play as play +except ImportError: + print("The integrity module relies on ansible!") + print("\tpip3 install ansible") + exit(1) + + +class bcolors: + HEADER = '\033[95m' + OKBLUE = '\033[94m' + OKGREEN = '\033[92m' + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = '\033[1m' + UNDERLINE = '\033[4m' + + +def get_all_users_and_subkeys(): + results = {} + users = util_ldap.get('users', data=['']) + if users: + authorized = crypter._map_sudoers_to_fingerprints(users) + else: + authorized = {} + for user, key in authorized: + if not isinstance(key, str): + results[user] = [] + for name, _ in dict(key.subkeys).items(): + results[user].append(name) + return results + -INVENTORY_FILE = '/home/alisa/git/playbooks/inventory.ini' -IGNORED = ['ubuntu', 'debian', 'ubuntu_host', 'debian_host'] -INVENTORY = InventoryManager(loader=DataLoader(), - sources=[INVENTORY_FILE]) - - -def read_message(file_to_read): - message = pgpy.PGPMessage.from_file(file_to_read) - dir(message) - print(message.encrypters) - - - -def parse_play(play_file): - - with open(play_file, mode = "r") as playbook: - playbook=yaml.load(playbook) - # print(playbook) - for task in playbook: - # print(task["hosts"]) - hosts=task['hosts'].lower().split(',') - hosts=[host.strip() for host in hosts] - div=set(hosts)-set(IGNORED) - div=list(div) - print(match(div)) -def match(groups): - hosts = [] - for group in groups : - if group.startswith('!'): - pass - else : - try: - hosts.append(INVENTORY.get_groups_dict()[group]) - except Exception: +def init(workdir='/home/cellebyte/git/selfnet/playbooks'): + workdir = os.path.join(workdir) + config = configparser.ConfigParser() + + ansible_cfg = os.path.join(workdir, 'ansible.cfg') + DEFAULT_INVENTORY = None + ROLES_PATH = None + USER_SUBKEYS = get_all_users_and_subkeys() + config.read(ansible_cfg) + for section in config: + for key_pair in config[section]: + if key_pair == 'inventory': + DEFAULT_INVENTORY = config[section][key_pair] + elif key_pair == 'roles_path': + ROLES_PATH = config[section][key_pair] + else: pass - - return util_crypt.flatten(hosts) - + if not DEFAULT_INVENTORY: + DEFAULT_INVENTORY = 'inventory.ini' + if not ROLES_PATH: + ROLES_PATH = './roles' + + inventory_file = os.path.join(workdir, DEFAULT_INVENTORY) + roles_path = os.path.join(workdir, ROLES_PATH) + INVENTORY = InventoryManager(loader=DataLoader(), + sources=[inventory_file]) + return workdir, INVENTORY, roles_path, USER_SUBKEYS + + +def checkout_information(MAPPING, DEPENDENCY_TREE, workdir=None, roles_path=None): + results = [] + for role, hosts in MAPPING.items(): + roles = DEPENDENCY_TREE[role] + [ roles.append(role) for role in roles if DEPENDENCY_TREE[role] and not role in roles] + gpg_path = os.path.join(workdir, roles_path, role, 'gpg') + if os.path.exists(gpg_path): + results.append(check_with_structure(role, hosts, gpg_path)) + for dep_role in roles: + gpg_path = os.path.join(workdir, roles_path, dep_role, 'gpg') + if os.path.exists(gpg_path): + results.append(check_with_structure(dep_role, hosts, gpg_path)) + return results + + +def check_with_structure(role, hosts, gpg_path): + results = {} + for path, _, files in os.walk(gpg_path): + for file in files: + file_path = os.path.join(path, file) + if file_path.endswith('.gpg'): + minified_path = util_check.remove_string( + gpg_path+os.sep, file_path) + splitted_path = minified_path.split(os.sep) + to_be_encrypted_for = [] + if len(splitted_path) > 1: + for host in splitted_path: + if host.endswith('.gpg') and os.path.isfile(file_path): + results[file_path] = to_be_encrypted_for + elif util_check.is_valid_hostname(host): + to_be_encrypted_for.append(host) + else: + print('Unknown') + else: + results[file_path] = hosts + return results + + +def get_encrypters_from_file(informations): + results = {} + for information in informations: + for path, _ in information.items(): + results[path] = list(util_check.read_message(path)) + return results + + +def get_encrypters_from_ldap(informations, USER_SUBKEYS): + results = {} + for information in informations: + for path, hosts in information.items(): + authorized = util_ldap.get_authorized( + [host.split('.')[0] for host in hosts]) + if not authorized: + authorized = {} + results[path] = [] + for user, _ in authorized: + for uid, keys in USER_SUBKEYS.items(): + if uid == user: + results[path].append({uid: keys}) + return results + + +def crossover(IS_ENCRYPTED_FOR, SHOULD_BE_ENCRYPTED_FOR, USER_SUBKEYS): + for path, user_keys in SHOULD_BE_ENCRYPTED_FOR.items(): + keys = list(IS_ENCRYPTED_FOR[path]) + for user_key in user_keys: + for user, ikeys in user_key.items(): + matched = False + for ikey in ikeys: + if ikey in keys: + matched = True + if not matched: + print( + bcolors.WARNING + 'WARNING\t:::\t{} not encrypted for {}'.format(path, user)) + else: + print( + bcolors.OKGREEN + 'OK\t:::\t{} correctly encrypted for {}'.format(path, user)) + for ikey in ikeys: + try: + keys.remove(ikey) + except ValueError: + pass + if len(keys) > 0: + for key in keys: + user = get_user(key, USER_SUBKEYS) + if not user: + print( + bcolors.WARNING + 'WARNING\t:::\t{} encrypted for unknown key {}'.format(path, key)) + else: + print( + bcolors.FAIL + 'ERROR\t:::\t{} encrypted for user {}, no longer assigned on this file.(please fix!)'.format(path, user)) + + pass + + +def get_user(key, USER_SUBKEYS): + for user, keys in USER_SUBKEYS.items(): + if key in keys: + return user + return None + +def check(workdir=None, playbook='all.yml'): + if not workdir: + workdir, INVENTORY, roles_path, USER_SUBKEYS = init() + else: + return "Not Implemented" + playbook_file = os.path.join(workdir, playbook) + mapping = util_check.parse_play(playbook_file, INVENTORY=INVENTORY) + MAPPING = util_check.look_for_dependencies(mapping, workdir, roles_path) + DEPENDENCY_TREE = util_check.build_dependency_tree(workdir, util_check.get_roles(workdir, roles_path=roles_path), roles_path=roles_path) + pprint(DEPENDENCY_TREE) + FILE_HOSTS = checkout_information( + MAPPING, DEPENDENCY_TREE, workdir=workdir, roles_path=roles_path) + IS_ENCRYPTED_FOR = get_encrypters_from_file(FILE_HOSTS) + SHOULD_BE_ENCRYPTED_FOR = get_encrypters_from_ldap( + FILE_HOSTS, USER_SUBKEYS) + crossover(IS_ENCRYPTED_FOR, SHOULD_BE_ENCRYPTED_FOR, USER_SUBKEYS) if __name__ == '__main__': - read_message('/home/alisa/Downloads/test.pw.gpg') - parse_play('/home/alisa/git/playbooks/all.yml') + config.load_config() + check() diff --git a/multivault/utilities/util_check.py b/multivault/utilities/util_check.py new file mode 100644 index 0000000..c5f2fb8 --- /dev/null +++ b/multivault/utilities/util_check.py @@ -0,0 +1,127 @@ +import re +import yaml +import os +import pgpy +from copy import deepcopy +from multivault.utilities import util_crypt + +IGNORED = ['ubuntu', 'debian', 'ubuntu_host', 'debian_host'] + +def is_valid_hostname(hostname): + if len(hostname) > 255: + return False + if hostname[-1] == ".": + hostname = hostname[:-1] # strip exactly one dot from the right, if present + allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(? 1: + hosts.append([group]) + return util_crypt.flatten(hosts) + + +def merge_hosts_to_roles(roles, MAPPING, hosts): + for role in roles: + if role in MAPPING.keys(): + for host in hosts: + if host not in MAPPING[role]: + MAPPING[role].append(host) + else: + MAPPING[role] = [] + for host in hosts: + if host not in MAPPING[role]: + MAPPING[role].append(host) + return MAPPING + +def read_message(file_to_read): + try: + message = pgpy.PGPMessage.from_file(file_to_read) + except ValueError: + try: + message = pgpy.PGPMessage.from_blob(file_to_read) + except ValueError: + print('Broken PGPMessage') + return {} + return(message.encrypters) + +def look_for_dependencies(mapping, workdir, roles_path="./roles"): + MAPPING = deepcopy(mapping) + for role, hosts in mapping.items(): + meta_path = os.path.join(workdir, roles_path, role, 'meta', 'main.yml') + roles = get_meta_info(meta_path) + MAPPING = merge_hosts_to_roles(roles, MAPPING, hosts) + if mapping == MAPPING: + return MAPPING + else: + return look_for_dependencies(MAPPING, workdir, roles_path=roles_path) + +def get_roles(workdir, roles_path="./roles"): + return [ role for role in os.listdir(os.path.join(workdir, roles_path)) if role ] + +def remove_string(gpg_path,path): + temp=0 + for i in range(0,len(gpg_path)): + if gpg_path[i] == path[i]: + temp = i + + return path[temp+1:] + +def get_meta_info(meta_path): + if os.path.exists(meta_path): + roles = [] + with open(meta_path, 'r') as meta: + meta_info = yaml.load(meta) + if 'dependencies' in meta_info.keys(): + try: + if isinstance(meta_info['dependencies'][0], dict): + roles = [dependency['role'] for dependency in meta_info['dependencies']] + elif isinstance(meta_info['dependencies'][0], str): + roles = meta_info['dependencies'] + except (IndexError, TypeError): + roles = [] + return list(set(roles)) + else: + return [] + +def build_dependency_tree(workdir, roles, roles_path="./roles"): + DEPENDENCY_TREE = {} + for role in roles: + meta_path = os.path.join(workdir,roles_path, role, 'meta', 'main.yml') + DEPENDENCY_TREE[role] = get_meta_info(meta_path) + return DEPENDENCY_TREE \ No newline at end of file From 85218d759aa74504315b957d54d3a8b02d52c152 Mon Sep 17 00:00:00 2001 From: Cellebyte Date: Sun, 13 May 2018 02:25:54 +0200 Subject: [PATCH 07/10] Fix an earlier behaviour --- multivault/utilities/util_ldap.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/multivault/utilities/util_ldap.py b/multivault/utilities/util_ldap.py index 8a08643..b83c355 100644 --- a/multivault/utilities/util_ldap.py +++ b/multivault/utilities/util_ldap.py @@ -129,11 +129,13 @@ def get_authorized(hostnames): ''' sudoers = get('hostnames', data=hostnames) masters = get('none') - if not sudoers or not masters: + if not masters and not sudoers: print("Sudoers:", sudoers) print("Masters:", masters) print("An error ocurred by getting the required ldap information!") - return None + return {} + if not sudoers: + return masters in_masters_but_not_in_sudoers = set(masters) - set(sudoers) authorized_list = list(sudoers) + list(in_masters_but_not_in_sudoers) return authorized_list From 6827c23310681e876df669327d84cca7c6bc3367 Mon Sep 17 00:00:00 2001 From: Cellebyte Date: Sun, 13 May 2018 16:07:04 +0200 Subject: [PATCH 08/10] added dependency match for meta.yml for one dependency stack --- multivault/integrities/check.py | 142 +++++++++++++++++++------------- 1 file changed, 86 insertions(+), 56 deletions(-) diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index 1cf93ab..86cf06e 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -1,6 +1,8 @@ import configparser import yaml import os +import copy +import json from multivault.utilities import util_check from multivault.utilities import util_crypt from multivault.utilities import util_ldap @@ -16,6 +18,8 @@ print("\tpip3 install ansible") exit(1) +INVENTORY = None + class bcolors: HEADER = '\033[95m' @@ -37,9 +41,11 @@ def get_all_users_and_subkeys(): authorized = {} for user, key in authorized: if not isinstance(key, str): - results[user] = [] + results[user] = {} + results[user]['key'] = key + results[user]['subkeys'] = [] for name, _ in dict(key.subkeys).items(): - results[user].append(name) + results[user]['subkeys'].append(name) return results @@ -51,6 +57,7 @@ def init(workdir='/home/cellebyte/git/selfnet/playbooks'): DEFAULT_INVENTORY = None ROLES_PATH = None USER_SUBKEYS = get_all_users_and_subkeys() + # USER_SUBKEYS = None config.read(ansible_cfg) for section in config: for key_pair in config[section]: @@ -75,20 +82,33 @@ def init(workdir='/home/cellebyte/git/selfnet/playbooks'): def checkout_information(MAPPING, DEPENDENCY_TREE, workdir=None, roles_path=None): results = [] for role, hosts in MAPPING.items(): - roles = DEPENDENCY_TREE[role] - [ roles.append(role) for role in roles if DEPENDENCY_TREE[role] and not role in roles] gpg_path = os.path.join(workdir, roles_path, role, 'gpg') if os.path.exists(gpg_path): results.append(check_with_structure(role, hosts, gpg_path)) - for dep_role in roles: - gpg_path = os.path.join(workdir, roles_path, dep_role, 'gpg') - if os.path.exists(gpg_path): - results.append(check_with_structure(dep_role, hosts, gpg_path)) + roles_with_gpg = [result['role'] for result in results] + for result in results: + role = result['role'] + hosts = result['hosts'] + dependency_roles = DEPENDENCY_TREE[role] + for dependency_role in dependency_roles: + if dependency_role in roles_with_gpg: + gpg_role = [result for result in results if result['role'] == dependency_role][0] + pprint(gpg_role) + for _, information in gpg_role['files'].items(): + for host in hosts: + if host not in information['hosts'] and hosts == information['hosts']: + information['hosts'].append(host) + pprint(role) + print('---------------------------') + pprint(gpg_role) return results def check_with_structure(role, hosts, gpg_path): results = {} + results['role'] = role + results['hosts'] = hosts + results['files'] = {} for path, _, files in os.walk(gpg_path): for file in files: file_path = os.path.join(path, file) @@ -97,74 +117,81 @@ def check_with_structure(role, hosts, gpg_path): gpg_path+os.sep, file_path) splitted_path = minified_path.split(os.sep) to_be_encrypted_for = [] + results['files'][file_path] = {} if len(splitted_path) > 1: for host in splitted_path: + # host is an encrypted file and not a host if host.endswith('.gpg') and os.path.isfile(file_path): - results[file_path] = to_be_encrypted_for - elif util_check.is_valid_hostname(host): + results['files'][file_path]['hosts'] = to_be_encrypted_for + elif util_check.is_valid_hostname(host) and host in util_check.match(['all'], INVENTORY): to_be_encrypted_for.append(host) else: - print('Unknown') + results['files'][file_path]['hosts'] = hosts + break else: - results[file_path] = hosts + results['files'][file_path]['hosts'] = hosts return results def get_encrypters_from_file(informations): - results = {} for information in informations: - for path, _ in information.items(): - results[path] = list(util_check.read_message(path)) - return results + for path, _ in information['files'].items(): + information['files'][path]['encrypters'] = list( + util_check.read_message(path)) + return informations def get_encrypters_from_ldap(informations, USER_SUBKEYS): - results = {} for information in informations: - for path, hosts in information.items(): + for path in information['files'].keys(): authorized = util_ldap.get_authorized( - [host.split('.')[0] for host in hosts]) + [host.split('.')[0] for host in information['files'][path]['hosts']]) if not authorized: authorized = {} - results[path] = [] + information['files'][path]['sudoers'] = [] for user, _ in authorized: for uid, keys in USER_SUBKEYS.items(): if uid == user: - results[path].append({uid: keys}) - return results + information['files'][path]['sudoers'].append( + {uid: keys}) + return informations -def crossover(IS_ENCRYPTED_FOR, SHOULD_BE_ENCRYPTED_FOR, USER_SUBKEYS): - for path, user_keys in SHOULD_BE_ENCRYPTED_FOR.items(): - keys = list(IS_ENCRYPTED_FOR[path]) - for user_key in user_keys: - for user, ikeys in user_key.items(): - matched = False - for ikey in ikeys: - if ikey in keys: - matched = True - if not matched: - print( - bcolors.WARNING + 'WARNING\t:::\t{} not encrypted for {}'.format(path, user)) - else: - print( - bcolors.OKGREEN + 'OK\t:::\t{} correctly encrypted for {}'.format(path, user)) - for ikey in ikeys: - try: - keys.remove(ikey) - except ValueError: - pass - if len(keys) > 0: - for key in keys: - user = get_user(key, USER_SUBKEYS) - if not user: - print( - bcolors.WARNING + 'WARNING\t:::\t{} encrypted for unknown key {}'.format(path, key)) - else: - print( - bcolors.FAIL + 'ERROR\t:::\t{} encrypted for user {}, no longer assigned on this file.(please fix!)'.format(path, user)) - - pass +def crossover(informations, USER_SUBKEYS): + for information in informations: + print(bcolors.OKBLUE + + 'INFO\t:::\tCheck Encryption for role >> {} <<'.format(information['role'])) + for path, file_information in information['files'].items(): + keys = list(copy.deepcopy(file_information['encrypters'])) + print(bcolors.OKBLUE + + '\tINFO\t:::\tCheck for hosts >> {} <<'.format(file_information['hosts'])) + filename = '.../' + str(path.split(os.sep)[-1]) + for sudoer in file_information['sudoers']: + for user, key_information in sudoer.items(): + matched = False + for sub_key in key_information['subkeys']: + if sub_key in keys: + matched = True + if not matched: + print( + bcolors.WARNING + '\tWARNING\t:::\t{} not encrypted for user >> {} <<'.format(filename, user)) + else: + print( + bcolors.OKGREEN + '\tOK\t:::\t{} correctly encrypted for user >> {} <<'.format(filename, user)) + for sub_key in key_information['subkeys']: + try: + keys.remove(sub_key) + except ValueError: + pass + if len(keys) > 0: + for key in keys: + user = get_user(key, USER_SUBKEYS) + if not user: + print( + bcolors.WARNING + '\tWARNING\t:::\t{} encrypted for unknown key >> {} <<'.format(filename, key)) + else: + print( + bcolors.FAIL + '\tERROR\t:::\t{} wrong encrypted for user >> {} <<(please fix!)'.format(filename, user)) def get_user(key, USER_SUBKEYS): @@ -175,21 +202,24 @@ def get_user(key, USER_SUBKEYS): def check(workdir=None, playbook='all.yml'): + global INVENTORY if not workdir: workdir, INVENTORY, roles_path, USER_SUBKEYS = init() else: return "Not Implemented" + # pprint(USER_SUBKEYS) playbook_file = os.path.join(workdir, playbook) mapping = util_check.parse_play(playbook_file, INVENTORY=INVENTORY) MAPPING = util_check.look_for_dependencies(mapping, workdir, roles_path) DEPENDENCY_TREE = util_check.build_dependency_tree(workdir, util_check.get_roles(workdir, roles_path=roles_path), roles_path=roles_path) pprint(DEPENDENCY_TREE) FILE_HOSTS = checkout_information( - MAPPING, DEPENDENCY_TREE, workdir=workdir, roles_path=roles_path) + MAPPING, DEPENDENCY_TREE, workdir=workdir, roles_path=roles_path) IS_ENCRYPTED_FOR = get_encrypters_from_file(FILE_HOSTS) SHOULD_BE_ENCRYPTED_FOR = get_encrypters_from_ldap( - FILE_HOSTS, USER_SUBKEYS) - crossover(IS_ENCRYPTED_FOR, SHOULD_BE_ENCRYPTED_FOR, USER_SUBKEYS) + IS_ENCRYPTED_FOR, USER_SUBKEYS) + # pprint(SHOULD_BE_ENCRYPTED_FOR) + crossover(SHOULD_BE_ENCRYPTED_FOR, USER_SUBKEYS) if __name__ == '__main__': From c47c72a25d0decf1b9182505a1676dadfef7e333 Mon Sep 17 00:00:00 2001 From: Cellebyte Date: Tue, 18 Sep 2018 19:29:48 +0200 Subject: [PATCH 09/10] Updated check module --- multivault/integrities/check.py | 39 +++++++------ multivault/utilities/util_check.py | 86 +++++++++++++++++------------ multivault/utilities/util_crypt.py | 6 +- multivault/utilities/util_filter.py | 5 ++ multivault/utilities/util_ssh.py | 5 +- 5 files changed, 87 insertions(+), 54 deletions(-) diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index 86cf06e..fe6a2a8 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -6,7 +6,7 @@ from multivault.utilities import util_check from multivault.utilities import util_crypt from multivault.utilities import util_ldap -from multivault.base import config +from multivault.base.config import config from multivault.base import crypter from pprint import pprint try: @@ -34,7 +34,7 @@ class bcolors: def get_all_users_and_subkeys(): results = {} - users = util_ldap.get('users', data=['']) + users = util_ldap.get('users', data='all') if users: authorized = crypter._map_sudoers_to_fingerprints(users) else: @@ -44,27 +44,27 @@ def get_all_users_and_subkeys(): results[user] = {} results[user]['key'] = key results[user]['subkeys'] = [] - for name, _ in dict(key.subkeys).items(): - results[user]['subkeys'].append(name) + for subkey in key.subkeys: + results[user]['subkeys'].append(subkey.keyid) return results def init(workdir='/home/cellebyte/git/selfnet/playbooks'): workdir = os.path.join(workdir) - config = configparser.ConfigParser() + ansible_config = configparser.ConfigParser() ansible_cfg = os.path.join(workdir, 'ansible.cfg') DEFAULT_INVENTORY = None ROLES_PATH = None USER_SUBKEYS = get_all_users_and_subkeys() # USER_SUBKEYS = None - config.read(ansible_cfg) - for section in config: - for key_pair in config[section]: + ansible_config.read(ansible_cfg) + for section in ansible_config: + for key_pair in ansible_config[section]: if key_pair == 'inventory': - DEFAULT_INVENTORY = config[section][key_pair] + DEFAULT_INVENTORY = ansible_config[section][key_pair] elif key_pair == 'roles_path': - ROLES_PATH = config[section][key_pair] + ROLES_PATH = ansible_config[section][key_pair] else: pass if not DEFAULT_INVENTORY: @@ -92,7 +92,8 @@ def checkout_information(MAPPING, DEPENDENCY_TREE, workdir=None, roles_path=None dependency_roles = DEPENDENCY_TREE[role] for dependency_role in dependency_roles: if dependency_role in roles_with_gpg: - gpg_role = [result for result in results if result['role'] == dependency_role][0] + gpg_role = [ + result for result in results if result['role'] == dependency_role][0] pprint(gpg_role) for _, information in gpg_role['files'].items(): for host in hosts: @@ -144,8 +145,9 @@ def get_encrypters_from_file(informations): def get_encrypters_from_ldap(informations, USER_SUBKEYS): for information in informations: for path in information['files'].keys(): - authorized = util_ldap.get_authorized( - [host.split('.')[0] for host in information['files'][path]['hosts']]) + hosts = [host.split('.')[0] + for host in information['files'][path]['hosts']] + authorized = util_ldap.get_authorized(hosts) if not authorized: authorized = {} information['files'][path]['sudoers'] = [] @@ -211,10 +213,11 @@ def check(workdir=None, playbook='all.yml'): playbook_file = os.path.join(workdir, playbook) mapping = util_check.parse_play(playbook_file, INVENTORY=INVENTORY) MAPPING = util_check.look_for_dependencies(mapping, workdir, roles_path) - DEPENDENCY_TREE = util_check.build_dependency_tree(workdir, util_check.get_roles(workdir, roles_path=roles_path), roles_path=roles_path) - pprint(DEPENDENCY_TREE) + DEPENDENCY_TREE = util_check.build_dependency_tree(workdir, util_check.get_roles( + workdir, roles_path=roles_path), roles_path=roles_path) + # pprint(DEPENDENCY_TREE) FILE_HOSTS = checkout_information( - MAPPING, DEPENDENCY_TREE, workdir=workdir, roles_path=roles_path) + MAPPING, DEPENDENCY_TREE, workdir=workdir, roles_path=roles_path) IS_ENCRYPTED_FOR = get_encrypters_from_file(FILE_HOSTS) SHOULD_BE_ENCRYPTED_FOR = get_encrypters_from_ldap( IS_ENCRYPTED_FOR, USER_SUBKEYS) @@ -222,6 +225,8 @@ def check(workdir=None, playbook='all.yml'): crossover(SHOULD_BE_ENCRYPTED_FOR, USER_SUBKEYS) +get_all_users_and_subkeys + if __name__ == '__main__': - config.load_config() + check() diff --git a/multivault/utilities/util_check.py b/multivault/utilities/util_check.py index c5f2fb8..15b00ad 100644 --- a/multivault/utilities/util_check.py +++ b/multivault/utilities/util_check.py @@ -1,20 +1,27 @@ import re import yaml import os -import pgpy +import sys +from subprocess import check_output, CalledProcessError from copy import deepcopy from multivault.utilities import util_crypt +from multivault.base.config import config IGNORED = ['ubuntu', 'debian', 'ubuntu_host', 'debian_host'] +encrypter = re.compile(r"^:pubkey.*keyid (?P.*?)$", re.MULTILINE) +allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(? 255: return False if hostname[-1] == ".": - hostname = hostname[:-1] # strip exactly one dot from the right, if present - allowed = re.compile(r"(?!-)[A-Z\d-]{1,63}(? Date: Tue, 18 Sep 2018 19:44:41 +0200 Subject: [PATCH 10/10] Fixed issues --- multivault/integrities/check.py | 1 + multivault/utilities/util_crypt.py | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/multivault/integrities/check.py b/multivault/integrities/check.py index fe6a2a8..40b73d4 100644 --- a/multivault/integrities/check.py +++ b/multivault/integrities/check.py @@ -137,6 +137,7 @@ def check_with_structure(role, hosts, gpg_path): def get_encrypters_from_file(informations): for information in informations: for path, _ in information['files'].items(): + print("Analyzing File: {}".format(path)) information['files'][path]['encrypters'] = list( util_check.read_message(path)) return informations diff --git a/multivault/utilities/util_crypt.py b/multivault/utilities/util_crypt.py index 1463253..a14ff32 100644 --- a/multivault/utilities/util_crypt.py +++ b/multivault/utilities/util_crypt.py @@ -17,7 +17,6 @@ trust-model tofu+pgp tofu-default-policy unknown enable-dsa2 -enable-large-rsa cert-digest-algo SHA512 default-preference-list {0} {1} {2} {3} {4} {5} personal-cipher-preferences {0} {1} {2} {3}