vaulti-ansible


Namevaulti-ansible JSON
Version 0.1.1 PyPI version JSON
download
home_pageNone
SummaryUtility for Ansible Vault inline-encrypted variables
upload_time2024-09-11 17:53:19
maintainerNone
docs_urlNone
authorNone
requires_python>=3.8
licenseMIT
keywords ansible ansible-vault
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Vaulti

Utility to edit, create, encrypt and decrypt ansible-vault in-line encrypted variables in yaml files.

If you wish you had `ansible-vault edit` for files with inline encrypted variables, that is what this utility is trying to do.

## Usage

https://github.com/user-attachments/assets/74480694-3333-4405-8f68-248af21c9999

```shell
vaulti file1 # If you want it to use standard ansible environment vars for the vault password
vaulti file1 [file2] [file3] [...] # Define multiple files if you wish
vaulti file1 --ask-vault-pass # If you want to specify the password on the CLI
vaulti file1 --ask-vault-pass --vault-id mylabel@prompt # You can also specify vault ids
vaulti file1 -r # Prints the output, doesn't let you edit. Useful for setting up custom git textconv, etc.
```

See `vaulti -h` for more parameters.

## About

### General

This utility opens an editor where the encrypted variables have been decrypted for you!

The previously encrypted variables are indicated with a special tag, `!ENCRYPT`.

You can use the standard ansible methods of defining a vault password or vault password file, like `--ask-vault-pass` parameter,
`ANSIBLE_VAULT_PASSWORD_FILE` environment variable and `--vault-id`.

It gives you the ability to:

- Add or remove the `!ENCRYPT` tags as you wish, and it will encrypt or decrypt it for you.
- Read, edit and encrypt block scalars if you need to include newlines (`|`, `>`, `|-`, etc.), which can be useful when you want to encrypt client certs, private keys or other multi-line values
- Read and edit different vault ids in the same file
- Swap a variable to be encrypted by a different vault-id

There are some quality of life features built in, such as:

- if you edit the file to some invalid yaml, you'll get the chance to re-open the file and try again
- ditto if you try to encrypt with a vault id that you didn't load when starting
- if you comment out a line while it is decrypted, it will not be reencrypted, but it will produce a warning.

Variable files that could not be decrypted for whatever reason, get a tag indicating the problem, but is left untouched after exiting.
The list of tags, both for success and failure, are currently:

- `!ENCRYPT` : Variables that have been decrypted, and will be reencrypted when you close the editor
- `!VAULT_FORMAT_ERROR` : Variables that could not be parsed due to ansible-vault rejecting the format. It will revert to the original `!vault` tag/value untouched after you close the editor.
- `!UNKNOWN_VAULT_ID_LABEL` : Variables that could not be decrypted, most likely because you did not load/specify the relevant vault id. It will revert to the original `!vault` tag/value untouched after you close the editor.
- `!COULD_NOT_DECRYPT` : Variables that could not be decrypted, probably because you specified the wrong password. It will revert to the original `!vault` tag/value untouched after you close the editor.
- `![any tag]:[label]`, for example `!ENCRYPT:foo`: Indicates that this value was decrypted with a specific vault-id label.



### Vault ids

Secrets decrypted with the non-default ID will be shown in the tag as `!ENCRYPT:mylabel`. You can also set these labels yourself, as long as 
you actually loaded the relevant vault-id when starting the utility.

**WARNING**: The labels are there to help *you* when prompted, but ansible-vault will try all of the keys when decrypting no matter what.
So if you have two vault-ids, but you swap the passwords on the prompt, it will still decrypt just fine. However, when you save and quit,
now you'll encrypt the variables with the swapped passwords instead, which might lead to confusion.


## Example

The dists have been published to PyPi, you can easily install it with `pip install vaulti_ansible`.

Alternatively, you can clone this repo and use another installation method:

```shell
# You can test this by cloning the repo, cd into it
git clone https://github.com/oveee92/vaulti.git && cd vaulti

# then EITHER install it with pip to get it installed into your PATH and as a python module
pip install .
vaulti example/example_data.yml
# OR put it somewhere in the PATH yourself
cp .src/vaulti_ansible/vaulti.py ~/.local/bin/vaulti
vaulti example/example_data.yml
# OR just use it directly without "installing" it
./src/vaulti_ansible/vaulti.py example/example_data.yml

```

Then you can set up and use it

```shell
# If you want to use a password file, you can set it as a variable
export ANSIBLE_VAULT_PASSWORD_FILE=example/.default_vault_pass.txt
# OR specify it on the command line
vaulti example/example_data.yml --vault-password-file example/.default_vault_pass.txt

# To see the variables encrypted with the foo vault ID, load it too, either being prompted for the password, or referring to a file
vaulti example/example_data.yml --vault-id foo@prompt
vaulti example/example_data.yml --vault-id foo@example/.foo_vault_pass.txt

# Make some changes to existing variables, create some new ones or remove some tags
# Save and quit, then open it regularly to see what changed, or just run git diff to see what happened
git diff example_encrypted_data.yaml
```

## Why this exists

The standard `ansible-vault` works fine for encrypting/decrypting/editing whole files, but there are times you don't want to encrypt entire files; for example:

If you use AWX/AAP, having vault-encrypted files is a bit difficult; you either have to

- include the vault password in whichever container/Execution environment you are running the playbooks (therefore requiring a custom container image), or
- decrypt the file when syncing the inventory (making all your secrets plaintext for those with high enough access in AWX)

Additionally, if your control repo is getting large, with lots of host vars, group vars and roles, and you want to find out where certain variables are defined,
you won't be able to search full vault-encrypted files easily, since all the keys are also encrypted.

So then you try inline encryption, which solves pretty much all of these problems, but using it with `ansible-vault edit <file>` is no longer possible...
you have to do something like this instead:

```shell
## To encrypt:
ansible-vault encrypt_string # <enter>
SomePasswordOrSomething # <Ctrl-D>, NOT <enter> unless you need the newline encrypted too
# Then copy the output into your yaml file, making sure the indentation is still ok

## To edit:
# Encrypt a new string and replace it.

## To decrypt:
ansible -i the/relevant/inventory the-relevant-host -m debug -a "var=TheRelevantVariable"
```

Not really easy to remember the encrypt and decrypt steps, pretty error-prone and requires you to actually run something with ansible, putting the variable
somewhere where it will actually be read (hostvars or groupvars). It is *much* easier to just open the decrypted content and edit it directly.


## Why you should NOT use this

I am a sysadmin by trade, not really a professional programmer, and the quality of the code might reflect that. It is getting better over time,
but there may still be edge cases where strange things could happen to the file you are editing. It isn't likely, and I've used it without issue
for some time, but if you don't have your files in a git repo with the ability to revert files easily, please dont use this just yet (or, better,
just initialize a git repo first! If you need this utility, it's probably time for version control anyway)

Also, if you try to change the yaml tags to or from the "invalid" tags, like `!COULD_NOT_DECRYPT`, when editing, you'll probably end up with unencrypted
or even broken variables in your file. Stick to adding or removing the `!ENCRYPT` tags and their labels only, for the full experience.

## Caveats

Since it uses the fantastic (yet sparsely documented) `ruamel.yaml`, and the yaml spec is pretty extensive, this utility does
make some "non-negotiable" changes to your files that you should be aware of, that happens when we load and parse the yaml data:

- Indentation for your multiline strings will always end up with a fixed (default two) spaces relative to the variable it belongs to;
  i.e. not the 10 spaces indented or whatever the default is from the `ansible-vault encrypt_string` output. This is good for consistency, but it does mean that the indentation
  of your inline-encrypted variables will probably change the first time you use this, if you've previously used `ansible-vault encrypt_string` to generate the encrypted strings.
  If you don't change the decrypted value, it should remain the same though, except for the indent change.
- Extra whitespaces will be removed whereever it is found (for example `key:  value` -> `key: value`)

Also, there are a few "opinionated" things I've hardcoded, which are relatively easy to comment out or change in `setup_yaml()` if you wish it.

- Header (`---`) and footer (`...`) will be added automatically to the variable file if it doesn't exist.
- An indent equals two spaces
- The hyphen starting each list items is indented, not inline with the parent key
- An extra newline is added below the ansible-vault output, for readability.
- No automatic line breaks for long values.

Finally, a word on diffs. The utility revolves around decrypting and reencrypting the variables, which means that every time you open a file with it, the
encrypted string actually changes (different salt for each reencrypt). Part of the utility is therefore dedicated to looping through the re-encrypted file, comparing it with
the original decrypted data, and preferring the old encrypted string if the actual decrypted value hasn't changed. That means that any git diff produced by these changes will
usually only involve the relevant changed variables, but it is a "best effort" process. If you change the number encrypted variables in a list, the items
whose list index was changed will be re-encrypted with a new salt, since the original value cannot be found. Same goes for any variables where you change
the key name. Create the key/entry with a regular editor first if this is important to you.

