support decryption of a file

This commit is contained in:
2023-12-06 12:51:34 +01:00
parent bd1d257634
commit e3cad0c66d

View File

@@ -1,13 +1,16 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
"""Encrypt or decrypt using Ansible-vault and Ansible""" """Encrypt or decrypt using Ansible-vault and Ansible"""
# SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx> # SPDX-FileCopyrightText: 2023 Max Mehl <https://mehl.mx>
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
import subprocess # pylint: disable=invalid-name
import json
import argparse import argparse
import json
import os
import subprocess
import sys
parser = argparse.ArgumentParser(description=__doc__) parser = argparse.ArgumentParser(description=__doc__)
subparsers = parser.add_subparsers(title="commands", dest="command", required=True) subparsers = parser.add_subparsers(title="commands", dest="command", required=True)
@@ -16,23 +19,37 @@ parser_encrypt = subparsers.add_parser(
"encrypt", "encrypt",
help="Encrypt a string using ansible-vault", help="Encrypt a string using ansible-vault",
) )
parser_encrypt.add_argument( encrypt_flags = parser_encrypt.add_mutually_exclusive_group(required=True)
encrypt_flags.add_argument(
"-s", "-s",
"--string", "--string",
help="String that shall be encrypted", help="String that shall be encrypted",
dest="encrypt_string", dest="encrypt_string",
) )
encrypt_flags.add_argument(
"-f",
"--file",
help="File that shall be encrypted",
dest="encrypt_file",
)
# Decrypt arguments # Decrypt arguments
parser_decrypt = subparsers.add_parser( parser_decrypt = subparsers.add_parser(
"decrypt", "decrypt",
help="Print a variable of one or multiple hosts and decrypt it if necessary", help="Print a variable of one or multiple hosts and decrypt it if necessary",
) )
parser_decrypt.add_argument( decrypt_flags = parser_decrypt.add_mutually_exclusive_group(required=True)
decrypt_flags.add_argument(
"-H", "-H",
"--host", "--host",
help="Host name from Ansible inventory for which you want to get the variable", help="Host name from Ansible inventory for which you want to get the variable",
dest="decrypt_host", dest="decrypt_host",
) )
decrypt_flags.add_argument(
"-f",
"--file",
help="File that shall be decrypted",
dest="decrypt_file",
)
parser_decrypt.add_argument( parser_decrypt.add_argument(
"-v", "-v",
"--var", "--var",
@@ -50,6 +67,24 @@ def convert_ansible_errors(error: str) -> str:
return error return error
def ask_for_confirm(question: str) -> bool:
"""Ask for confirmation.
Args:
question (str): The question to ask the user.
Returns:
bool: True if the user confirms with 'y', False otherwise.
"""
while True:
answer = input(f"{question} [y/n]: ").lower().strip()
if answer in ("y", "n"):
break
print("Invalid input. Please enter 'y' or 'n'.")
return answer == "y"
def encrypt_string(password): def encrypt_string(password):
"""Encrypt string with ansible-vault""" """Encrypt string with ansible-vault"""
result = subprocess.run( result = subprocess.run(
@@ -57,6 +92,7 @@ def encrypt_string(password):
input=password, input=password,
text=True, text=True,
capture_output=True, capture_output=True,
check=False,
) )
return result.stdout.strip() return result.stdout.strip()
@@ -74,7 +110,30 @@ def format_data(data: dict) -> str:
return "\n".join(formatted_strings) return "\n".join(formatted_strings)
def decrypt_string(host, var): def decrypt_file(filename) -> None:
"""Decrypt file with ansible-vault"""
if not os.path.exists(filename):
sys.exit(f"ERROR: File '{filename}' does not exist")
decrypted_content = subprocess.run(
["ansible-vault", "decrypt", "--output", "-", filename], check=False, capture_output=True
)
if decrypted_content.returncode != 0:
sys.exit(
f"ERROR: Could not decrypt file '{filename}'. This is the error:"
f"\n{decrypted_content.stderr.decode()}"
)
print(decrypted_content.stdout.decode().strip())
if ask_for_confirm("Shall I write the encrypted content as seen above to the file?"):
decrypted_content = subprocess.run(
["ansible-vault", "decrypt", filename], check=True, capture_output=True
)
def decrypt_string(host, var) -> str:
"""Decrypt/print a variable from one or multiple hosts""" """Decrypt/print a variable from one or multiple hosts"""
# Run ansible msg for variable # Run ansible msg for variable
# Send return as JSON # Send return as JSON
@@ -83,14 +142,15 @@ def decrypt_string(host, var):
"ANSIBLE_LOAD_CALLBACK_PLUGINS": "1", "ANSIBLE_LOAD_CALLBACK_PLUGINS": "1",
"ANSIBLE_STDOUT_CALLBACK": "json", "ANSIBLE_STDOUT_CALLBACK": "json",
} }
result = subprocess.run(ansible_command, env=ansible_env, capture_output=True, text=True) result = subprocess.run(
ansible_command, env=ansible_env, capture_output=True, text=True, check=False
)
# Parse JSON # Parse JSON
try: try:
ansible_output = json.loads(result.stdout)["plays"][0]["tasks"][0]["hosts"] ansible_output = json.loads(result.stdout)["plays"][0]["tasks"][0]["hosts"]
except IndexError: except IndexError:
print(f"ERROR: Host '{host}' not found.") sys.exit(f"ERROR: Host '{host}' not found.")
return ""
# Attempt to create a :-separated list of host/values # Attempt to create a :-separated list of host/values
output = {} output = {}
@@ -103,16 +163,28 @@ def decrypt_string(host, var):
def main(): def main():
"""Main function""" """Main function"""
args = parser.parse_args() args = parser.parse_args()
output = ""
# ENCRYPTION
if args.command == "encrypt": if args.command == "encrypt":
password = input("Enter string: ") if not args.encrypt_string else args.encrypt_string if args.encrypt_string:
vaultpw = encrypt_string(password) password = input("Enter string: ") if not args.encrypt_string else args.encrypt_string
output = encrypt_string(password)
elif args.encrypt_file:
filename = input("Enter filename: ") if not args.encrypt_file else args.encrypt_file
# TODO
# DECRYPTION
elif args.command == "decrypt": elif args.command == "decrypt":
host = input("Enter host: ") if not args.decrypt_host else args.decrypt_host if args.decrypt_host:
var = input("Enter variable: ") if not args.decrypt_var else args.decrypt_var host = input("Enter host: ") if not args.decrypt_host else args.decrypt_host
vaultpw = decrypt_string(host, var) var = input("Enter variable: ") if not args.decrypt_var else args.decrypt_var
output = decrypt_string(host, var)
elif args.decrypt_file:
filename = input("Enter filename: ") if not args.decrypt_file else args.decrypt_file
decrypt_file(filename)
print(vaultpw) if output:
print(output)
if __name__ == "__main__": if __name__ == "__main__":