avatarTate Galbraith

Summary

The article provides a guide on integrating Ansible Vault with Python to securely manage sensitive credentials for both playbooks and other Python code.

Abstract

Ansible Vault is a powerful feature that allows users to securely manage sensitive data within Ansible playbooks. The article explains how to extend this functionality to Python applications by demonstrating how to encrypt data with Ansible Vault, create a Python script to decrypt the vault file, and access the decrypted data within Python. It emphasizes the security of Ansible Vault's encryption, using AES256 by default, and provides a detailed walkthrough on using the Ansible API for Python to handle vault files without relying on third-party modules. The article also discusses different methods for providing the vault password, including using a password file, plain-text password, or password prompt, and concludes with instructions on running the decryption script and a call to action for readers to engage with more content from the author.

Opinions

  • The author positively regards Ansible Vault's encryption method, considering it reliable and secure, as it is trusted by the NSA and uses AES256.
  • There is an acknowledgment of a limitation with Ansible Vault, which is its exclusive integration with Ansible, prompting the need for a solution to use Vault with other codebases.
  • The author suggests that using the Ansible API directly for Python integration is preferable to third-party wrappers due to its flexibility and lack of dependencies.
  • The article implies that managing secrets in a centralized location (Ansible Vault) is beneficial for maintaining consistency and security across different types of code.
  • The author encourages readers to explore additional resources and content, indicating a belief in the value of continuous learning and community engagement.

How To Use Ansible Vault With Python

Photo by regularguy.eth on Unsplash

Isn’t Ansible Vault handy? It lets you use passwords and other sensitive credentials in your playbooks without ever exposing them to source control or plain text files. When you reference a vault variable, you can be sure that your secrets are safely tucked away at rest.

The encryption is great too. By default Ansible Vault uses an AES256 cipher algorithm to secure data. This is currently one of the most secure methods for encrypting data in existence. If the NSA can rely on it, so can you.

There’s just one problem with all this Vault magic. It only works with Ansible. Imagine you put all of your credentials in there. This works fantastic for playbooks, but what about the rest of your code? How can you keep your secrets in Vault but give other code access?

In this article, we’ll see exactly how to use Ansible Vault with Python. This will let you keep your sensitive credentials in one place for both your code and your playbooks.

Encrypt some data

Let’s play around with a test vault so we don’t mess up any important secrets. Make a new vault YAML file and give it a password of your choice:

ansible-vault create test_vault.yml

Now, throw the following data in there:

---
vault_secret: 123456

If you want to validate the data you can decrypt it with the following command:

ansible-vault view test_vault.yml

It should prompt you for your password and show you the contents of the file.

Make a test decrypt script

In order to decrypt our vault file and load the contents into Python we’ll use a combination of standard modules and the Ansible API for Python.

This method requires no third-party modules (aside from Ansible) and lets you handle any special parsing you may need on your own. While it might be a touch more work than using a third-party wrapper, it is a bit more flexible and also has the added benefit of being dependency-free.

Let’s make a Python script with the following code:

# decrypt.py

from os import environ
import yaml
from ansible.constants import DEFAULT_VAULT_ID_MATCH
from ansible.parsing.vault import VaultLib, VaultSecret

vault_file = 'test_vault.yml'

vault_env = environ.get("ANSIBLE_VAULT_PASSWORD_FILE")
vault_pass = open(vault_env).read().strip().encode('utf-8')

vault = VaultLib([
  (DEFAULT_VAULT_ID_MATCH, VaultSecret(vault_pass))
])

decrypted_vault = vault.decrypt(open(vault_file).read())
vault_dict = yaml.load(decrypted_vault.decode(), Loader=yaml.SafeLoader)

print(vault_dict)

There’s a lot going on in this file, so let’s take a look at everything one step at a time:

  • First, bring in the required modules, including some Vault functions from the Ansible API.
  • Specify the vault file in the same directory by name and extension.
  • Next, load the vault password file path based on the environment variable. This is if you’ve already defined a vault password file variable in your Ansible configuration or in some other loader.
  • Read the vault password file from the path, strip whitespace and encode it to bytes. The library requires a bytes-like object. This is our actual vault password used to decrypt the vault.

Let’s pause here for a few notes about the different ways to obtain the vault password.

If you don’t want to use a vault password file, or simply want to pass the vault password on the command-line you can change the vault_pass variable to either a plain-text password or a password prompt like this:

# as an encoded string
vault_pass = '1234'.encode('utf-8')

# or as a password prompt
from getpass import getpass
vault_pass = getpass('enter your vault password: ').encode('utf-8')

If you decide to obtain the vault password like this, you can just omit the environment variable from vault_env.

Once you’ve decided on the best password method, let’s return to our line-by-line breakdown:

  • Instantiate a new VaultLib object and pass in the encoded secret. Here this is a list with a tuple of the default vault ID (you can keep this the same unless you’ve changed your vault ID) and the VaultSecret object. The vault password you provided gets passed in here.
  • Next the vault file is read in and decrypted.
  • Finally, the contents of the decrypted vault file are decoded from bytes and converted from YAML to a Python dictionary. Since our vault file is actually just another YAML file, we still need to parse it in order to bring it into Python as structured data.
  • The results are printed and you can now use the secrets within Python as you wish. Keep in mind that they are decrypted, so be careful what you do with them from this point forward.

You can run the script and pass in the environment variable manually using the following command. Keep in mind the password file in our example is located in the same directory. If you have placed your password file somewhere else, you’ll need to adjust the path in this environment variable accordingly:

ANSIBLE_VAULT_PASSWORD_FILE=vault_secret python3 decrypt.py

Once run, this script should print out a dictionary containing the contents of our encrypted vault file. Now you can use all your Ansible Vault secrets inside of Python!

If you get stuck or have questions about the Ansible API, check out the official Ansible documentation.

Thank you for reading! If you liked this article, please subscribe, follow and if you haven’t already sign-up for more great content. Here’s some of my other posts to check out:

Python
Programming
Software Development
Technology
Coding
Recommended from ReadMedium