## Dependencies

Won't put the dependencies in the `pyproject.toml` file for now, since with Ansible, sometimes you
want ansible-core on a specific version to keep a consistent execution environment. Any mention of
the required libraries will make pip upgrade `ansible` and `ansible-core` packages even if the
requirements don't make it necessary.

Having to use `--no-deps` for installing this tool is just asking for trouble.

Dependencies are:

```
# We're using typing classes from Python3.9, and __future__ annotations is not not available before python 3.7.
# Since ansible seems to skip 3.7, let's just say 3.8. Might work with 3.7, if you are using that for some reason.
python>=3.8 

ruamel.yaml>=0.16.6 # Won't work before this version due to TaggedScalar changes
ansible>=2.4.0.0 # Won't work for older versions due to pycrypto
```

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "vaulti-ansible",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": null,
    "keywords": "ansible, ansible-vault",
    "author": null,
    "author_email": "Ove <oveee92@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/ca/11/9f8955f5f987edd6d55f4961c1caf8c0fef16f9fb170439f4c56000ff4f2/vaulti_ansible-0.1.1.tar.gz",
    "platform": null,
    "description": "# Vaulti\n\nUtility to edit, create, encrypt and decrypt ansible-vault in-line encrypted variables in yaml files.\n\nIf you wish you had `ansible-vault edit` for files with inline encrypted variables, that is what this utility is trying to do.\n\n## Usage\n\nhttps://github.com/user-attachments/assets/74480694-3333-4405-8f68-248af21c9999\n\n```shell\nvaulti file1 # If you want it to use standard ansible environment vars for the vault password\nvaulti file1 [file2] [file3] [...] # Define multiple files if you wish\nvaulti file1 --ask-vault-pass # If you want to specify the password on the CLI\nvaulti file1 --ask-vault-pass --vault-id mylabel@prompt # You can also specify vault ids\nvaulti file1 -r # Prints the output, doesn't let you edit. Useful for setting up custom git textconv, etc.\n```\n\nSee `vaulti -h` for more parameters.\n\n## About\n\n### General\n\nThis utility opens an editor where the encrypted variables have been decrypted for you!\n\nThe previously encrypted variables are indicated with a special tag, `!ENCRYPT`.\n\nYou can use the standard ansible methods of defining a vault password or vault password file, like `--ask-vault-pass` parameter,\n`ANSIBLE_VAULT_PASSWORD_FILE` environment variable and `--vault-id`.\n\nIt gives you the ability to:\n\n- Add or remove the `!ENCRYPT` tags as you wish, and it will encrypt or decrypt it for you.\n- Read, edit and encrypt block scalars if you need to include newlines (`|`, `>`, `|-`, etc.), which can be useful when you want to encrypt client certs, private keys or other multi-line values\n- Read and edit different vault ids in the same file\n- Swap a variable to be encrypted by a different vault-id\n\nThere are some quality of life features built in, such as:\n\n- if you edit the file to some invalid yaml, you'll get the chance to re-open the file and try again\n- ditto if you try to encrypt with a vault id that you didn't load when starting\n- if you comment out a line while it is decrypted, it will not be reencrypted, but it will produce a warning.\n\nVariable files that could not be decrypted for whatever reason, get a tag indicating the problem, but is left untouched after exiting.\nThe list of tags, both for success and failure, are currently:\n\n- `!ENCRYPT` : Variables that have been decrypted, and will be reencrypted when you close the editor\n- `!VAULT_FORMAT_ERROR` : Variables that could not be parsed due to ansible-vault rejecting the format. It will revert to the original `!vault` tag/value untouched after you close the editor.\n- `!UNKNOWN_VAULT_ID_LABEL` : Variables that could not be decrypted, most likely because you did not load/specify the relevant vault id. It will revert to the original `!vault` tag/value untouched after you close the editor.\n- `!COULD_NOT_DECRYPT` : Variables that could not be decrypted, probably because you specified the wrong password. It will revert to the original `!vault` tag/value untouched after you close the editor.\n- `![any tag]:[label]`, for example `!ENCRYPT:foo`: Indicates that this value was decrypted with a specific vault-id label.\n\n\n\n### Vault ids\n\nSecrets decrypted with the non-default ID will be shown in the tag as `!ENCRYPT:mylabel`. You can also set these labels yourself, as long as \nyou actually loaded the relevant vault-id when starting the utility.\n\n**WARNING**: The labels are there to help *you* when prompted, but ansible-vault will try all of the keys when decrypting no matter what.\nSo if you have two vault-ids, but you swap the passwords on the prompt, it will still decrypt just fine. However, when you save and quit,\nnow you'll encrypt the variables with the swapped passwords instead, which might lead to confusion.\n\n\n## Example\n\nThe dists have been published to PyPi, you can easily install it with `pip install vaulti_ansible`.\n\nAlternatively, you can clone this repo and use another installation method:\n\n```shell\n# You can test this by cloning the repo, cd into it\ngit clone https://github.com/oveee92/vaulti.git && cd vaulti\n\n# then EITHER install it with pip to get it installed into your PATH and as a python module\npip install .\nvaulti example/example_data.yml\n# OR put it somewhere in the PATH yourself\ncp .src/vaulti_ansible/vaulti.py ~/.local/bin/vaulti\nvaulti example/example_data.yml\n# OR just use it directly without \"installing\" it\n./src/vaulti_ansible/vaulti.py example/example_data.yml\n\n```\n\nThen you can set up and use it\n\n```shell\n# If you want to use a password file, you can set it as a variable\nexport ANSIBLE_VAULT_PASSWORD_FILE=example/.default_vault_pass.txt\n# OR specify it on the command line\nvaulti example/example_data.yml --vault-password-file example/.default_vault_pass.txt\n\n# To see the variables encrypted with the foo vault ID, load it too, either being prompted for the password, or referring to a file\nvaulti example/example_data.yml --vault-id foo@prompt\nvaulti example/example_data.yml --vault-id foo@example/.foo_vault_pass.txt\n\n# Make some changes to existing variables, create some new ones or remove some tags\n# Save and quit, then open it regularly to see what changed, or just run git diff to see what happened\ngit diff example_encrypted_data.yaml\n```\n\n## Why this exists\n\nThe standard `ansible-vault` works fine for encrypting/decrypting/editing whole files, but there are times you don't want to encrypt entire files; for example:\n\nIf you use AWX/AAP, having vault-encrypted files is a bit difficult; you either have to\n\n- include the vault password in whichever container/Execution environment you are running the playbooks (therefore requiring a custom container image), or\n- decrypt the file when syncing the inventory (making all your secrets plaintext for those with high enough access in AWX)\n\nAdditionally, if your control repo is getting large, with lots of host vars, group vars and roles, and you want to find out where certain variables are defined,\nyou won't be able to search full vault-encrypted files easily, since all the keys are also encrypted.\n\nSo then you try inline encryption, which solves pretty much all of these problems, but using it with `ansible-vault edit <file>` is no longer possible...\nyou have to do something like this instead:\n\n```shell\n## To encrypt:\nansible-vault encrypt_string # <enter>\nSomePasswordOrSomething # <Ctrl-D>, NOT <enter> unless you need the newline encrypted too\n# Then copy the output into your yaml file, making sure the indentation is still ok\n\n## To edit:\n# Encrypt a new string and replace it.\n\n## To decrypt:\nansible -i the/relevant/inventory the-relevant-host -m debug -a \"var=TheRelevantVariable\"\n```\n\nNot really easy to remember the encrypt and decrypt steps, pretty error-prone and requires you to actually run something with ansible, putting the variable\nsomewhere where it will actually be read (hostvars or groupvars). It is *much* easier to just open the decrypted content and edit it directly.\n\n\n## Why you should NOT use this\n\nI am a sysadmin by trade, not really a professional programmer, and the quality of the code might reflect that. It is getting better over time,\nbut there may still be edge cases where strange things could happen to the file you are editing. It isn't likely, and I've used it without issue\nfor some time, but if you don't have your files in a git repo with the ability to revert files easily, please dont use this just yet (or, better,\njust initialize a git repo first! If you need this utility, it's probably time for version control anyway)\n\nAlso, if you try to change the yaml tags to or from the \"invalid\" tags, like `!COULD_NOT_DECRYPT`, when editing, you'll probably end up with unencrypted\nor even broken variables in your file. Stick to adding or removing the `!ENCRYPT` tags and their labels only, for the full experience.\n\n## Caveats\n\nSince it uses the fantastic (yet sparsely documented) `ruamel.yaml`, and the yaml spec is pretty extensive, this utility does\nmake some \"non-negotiable\" changes to your files that you should be aware of, that happens when we load and parse the yaml data:\n\n- Indentation for your multiline strings will always end up with a fixed (default two) spaces relative to the variable it belongs to;\n  i.e. not the 10 spaces indented or whatever the default is from the `ansible-vault encrypt_string` output. This is good for consistency, but it does mean that the indentation\n  of your inline-encrypted variables will probably change the first time you use this, if you've previously used `ansible-vault encrypt_string` to generate the encrypted strings.\n  If you don't change the decrypted value, it should remain the same though, except for the indent change.\n- Extra whitespaces will be removed whereever it is found (for example `key:  value` -> `key: value`)\n\nAlso, there are a few \"opinionated\" things I've hardcoded, which are relatively easy to comment out or change in `setup_yaml()` if you wish it.\n\n- Header (`---`) and footer (`...`) will be added automatically to the variable file if it doesn't exist.\n- An indent equals two spaces\n- The hyphen starting each list items is indented, not inline with the parent key\n- An extra newline is added below the ansible-vault output, for readability.\n- No automatic line breaks for long values.\n\nFinally, a word on diffs. The utility revolves around decrypting and reencrypting the variables, which means that every time you open a file with it, the\nencrypted string actually changes (different salt for each reencrypt). Part of the utility is therefore dedicated to looping through the re-encrypted file, comparing it with\nthe original decrypted data, and preferring the old encrypted string if the actual decrypted value hasn't changed. That means that any git diff produced by these changes will\nusually only involve the relevant changed variables, but it is a \"best effort\" process. If you change the number encrypted variables in a list, the items\nwhose list index was changed will be re-encrypted with a new salt, since the original value cannot be found. Same goes for any variables where you change\nthe key name. Create the key/entry with a regular editor first if this is important to you.\n\n## Dependencies\n\nWon't put the dependencies in the `pyproject.toml` file for now, since with Ansible, sometimes you\nwant ansible-core on a specific version to keep a consistent execution environment. Any mention of\nthe required libraries will make pip upgrade `ansible` and `ansible-core` packages even if the\nrequirements don't make it necessary.\n\nHaving to use `--no-deps` for installing this tool is just asking for trouble.\n\nDependencies are:\n\n```\n# We're using typing classes from Python3.9, and __future__ annotations is not not available before python 3.7.\n# Since ansible seems to skip 3.7, let's just say 3.8. Might work with 3.7, if you are using that for some reason.\npython>=3.8 \n\nruamel.yaml>=0.16.6 # Won't work before this version due to TaggedScalar changes\nansible>=2.4.0.0 # Won't work for older versions due to pycrypto\n```\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Utility for Ansible Vault inline-encrypted variables",
    "version": "0.1.1",
    "project_urls": {
        "Homepage": "https://github.com/oveee92/vaulti",
        "Issues": "https://github.com/oveee92/vaulti/issues",
        "Repository": "https://github.com/oveee92/vaulti"
    },
    "split_keywords": [
        "ansible",
        " ansible-vault"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "1921e34154e62c1b1992dc177d19cf98a317aadae14198d6e5dc4aaf91bd3864",
                "md5": "9b37a30eddad78d30c302ccf45b95384",
                "sha256": "78a2e46946e7d7d7c90681b9a326dee5fa9a7cad46574e69d65f8cd673a97bcf"
            },
            "downloads": -1,
            "filename": "vaulti_ansible-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "9b37a30eddad78d30c302ccf45b95384",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 15620,
            "upload_time": "2024-09-11T17:53:17",
            "upload_time_iso_8601": "2024-09-11T17:53:17.297428Z",
            "url": "https://files.pythonhosted.org/packages/19/21/e34154e62c1b1992dc177d19cf98a317aadae14198d6e5dc4aaf91bd3864/vaulti_ansible-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "ca119f8955f5f987edd6d55f4961c1caf8c0fef16f9fb170439f4c56000ff4f2",
                "md5": "704d8842a29efbb5020a24190385699d",
                "sha256": "c8e42b76693fdcb993340505d27d0aa183a7ab2eb0776beee394b0e233d7de07"
            },
            "downloads": -1,
            "filename": "vaulti_ansible-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "704d8842a29efbb5020a24190385699d",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 16446,
            "upload_time": "2024-09-11T17:53:19",
            "upload_time_iso_8601": "2024-09-11T17:53:19.346836Z",
            "url": "https://files.pythonhosted.org/packages/ca/11/9f8955f5f987edd6d55f4961c1caf8c0fef16f9fb170439f4c56000ff4f2/vaulti_ansible-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-09-11 17:53:19",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "oveee92",
    "github_project": "vaulti",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "vaulti-ansible"
}
        
Elapsed time: 0.58506s