Skip to content

Instantly share code, notes, and snippets.

@darahayes
Last active February 18, 2024 18:57
Show Gist options
  • Star 26 You must be signed in to star a gist
  • Fork 5 You must be signed in to fork a gist
  • Save darahayes/7f2d52ffc190929f14db79ee7d176ed8 to your computer and use it in GitHub Desktop.
Save darahayes/7f2d52ffc190929f14db79ee7d176ed8 to your computer and use it in GitHub Desktop.
KMS Encrypt and Decrypt filters in Ansible

KMS Encrypt and Decrypt Filters for Ansible

This Gist shows how you can encrypt/decrypt variables with KMS during your Ansible playbook execution. While google searching I couldn't find anything useful on the subject.

Let's say your project has a folder of playbooks called plays.

In that folder, create a folder called filter_plugins and insert kms_filters.py (included in this gist)

plays/
├── filter_plugins
│   └── kms_filters.py
├── play1.yml
├── play2.yml

Ansible automatically imports any plugins found and makes them available to your playbooks. The example below shows how you can use the filters.

# play.yml
---
- hosts: localhost
  connection: local
  vars:
    kms_key: arn:aws:kms:us-east-1:xxxxxxxxxxxx:key/c21ca336-c9ed-5765-ad5f-fc941a5192ca
  tasks:
    - name: kms encrypt
      debug:
        msg: "{{ 'hello' | kms_encrypt(kms_key) }}"
    - name: kms encrypt
      debug:
        msg: "{{ 'Some base64 encoded Ciphertext Blob' | kms_decrypt }}"

Assumptions

For this to work you must have either one of the following:

  • The awscli is configured on your machine (so boto can automatically pick up your AWS credentials)
  • OR you're running this on an EC2 instance that has the appropriate permissions to access KMS
import boto3
import base64
kms = boto3.client('kms')
def kms_decrypt(ciphertext):
return kms.decrypt(CiphertextBlob=base64.b64decode(ciphertext)).get('Plaintext')
def kms_encrypt(plaintext, key):
return base64.b64encode(kms.encrypt(KeyId=key,Plaintext=plaintext).get('CiphertextBlob'))
class FilterModule(object):
def filters(self):
return { 'kms_encrypt': kms_encrypt, 'kms_decrypt': kms_decrypt }
---
- hosts: localhost
connection: local
vars:
kms_key: arn:aws:kms:us-east-1:xxxxxxxxxxxx:key/c21ca336-c9ed-5765-ad5f-fc941a5192ca
tasks:
- name: kms encrypt
debug:
msg: "{{ 'hello' | kms_encrypt(kms_key) }}"
- name: kms encrypt
debug:
msg: "{{ 'Some base64 encoded Ciphertext Blob' | kms_decrypt }}"
Copy link

ghost commented Feb 28, 2018

Very nice. I found that it fails when you need use a key from outside your default region; I know you can switch that using the AWS_DEFAULT_REGION environment variable, or by using a profile and AWS_PROFILE, but I found it more useful in my case to extend your filters with a region parameter.

I did have the encrypt call parse the ARN and pull the region out, but couldn't nut out a method of extracting the region from the cyphertext. So both calls include the region parameter for consistency's sake. Do you know whether it's possible to get anything useful from the cyphertext?

@anherrera
Copy link

Anyone get this error (or similar) when trying to use this?

FAILED! => {"msg": "An unhandled exception occurred while running the lookup plugin 'file'. Error was a <type 'exceptions.UnicodeDecodeError'>, original message: 'utf8' codec can't decode byte 0x8d in position 5: invalid start byte"}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment