bin/ansible-vault
427b8dc7
 #!/usr/bin/env python
 
 # (c) 2014, James Tanner <tanner.jc@gmail.com>
 #
 # 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 <http://www.gnu.org/licenses/>.
 #
 # ansible-pull is a script that runs ansible in local mode
 # after checking out a playbooks directory from source repo.  There is an
 # example playbook to bootstrap this script in the examples/ dir which
 # installs ansible and sets it up to run on cron.
 
0e7b9e5c
 #__requires__ = ['ansible']
 #import pkg_resources
0fefab66
 
52a8efef
 import os
427b8dc7
 import sys
 import traceback
 
 from ansible import utils
 from ansible import errors
52a8efef
 from ansible.utils.vault import VaultEditor
427b8dc7
 
 from optparse import OptionParser
 
 #-------------------------------------------------------------------------------------
 # Utility functions for parsing actions/options
 #-------------------------------------------------------------------------------------
 
 VALID_ACTIONS = ("create", "decrypt", "edit", "encrypt", "rekey")
 
 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 <command> --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
0d6f6ad2
     #parser.add_option('-c', '--cipher', dest='cipher', default="AES256", help="cipher to use")
7acd2f3a
     parser.add_option('--debug', dest='debug', action="store_true", help="debug")
     parser.add_option('--vault-password-file', dest='password_file',
                     help="vault password file")
427b8dc7
 
     # 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 == "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
 #-------------------------------------------------------------------------------------
 
7acd2f3a
 def _read_password(filename):
     f = open(filename, "rb")
     data = f.read()
5849bb3d
     f.close()
8c2e1e2b
     data = data.strip()
7acd2f3a
     return data
 
427b8dc7
 def execute_create(args, options, parser):
 
     if len(args) > 1:
52a8efef
         raise errors.AnsibleError("'create' does not accept more than one filename")        
7acd2f3a
 
     if not options.password_file:        
         password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True)
     else:
         password = _read_password(options.password_file)
427b8dc7
 
0d6f6ad2
     cipher = 'AES256'
52a8efef
     if hasattr(options, 'cipher'):
         cipher = options.cipher
 
     this_editor = VaultEditor(cipher, password, args[0])
     this_editor.create_file()
427b8dc7
 
 def execute_decrypt(args, options, parser):
 
7acd2f3a
     if not options.password_file:        
         password, new_password = utils.ask_vault_passwords(ask_vault_pass=True)
     else:
         password = _read_password(options.password_file)
427b8dc7
 
0d6f6ad2
     cipher = 'AES256'
52a8efef
     if hasattr(options, 'cipher'):
         cipher = options.cipher
 
427b8dc7
     for f in args:
52a8efef
         this_editor = VaultEditor(cipher, password, f)
         this_editor.decrypt_file()
427b8dc7
 
     print "Decryption successful"
 
 def execute_edit(args, options, parser):
 
     if len(args) > 1:
         raise errors.AnsibleError("create does not accept more than one filename")        
 
7acd2f3a
     if not options.password_file:        
         password, new_password = utils.ask_vault_passwords(ask_vault_pass=True)
     else:
         password = _read_password(options.password_file)
427b8dc7
 
52a8efef
     cipher = None
 
427b8dc7
     for f in args:
52a8efef
         this_editor = VaultEditor(cipher, password, f)
         this_editor.edit_file()
427b8dc7
 
 def execute_encrypt(args, options, parser):
 
7acd2f3a
     if not options.password_file:        
         password, new_password = utils.ask_vault_passwords(ask_vault_pass=True, confirm_vault=True)
     else:
         password = _read_password(options.password_file)
427b8dc7
 
0d6f6ad2
     cipher = 'AES256'
52a8efef
     if hasattr(options, 'cipher'):
         cipher = options.cipher
 
427b8dc7
     for f in args:
52a8efef
         this_editor = VaultEditor(cipher, password, f)
         this_editor.encrypt_file()
427b8dc7
 
     print "Encryption successful"
 
 def execute_rekey(args, options, parser):
 
7acd2f3a
     if not options.password_file:        
         password, __ = utils.ask_vault_passwords(ask_vault_pass=True)
     else:
         password = _read_password(options.password_file)
 
     __, new_password = utils.ask_vault_passwords(ask_vault_pass=False, ask_new_vault_pass=True, confirm_new=True)
 
52a8efef
     cipher = None
427b8dc7
     for f in args:
52a8efef
         this_editor = VaultEditor(cipher, password, f)
         this_editor.rekey_file(new_password)
427b8dc7
 
     print "Rekey successful"
 
 #-------------------------------------------------------------------------------------
 # MAIN
 #-------------------------------------------------------------------------------------
 
 def main():
 
     action = get_action(sys.argv)
     parser = build_option_parser(action)
     (options, args) = parser.parse_args()
 
     # 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()