#!/usr/bin/env python # (c) 2014, James Tanner # # Ansible is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # Ansible is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with Ansible. If not, see . # # ansible-vault is a script that encrypts/decrypts YAML files. See # http://docs.ansible.com/playbooks_vault.html for more details. __requires__ = ['ansible'] try: import pkg_resources except Exception: # Use pkg_resources to find the correct versions of libraries and set # sys.path appropriately when there are multiversion installs. But we # have code that better expresses the errors in the places where the code # is actually used (the deps are optional for many code paths) so we don't # want to fail here. pass import os import sys import traceback import ansible.constants as C from ansible import utils from ansible import errors from ansible.utils.vault import VaultEditor from optparse import OptionParser #------------------------------------------------------------------------------------- # Utility functions for parsing actions/options #------------------------------------------------------------------------------------- VALID_ACTIONS = ("create", "decrypt", "edit", "encrypt", "rekey", "view") def build_option_parser(action): """ Builds an option parser object based on the action the user wants to execute. """ usage = "usage: %%prog [%s] [--help] [options] file_name" % "|".join(VALID_ACTIONS) epilog = "\nSee '%s --help' for more information on a specific command.\n\n" % os.path.basename(sys.argv[0]) OptionParser.format_epilog = lambda self, formatter: self.epilog parser = OptionParser(usage=usage, epilog=epilog) if not action: parser.print_help() sys.exit() # options for all actions #parser.add_option('-c', '--cipher', dest='cipher', default="AES256", help="cipher to use") parser.add_option('--debug', dest='debug', action="store_true", help="debug") parser.add_option('--vault-password-file', dest='password_file', help="vault password file", default=C.DEFAULT_VAULT_PASSWORD_FILE) # options specific to actions if action == "create": parser.set_usage("usage: %prog create [options] file_name") elif action == "decrypt": parser.set_usage("usage: %prog decrypt [options] file_name") elif action == "edit": parser.set_usage("usage: %prog edit [options] file_name") elif action == "view": parser.set_usage("usage: %prog view [options] file_name") elif action == "encrypt": parser.set_usage("usage: %prog encrypt [options] file_name") elif action == "rekey": parser.set_usage("usage: %prog rekey [options] file_name") # done, return the parser return parser def get_action(args): """ Get the action the user wants to execute from the sys argv list. """ for i in range(0,len(args)): arg = args[i] if arg in VALID_ACTIONS: del args[i] return arg return None def get_opt(options, k, defval=""): """ Returns an option from an Optparse values instance. """ try: data = getattr(options, k) except: return defval if k == "roles_path": if os.pathsep in data: data = data.split(os.pathsep)[0] return data #------------------------------------------------------------------------------------- # Command functions #------------------------------------------------------------------------------------- def execute_create(args, options, parser): if len(args) > 1: raise errors.AnsibleError("'create' does not accept more than one filename") if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True) else: password = utils.read_vault_file(options.password_file) cipher = 'AES256' if hasattr(options, 'cipher'): cipher = options.cipher this_editor = VaultEditor(cipher, password, args[0]) this_editor.create_file() def execute_decrypt(args, options, parser): if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True) else: password = utils.read_vault_file(options.password_file) cipher = 'AES256' if hasattr(options, 'cipher'): cipher = options.cipher for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.decrypt_file() print "Decryption successful" def execute_edit(args, options, parser): if len(args) > 1: raise errors.AnsibleError("edit does not accept more than one filename") if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True) else: password = utils.read_vault_file(options.password_file) cipher = None for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.edit_file() def execute_view(args, options, parser): if len(args) > 1: raise errors.AnsibleError("view does not accept more than one filename") if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True) else: password = utils.read_vault_file(options.password_file) cipher = None for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.view_file() def execute_encrypt(args, options, parser): if not options.password_file: password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True) else: password = utils.read_vault_file(options.password_file) cipher = 'AES256' if hasattr(options, 'cipher'): cipher = options.cipher for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.encrypt_file() print "Encryption successful" def execute_rekey(args, options, parser): if not options.password_file: password, __ = utils.ask_vault_passwords(ask_vault_pass=True) else: password = utils.read_vault_file(options.password_file) __, new_password = utils.ask_vault_passwords(ask_vault_pass=False, ask_new_vault_pass=True, confirm_new=True) cipher = None for f in args: this_editor = VaultEditor(cipher, password, f) this_editor.rekey_file(new_password) print "Rekey successful" #------------------------------------------------------------------------------------- # MAIN #------------------------------------------------------------------------------------- def main(): action = get_action(sys.argv) parser = build_option_parser(action) (options, args) = parser.parse_args() if not len(args): raise errors.AnsibleError( "The '%s' command requires a filename as the first argument" % action ) # execute the desired action try: fn = globals()["execute_%s" % action] fn(args, options, parser) except Exception, err: if options.debug: print traceback.format_exc() print "ERROR:",err sys.exit(1) if __name__ == "__main__": main()