def vault_encrypt(plaintext, secret): """ Vault encrypt a piece of data. """ try: vault = VaultLib() secret_file = get_file_vault_secret(filename=secret, loader=DataLoader()) secret_file.load() vault.secrets = [('default', secret_file)] return vault.encrypt(plaintext) except AnsibleError as exc: LOGGER.critical('Cannot encrypt string: %s', exc) sys.exit(1)
def test_file(self): password = '******' tmp_file = tempfile.NamedTemporaryFile(delete=False) tmp_file.write(to_bytes(password)) tmp_file.close() fake_loader = DictDataLoader({tmp_file.name: 'sdfadf'}) secret = vault.get_file_vault_secret(filename=tmp_file.name, loader=fake_loader) secret.load() os.unlink(tmp_file.name) self.assertEqual(secret.bytes, to_bytes(password))
def vault_encrypt(plaintext, secret): ''' Vault encrypt a piece of data. ''' try: vault = VaultLib() secret_file = get_file_vault_secret(filename=secret, loader=DataLoader()) secret_file.load() vault.secrets = [('default', secret_file)] return vault.encrypt(plaintext) except AnsibleError as e: logger.critical(f"Cannot encrypt string: {e}") sys.exit(1)
def vault_encrypt(plaintext, secret): """ Vault encrypt a piece of data. """ try: vault = VaultLib() secret_file = get_file_vault_secret(filename=secret, loader=DataLoader()) secret_file.load() vault.secrets = [("default", secret_file)] return vault.encrypt(plaintext) except AnsibleError as e: logger.critical("Cannot encrypt string: {}".format(e)) sys.exit(1)
def test_file(self): password = '******' tmp_file = tempfile.NamedTemporaryFile(delete=False) tmp_file.write(to_bytes(password)) tmp_file.close() fake_loader = DictDataLoader({tmp_file.name: 'sdfadf'}) secret = vault.get_file_vault_secret(filename=tmp_file.name, loader=fake_loader) secret.load() os.unlink(tmp_file.name) self.assertEqual(secret.bytes, to_bytes(password))
def decrypt(secrets_file_path, decrypted_file_path): try: vault_password_file = os.environ["ANSIBLE_VAULT_PASSWORD_FILE"] except KeyError: sys.exit(3) with open(vault_password_file, 'r') as vpf: vault_password = vpf.read().replace('\n', '') # Load vault password and prepare secrets for decryption loader = DataLoader() secret = vault.get_file_vault_secret(filename=vault_password_file, loader=loader) secret.load() vault_secrets = [('default', secret)] _vault = vault.VaultLib(vault_secrets) # Load encrypted yml for processing with codecs.open(secrets_file_path, 'r', encoding='utf-8') as f: loaded_yaml = AnsibleLoader(f, vault_secrets=_vault.secrets).get_single_data() # Define decrypted file params flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY) mode = stat.S_IRUSR | stat.S_IWUSR # 0o600 in octal umask = os.umask(0) # Save current umask to prevent downgrading to 0 # Delete and replace decrypted secrets to ensure file permissions try: os.remove(decrypted_file_path) except OSError: pass # Open the file descriptor umask_original = os.umask(umask) try: decrypted_file_fd = os.open(decrypted_file_path, flags, mode) finally: os.umask(umask_original) # Open file handle and write the decrypted file decrypted_file_out = os.fdopen(decrypted_file_fd, 'w') for k, v in loaded_yaml.items(): line = "export " + str(k) + "=" + str(v) + "\n" decrypted_file_out.write(line) decrypted_file_out.close() print("secrets decrypted")
def load_yaml(yaml_file, vault_secret=None): """ Load a YAML file into a python dictionary. The YAML file can be fully encrypted by Ansible-Vault or can contain multiple inline Ansible-Vault encrypted values. Ansible Vault encryption is ideal to store passwords or encrypt the entire file with sensitive data if required. """ vault = VaultLib() if vault_secret: secret_file = get_file_vault_secret(filename=vault_secret, loader=DataLoader()) secret_file.load() vault.secrets = [('default', secret_file)] data = None if os.path.isfile(yaml_file): with open(yaml_file, 'r') as stream: # Render environment variables using jinja templates contents = stream.read() template = Template(contents) stream = StringIO(template.render(env_var=os.environ)) try: if is_encrypted_file(stream): file_data = stream.read() data = yaml.load(vault.decrypt(file_data, None)) else: loader = AnsibleLoader(stream, None, vault.secrets) try: data = loader.get_single_data() except Exception as exc: raise Exception( f'Error when loading YAML config at {yaml_file} {exc}' ) finally: loader.dispose() except yaml.YAMLError as exc: raise Exception( f'Error when loading YAML config at {yaml_file} {exc}') else: LOGGER.debug('No file at %s', yaml_file) return data
def _load_file_vault_secrets(self, password_file_path=None): if password_file_path is None: password_file_path = self._config.get_config_value( "DEFAULT_VAULT_PASSWORD_FILE") password_file = Path(password_file_path) if password_file.name in self._file_vault_secrets: return if not password_file.is_file(): raise FileNotFoundError(password_file) self._file_vault_secrets[password_file.name] = get_file_vault_secret( filename=password_file, loader=self._loader) self._file_vault_secrets[password_file.name].load() self._loader.set_vault_secrets([ (password_file.name, self._file_vault_secrets[password_file.name]) ])
def load_yaml(yaml_file, vault_secret=None): ''' Load a YAML file into a python dictionary. The YAML file can be fully encrypted by Ansible-Vault or can contain multiple inline Ansible-Vault encrypted values. Ansible Vault encryption is ideal to store passwords or encrypt the entire file with sensitive data if required. ''' vault = VaultLib() if vault_secret: secret_file = get_file_vault_secret(filename=vault_secret, loader=DataLoader()) secret_file.load() vault.secrets = [('default', secret_file)] data = None if os.path.isfile(yaml_file): with open(yaml_file, 'r') as stream: try: if is_encrypted_file(stream): file_data = stream.read() data = yaml.load(vault.decrypt(file_data, None)) else: loader = AnsibleLoader(stream, None, vault.secrets) try: data = loader.get_single_data() except Exception as exc: raise Exception( "Error when loading YAML config at {} {}".format( yaml_file, exc)) finally: loader.dispose() except yaml.YAMLError as exc: raise Exception( "Error when loading YAML config at {} {}".format( yaml_file, exc)) else: logger.debug("No file at {}".format(yaml_file)) return data
def __init__( self, ansibleinventory, ansible_vault_password_file, moleculeenv): # Leverage the ansible python api # to run a playbook against a molecule host. # # see: ansible python api # https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html self._moleculeenv = moleculeenv context.CLIARGS = ImmutableDict( connection='local', module_path=[''], forks=10, become=None, become_method=None, become_user=None, check=False, diff=False) loader = DataLoader() # Load ansible vault secrets if environment variable is set if ansible_vault_password_file: vault_id_name = 'default' file_vault_secret = get_file_vault_secret( filename=ansible_vault_password_file, vault_id=vault_id_name, loader=loader) file_vault_secret.load() loader.set_vault_secrets( [(ansible_vault_password_file, file_vault_secret)]) self._loader = loader self._inventory = ansibleinventory self._variable_manager = VariableManager( loader=loader, inventory=ansibleinventory)
def main(): vault_file = '~/.vaultpass' in_file = "variables.yml" target_env = 'test' external_system_name = 'blabla' external_system_password = '******' # Load vault password and prepare secrets for decryption loader = DataLoader() secret = vault.get_file_vault_secret(filename=vault_file, loader=loader) secret.load() vault_secrets = [('default', secret)] _vault = vault.VaultLib(vault_secrets) # Load encrypted yml for processing with codecs.open(in_file, 'r', encoding='utf-8') as f: loaded_yaml = AnsibleLoader( f, vault_secrets=_vault.secrets).get_single_data() # Modify yml with new encrypted values new_encrypted_variable = objects.AnsibleVaultEncryptedUnicode.from_plaintext( external_system_password, _vault, vault_secrets[0][1]) loaded_yaml[target_env]['credentials'][external_system_name][ 'password'] = new_encrypted_variable # Write a new encrypted yml with open('new_variables.yml', 'w') as fd: yaml.dump(loaded_yaml, fd, Dumper=AnsibleDumper, encoding=None, default_flow_style=False) print(loaded_yaml)
def setup_vault_secrets(loader, vault_ids, vault_password_files=None, ask_vault_pass=None, create_new_password=False, auto_prompt=True): # list of tuples vault_secrets = [] # Depending on the vault_id value (including how --ask-vault-pass / --vault-password-file create a vault_id) # we need to show different prompts. This is for compat with older Towers that expect a # certain vault password prompt format, so 'promp_ask_vault_pass' vault_id gets the old format. prompt_formats = {} # If there are configured default vault identities, they are considered 'first' # so we prepend them to vault_ids (from cli) here vault_password_files = vault_password_files or [] if C.DEFAULT_VAULT_PASSWORD_FILE: vault_password_files.append(C.DEFAULT_VAULT_PASSWORD_FILE) if create_new_password: prompt_formats['prompt'] = [ 'New vault password (%(vault_id)s): ', 'Confirm vew vault password (%(vault_id)s): ' ] # 2.3 format prompts for --ask-vault-pass prompt_formats['prompt_ask_vault_pass'] = [ 'New Vault password: '******'Confirm New Vault password: '******'prompt'] = ['Vault password (%(vault_id)s): '] # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$' prompt_formats['prompt_ask_vault_pass'] = ['Vault password: '******'prompt', 'prompt_ask_vault_pass']: # prompts cant/shouldnt work without a tty, so dont add prompt secrets if not sys.stdin.isatty(): continue # --vault-id some_name@prompt_ask_vault_pass --vault-id other_name@prompt_ask_vault_pass will be a little # confusing since it will use the old format without the vault id in the prompt built_vault_id = vault_id_name or C.DEFAULT_VAULT_IDENTITY # choose the prompt based on --vault-id=prompt or --ask-vault-pass. --ask-vault-pass # always gets the old format for Tower compatibility. # ie, we used --ask-vault-pass, so we need to use the old vault password prompt # format since Tower needs to match on that format. prompted_vault_secret = PromptVaultSecret( prompt_formats=prompt_formats[vault_id_value], vault_id=built_vault_id) # a empty or invalid password from the prompt will warn and continue to the next # without erroring globablly try: prompted_vault_secret.load() except AnsibleError as exc: display.warning('Error in vault password prompt (%s): %s' % (vault_id_name, exc)) raise vault_secrets.append((built_vault_id, prompted_vault_secret)) # update loader with new secrets incrementally, so we can load a vault password # that is encrypted with a vault secret provided earlier loader.set_vault_secrets(vault_secrets) continue # assuming anything else is a password file display.vvvvv('Reading vault password file: %s' % vault_id_value) # read vault_pass from a file file_vault_secret = get_file_vault_secret(filename=vault_id_value, vault_id=vault_id_name, loader=loader) # an invalid password file will error globally try: file_vault_secret.load() except AnsibleError as exc: display.warning( 'Error in vault password file loading (%s): %s' % (vault_id_name, exc)) raise if vault_id_name: vault_secrets.append((vault_id_name, file_vault_secret)) else: vault_secrets.append( (C.DEFAULT_VAULT_IDENTITY, file_vault_secret)) # update loader with as-yet-known vault secrets loader.set_vault_secrets(vault_secrets) return vault_secrets
def setup_vault_secrets(loader, vault_ids, vault_password_files=None, ask_vault_pass=None, create_new_password=False, auto_prompt=True): # list of tuples vault_secrets = [] # Depending on the vault_id value (including how --ask-vault-pass / --vault-password-file create a vault_id) # we need to show different prompts. This is for compat with older Towers that expect a # certain vault password prompt format, so 'promp_ask_vault_pass' vault_id gets the old format. prompt_formats = {} # If there are configured default vault identities, they are considered 'first' # so we prepend them to vault_ids (from cli) here vault_password_files = vault_password_files or [] if C.DEFAULT_VAULT_PASSWORD_FILE: vault_password_files.append(C.DEFAULT_VAULT_PASSWORD_FILE) if create_new_password: prompt_formats['prompt'] = ['New vault password (%(vault_id)s): ', 'Confirm vew vault password (%(vault_id)s): '] # 2.3 format prompts for --ask-vault-pass prompt_formats['prompt_ask_vault_pass'] = ['New Vault password: '******'Confirm New Vault password: '******'prompt'] = ['Vault password (%(vault_id)s): '] # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$' prompt_formats['prompt_ask_vault_pass'] = ['Vault password: '******'prompt', 'prompt_ask_vault_pass']: # --vault-id some_name@prompt_ask_vault_pass --vault-id other_name@prompt_ask_vault_pass will be a little # confusing since it will use the old format without the vault id in the prompt built_vault_id = vault_id_name or C.DEFAULT_VAULT_IDENTITY # choose the prompt based on --vault-id=prompt or --ask-vault-pass. --ask-vault-pass # always gets the old format for Tower compatibility. # ie, we used --ask-vault-pass, so we need to use the old vault password prompt # format since Tower needs to match on that format. prompted_vault_secret = PromptVaultSecret(prompt_formats=prompt_formats[vault_id_value], vault_id=built_vault_id) # a empty or invalid password from the prompt will warn and continue to the next # without erroring globablly try: prompted_vault_secret.load() except AnsibleError as exc: display.warning('Error in vault password prompt (%s): %s' % (vault_id_name, exc)) raise vault_secrets.append((built_vault_id, prompted_vault_secret)) # update loader with new secrets incrementally, so we can load a vault password # that is encrypted with a vault secret provided earlier loader.set_vault_secrets(vault_secrets) continue # assuming anything else is a password file display.vvvvv('Reading vault password file: %s' % vault_id_value) # read vault_pass from a file file_vault_secret = get_file_vault_secret(filename=vault_id_value, vault_id=vault_id_name, loader=loader) # an invalid password file will error globally try: file_vault_secret.load() except AnsibleError as exc: display.warning('Error in vault password file loading (%s): %s' % (vault_id_name, exc)) raise if vault_id_name: vault_secrets.append((vault_id_name, file_vault_secret)) else: vault_secrets.append((C.DEFAULT_VAULT_IDENTITY, file_vault_secret)) # update loader with as-yet-known vault secrets loader.set_vault_secrets(vault_secrets) return vault_secrets
def setup_vault_secrets(loader, vault_ids, vault_password_files=None, ask_vault_pass=None, create_new_password=False): # list of tuples vault_secrets = [] # Depending on the vault_id value (including how --ask-vault-pass / --vault-password-file create a vault_id) # we need to show different prompts. This is for compat with older Towers that expect a # certain vault password prompt format, so 'promp_ask_vault_pass' vault_id gets the old format. prompt_formats = {} vault_password_files = vault_password_files or [] if C.DEFAULT_VAULT_PASSWORD_FILE: vault_password_files.append(C.DEFAULT_VAULT_PASSWORD_FILE) if create_new_password: prompt_formats['prompt'] = [ 'New vault password (%(vault_id)s): ', 'Confirm vew vault password (%(vault_id)s): ' ] else: prompt_formats['prompt'] = ['Vault password (%(vault_id)s): '] # The format when we use just --ask-vault-pass needs to match 'Vault password:\s*?$' prompt_formats['prompt_ask_vault_pass'] = ['Vault password: '******'prompt', 'prompt_ask_vault_pass']: # --vault-id some_name@prompt_ask_vault_pass --vault-id other_name@prompt_ask_vault_pass will be a little # confusing since it will use the old format without the vault id in the prompt if vault_id_name: prompted_vault_secret = PromptVaultSecret( prompt_formats=prompt_formats[vault_id_value], vault_id=vault_id_name) prompted_vault_secret.load() vault_secrets.append( (vault_id_name, prompted_vault_secret)) else: # ie, we used --ask-vault-pass, so we need to use the old vault password prompt # format since Tower needs to match on that format. prompted_vault_secret = PromptVaultSecret( prompt_formats=prompt_formats[vault_id_value], vault_id=C.DEFAULT_VAULT_IDENTITY) prompted_vault_secret.load() vault_secrets.append( (C.DEFAULT_VAULT_IDENTITY, prompted_vault_secret)) # update loader with new secrets incrementally, so we can load a vault password # that is encrypted with a vault secret provided earlier loader.set_vault_secrets(vault_secrets) continue # assuming anything else is a password file display.vvvvv('Reading vault password file: %s' % vault_id_value) # read vault_pass from a file file_vault_secret = get_file_vault_secret( filename=vault_id_value, vault_id_name=vault_id_name, loader=loader) file_vault_secret.load() if vault_id_name: vault_secrets.append((vault_id_name, file_vault_secret)) else: vault_secrets.append( (C.DEFAULT_VAULT_IDENTITY, file_vault_secret)) # update loader with as-yet-known vault secrets loader.set_vault_secrets(vault_secrets) return vault_secrets
def setup_vault_secrets(loader, vault_ids, vault_password_files=None, ask_vault_pass=None, create_new_password=False): # list of tuples vault_secrets = [] if create_new_password: prompt_formats = [ 'New vault password (%s): ', 'Confirm vew vault password (%s): ' ] else: prompt_formats = ['Vault password (%s): '] vault_ids = CLI.build_vault_ids(vault_ids, vault_password_files, ask_vault_pass) for index, vault_id_slug in enumerate(vault_ids): vault_id_name, vault_id_value = CLI.split_vault_id(vault_id_slug) if vault_id_value == 'prompt': # TODO: we could assume --vault-id=prompt implies --ask-vault-pass # if not, we need to 'if ask_vault_pass' here if vault_id_name: prompted_vault_secret = PromptVaultSecret( prompt_formats=prompt_formats, vault_id=vault_id_name) prompted_vault_secret.load() vault_secrets.append( (vault_id_name, prompted_vault_secret)) else: prompted_vault_secret = PromptVaultSecret( prompt_formats=prompt_formats, vault_id=C.DEFAULT_VAULT_IDENTITY) prompted_vault_secret.load() vault_secrets.append( (C.DEFAULT_VAULT_IDENTITY, prompted_vault_secret)) # update loader with new secrets incrementally, so we can load a vault password # that is encrypted with a vault secret provided earlier loader.set_vault_secrets(vault_secrets) continue # assuming anything else is a password file display.vvvvv('Reading vault password file: %s' % vault_id_value) # read vault_pass from a file file_vault_secret = get_file_vault_secret( filename=vault_id_value, vault_id_name=vault_id_name, loader=loader) file_vault_secret.load() if vault_id_name: vault_secrets.append((vault_id_name, file_vault_secret)) else: vault_secrets.append( (C.DEFAULT_VAULT_IDENTITY, file_vault_secret)) # update loader with as-yet-known vault secrets loader.set_vault_secrets(vault_secrets) return vault_secrets