#!/usr/bin/env python from functools import lru_cache import os from pathlib import Path import subprocess import sys from ansible.module_utils.six.moves import configparser from ansible.plugins.vars import BaseVarsPlugin DOCUMENTATION = """ module: pass vars: vault version_added: 2.9 short_description: Load vault passwords from pass description: - Works exactly as a vault, loading variables from pass. - Decrypts the YAML file `ansible_vault` from cranspasswords. - Loads the secret variables. - Makes use of data caching in order to avoid calling cranspasswords multiple times. - Uses the local gpg key from the user running ansible on the Control node. """ class VarsModule(BaseVarsPlugin): @staticmethod @lru_cache def vault_passwords(): """ Passwords are decrypted from the local password store, then are cached. By that way, we don't decrypt these passwords everytime. """ # Load config config = configparser.ConfigParser() config.read(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'pass.ini')) password_store = Path(config.get('pass', 'password_store_dir', fallback=os.getenv('PASSWORD_STORE_DIR', Path.home() / '.password-store'))) crans_submodule = config.get('pass', 'crans_password_store_submodule', fallback=os.getenv('CRANS_PASSWORD_STORE_SUBMODULE', 'crans')) full_command = ['gpg', '-d', password_store / crans_submodule / 'ansible_vault.gpg'] proc = subprocess.run(full_command, capture_output=True, close_fds=True) clear_text = proc.stdout.decode('UTF-8') sys.stderr.write(proc.stderr.decode('UTF-8')) return clear_text def get_vars(self, loader, path, entities): """ Get all vars for entities, called by Ansible. loader: Ansible's DataLoader. path: Current play's playbook directory. entities: Host or group names pertinent to the variables needed. """ # VarsModule objects are called every time you need host vars, per host, # and per group the host is part of. # It is about 6 times per host per task in current state # of Ansible Crans configuration. # It is way to much. # So we cache the data into the DataLoader (see parsing/DataLoader). return {'vault': loader.load(VarsModule.vault_passwords())}