Script to migrate ansible-vault file to single-encrypted-variable

From ansible 2.3, single-encrypted-variable is supported in addition to full file encryption.

Before this functionality was implemented, we have to handle secrets with full file encryption. With full file encryption, we can't check the diff of vault files because the whole file will be changed when adding/updating any small changes to vault file. But with using single-encrypted-variable, it's provides us transparency and make it easier to take diff and confirm the changes done(with in PRs etc..)

This script will help migrating the file based ansible-vault files into single-encrypted variable format.

for more details about single-encrypted-variable, please see following website. https://docs.ansible.com/ansible/latest/user_guide/playbooks_vault.html#single-encrypted-variable

import argparse, yaml, sys

from ansible.constants import DEFAULT_VAULT_ID_MATCH
from ansible.parsing.vault import VaultLib
from ansible.parsing.vault import VaultSecret


def main(argv):
    parser = argparse.ArgumentParser(
            description='This script will convert ansible-vault format'
                        'files to variable-based encrypted format.')

    parser.add_argument('-i', '--inputfile',
                        help='inputfile(expected vault format)',
                        required=True)
    parser.add_argument('-p', '--secret', required=True)
    parser.add_argument('--overwrite', action='store_true')
    args = parser.parse_args()

    vault = VaultLib([(DEFAULT_VAULT_ID_MATCH, VaultSecret(args.secret))])

    with open(args.inputfile, "r") as f:
        encrypted_vars = {}

        plaintext_vars = yaml.load(vault.decrypt(f.read()))
        for plaintext_var_name, plaintext_var_contents \
                in plaintext_vars.items():
            encrypted_vars[plaintext_var_name] \
                    = vault.encrypt(plaintext_var_contents)

        encrypted_yaml = yaml.safe_dump(encrypted_vars, default_style='|')

        # workaround for custom tag in yaml(!vault)
        encrypted_yaml = \
            encrypted_yaml.replace('|', '!vault |')

        print(encrypted_yaml)

    if args.overwrite:
        with open(args.inputfile, "w") as f:
            f.write(encrypted_yaml)


if __name__ == "__main__":
    main(sys.argv[1:])