diff --git a/app/fields.py b/app/fields.py index a5ed4fb40d699e07bd2abae891f98c7a0ae8c5c7..bc35c41688b7033285d31b8feef20c25d11da80c 100644 --- a/app/fields.py +++ b/app/fields.py @@ -13,6 +13,18 @@ import yaml from wtforms import TextAreaField +# String can be encoded with ansible-vault and stored in yaml files +# using the "!vault" tag. +# To be used in a dynamic inventory, it shall be converted to the mapping +# {"__ansible_vault": value} as it needs to be returned as JSON. +def vault_constructor(loader, node): + value = loader.construct_scalar(node) + return {"__ansible_vault": value} + + +yaml.SafeLoader.add_constructor("!vault", vault_constructor) + + class YAMLField(TextAreaField): """This field represents an HTML ``<textarea>`` used to input YAML""" diff --git a/docs/_static/ansible/awx_ansible_vault_credential.png b/docs/_static/ansible/awx_ansible_vault_credential.png new file mode 100644 index 0000000000000000000000000000000000000000..a50a1ad92b9626e0e5446d64b2ef85992c969e56 Binary files /dev/null and b/docs/_static/ansible/awx_ansible_vault_credential.png differ diff --git a/docs/_static/ansible/enter_vault_variable.png b/docs/_static/ansible/enter_vault_variable.png new file mode 100644 index 0000000000000000000000000000000000000000..e9b1e8d7776cf1355c9d07623fc129575d645607 Binary files /dev/null and b/docs/_static/ansible/enter_vault_variable.png differ diff --git a/docs/_static/ansible/saved_vault_variable.png b/docs/_static/ansible/saved_vault_variable.png new file mode 100644 index 0000000000000000000000000000000000000000..a03083a6f9bef86930ed47f663864ef1035607ca Binary files /dev/null and b/docs/_static/ansible/saved_vault_variable.png differ diff --git a/docs/network.rst b/docs/network.rst index f7d18c322790eecb4857c0660157049d241aa230..71cf6c550ba24a3feb2fbc535cb4cb08505c903a 100644 --- a/docs/network.rst +++ b/docs/network.rst @@ -125,3 +125,42 @@ You can also create `groups of groups <https://docs.ansible.com/ansible/latest/u To do so, just select the group names in the *Children* field when registering a new group: .. image:: _static/ansible/create_ansible_group_of_groups.png + +Encrypted variables +~~~~~~~~~~~~~~~~~~~ + +`Ansible vault`_ allows to create encrypted variables to embed in yaml using the `ansible-vault encrypt_string`_ command. + +:: + + $ ansible-vault encrypt_string -n mypassord acomplexpassword + New Vault password: + Confirm New Vault password: + mypassord: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 33383731306533343464396365336135653261316639643937326134313430313833316438633238 + 3237613332396239363134346462653831626237663231360a356235306262333634653036336236 + 32333435306334343839353664396165343861373333613830383762393734393434346633653839 + 6139663637336462330a316366326461633964386135346239303338366237383561643034353263 + 66623362333866373530316437366564303332353032643961663435343939633164 + Encryption successful + +You can directly copy/paste the result of the command to CSEntry: + +.. image:: _static/ansible/enter_vault_variable.png + +The ``!vault`` tag is used to embed encrypted variables in yaml. But variables are saved in JSON in CSEntry as +this is the format used by the dynamic inventory. +The scalar value is thus automatically converted to the mapping ``{"__ansible_vault": "encrypted_value"}`` which +is what AWX expects. +So this is what you'll see when you save the variable: + +.. image:: _static/ansible/saved_vault_variable.png + +When encrypting variables, be sure to use the vault password that is defined in AWX. +And don't forget to add the **ansible-vault** credential to your template to allow AWX to decrypt the variable. + +.. image:: _static/ansible/awx_ansible_vault_credential.png + +.. _Ansible vault: https://docs.ansible.com/ansible/2.6/user_guide/vault.html +.. _ansible-vault encrypt_string: https://docs.ansible.com/ansible/2.6/user_guide/vault.html#use-encrypt-string-to-create-encrypted-variables-to-embed-in-yaml diff --git a/tests/unit/test_fields.py b/tests/unit/test_fields.py new file mode 100644 index 0000000000000000000000000000000000000000..99e2a9be433eea1cb33a3ced998fad2e0cb04e6d --- /dev/null +++ b/tests/unit/test_fields.py @@ -0,0 +1,35 @@ +# -*- coding: utf-8 -*- +""" +tests.unit.test_fields +~~~~~~~~~~~~~~~~~~~~~~ + +This module defines fields tests. + +:copyright: (c) 2018 European Spallation Source ERIC +:license: BSD 2-Clause, see LICENSE for more details. + +""" +from app.fields import yaml + + +def test_vault_yaml_tag_load(): + s = """foo: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 31333561643032383935666363366337303435363132373238313334663563346164613433616231 + 3464663834343564663638613062386366303836646136360a343231373731656261303830363837 + 63636137336163383637383135643065306436306365343136373138393762366534346161316633 + 3166363036616162620a346536663132343137663464653663383163646239313537316537626165 + 3839 + """ + value = yaml.safe_load(s) + assert value == { + "foo": { + "__ansible_vault": """$ANSIBLE_VAULT;1.1;AES256 +31333561643032383935666363366337303435363132373238313334663563346164613433616231 +3464663834343564663638613062386366303836646136360a343231373731656261303830363837 +63636137336163383637383135643065306436306365343136373138393762366534346161316633 +3166363036616162620a346536663132343137663464653663383163646239313537316537626165 +3839 +""" + } + }