ansible / awx

AWX provides a web-based user interface, REST API, and task engine built on top of Ansible. It is one of the upstream projects for Red Hat Ansible Automation Platform.
Other
13.54k stars 3.35k forks source link

Support vault encrypted secrets in the inventory source #223

Closed dzeban closed 5 years ago

dzeban commented 6 years ago
ISSUE TYPE
COMPONENT NAME
SUMMARY

AWX inventory source can't handle Vault encrypted secrets for the simple ini-like inventory ("Sourced from the project" in the UI).

For example, I have an ini-like inventory and a few variables in the group_vars that are encrypted with Ansible Vault (like in this example repo). When I add this inventory source and try to sync it I get the following error:

2017-09-20 11:45:09,104 INFO     awx.main.commands.inventory_import Updating inventory 2: Production
2017-09-20 11:45:09,114 DEBUG    awx.main.commands.inventory_import Using backported ansible-inventory module: /usr/lib/python2.7/site-packages/awx/plugins/ansible_inventory/backport.py
2017-09-20 11:45:09,114 INFO     awx.main.commands.inventory_import Reading Ansible inventory source: /var/lib/awx/projects/_6__myproj/inventory
2017-09-20 11:45:09,114 INFO     awx.main.commands.inventory_import Command: ['/usr/lib/python2.7/site-packages/awx/plugins/ansible_inventory/backport.py', '-i', '/var/lib/awx/projects/_6__myproj/inventory']
Traceback (most recent call last):
  File "/usr/bin/awx-manage", line 9, in <module>
    load_entry_point('awx==1.0.0.487', 'console_scripts', 'awx-manage')()
  File "/usr/lib/python2.7/site-packages/awx/__init__.py", line 107, in manage
    execute_from_command_line(sys.argv)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
    utility.execute()
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/__init__.py", line 346, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/base.py", line 661, in handle
    return self.handle_noargs(**options)
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 956, in handle_noargs
    self.is_custom)
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 211, in load_inventory_source
    is_custom=is_custom).load()
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 180, in load
    data = self.command_to_json(base_args + ['--list'])
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 163, in command_to_json
    self.method, proc.returncode, stdout, stderr))
RuntimeError: ansible-inventory backport failed (rc=1) with stdout:

stderr:
ERROR! Decryption failed on /var/lib/awx/projects/_6__myproj/inventory/group_vars/aws/credentials.yml

You can't set Vault credential for the inventory source - trying to add it via UI shows "NO CREDENTIALS HAVE BEEN CREATED" window. Even if you set the Vault credential by typing its name in the input field it's still not used - I get the same error.

ENVIRONMENT
ADDITIONAL INFORMATION

I'll gladly help with fixing this if somebody would give me some hints. I've tried to hack the patch by myself but I can't figure out how to pass vault credential from RunInventoryUpdate task to the inventory_import.py management command.

wenottingham commented 6 years ago

This is https://github.com/ansible/awx/issues/137. The issue is that the ansible-inventory tool doesn't support prompting... until a variant of that does, we can't do much here.

dzeban commented 6 years ago

@wenottingham Thanks, it's related! What's good is that ansible-inventory tool understands Vault password files:

$ ~/dev/ansible-inventory-backport/backport.py --list
ERROR! Decryption failed on /home/avd/dev/example-ansible/inventory/group_vars/group1
$ ~/dev/ansible-inventory-backport/backport.py --vault-password-file=.vaultpass --list
{
    "_meta": {
        "hostvars": {
<snip>
}
}

Isn't there a way to generate a vault password file and supply it to the ansible-inventory tool? As I saw in the sources there is a private data dir that is created on the inventory update job run. Maybe we can render vault password file there and pass it to the ansible-inventory?

wenottingham commented 6 years ago

Vault passwords are (currently) passed in AWX by prompting via pexpect, not by the commandline... which means that --ask-vault-pass may work.

wenottingham commented 6 years ago

So if that does work, you'd then:

dzeban commented 6 years ago

Indeed, --ask-vault-pass could've worked, but when I set ANSIBLE_ASK_VAULT_PASS env var in the inventory source, sync job hangs on the prompt indefinitely:

2017-09-20 17:20:44,725 INFO     awx.main.commands.inventory_import Updating inventory 2: Production
2017-09-20 17:20:44,736 DEBUG    awx.main.commands.inventory_import Using backported ansible-inventory module: /usr/lib/python2.7/site-packages/awx/plugins/ansible_inventory/backport.py
2017-09-20 17:20:44,736 INFO     awx.main.commands.inventory_import Reading Ansible inventory source: /var/lib/awx/projects/_6__myproj/inventory
2017-09-20 17:20:44,736 INFO     awx.main.commands.inventory_import Command: ['/usr/lib/python2.7/site-packages/awx/plugins/ansible_inventory/backport.py', '-i', '/var/lib/awx/projects/_6__myproj/inventory']
Vault password: 

I can't find a way to pass the vault password to the prompt. "Credential" field in the UI can't find my vault credential and even if I type its name by hand it's still not passed. I can verify in the API that my inventory source has vault credential

GET /api/v2/inventory_sources/7/
{
    "id": 7,
    "type": "inventory_source",
    ...
    "summary_fields": {
        ...
        "credential": {
            "id": 4,
            "name": "Vault cred",
            "description": "",
            "kind": "vault",
            "cloud": false,
            "credential_type_id": 3
        },
        ...
    },
    ...
    "source_vars": "---\nANSIBLE_ASK_VAULT_PASS: 1",
    "credential": 4,
    ...
}

So I still don't understand how to pass vault password to the inventory source: setting credential for the inventory source doesn't seem to work and asking vault pass hangs on the prompt.

wenottingham commented 6 years ago

Sorry, I wasn't clear above in https://github.com/ansible/awx/issues/223#issuecomment-330921091 - this is changes to awx itself that would need to be done in the code.

dzeban commented 6 years ago

I've checked this with the newest versions (non-backport version of ansible-inventory), here is how it's looking:

2017-09-20 18:04:09,549 INFO     awx.main.commands.inventory_import Updating inventory 2: example inventory
2017-09-20 18:04:09,568 DEBUG    awx.main.commands.inventory_import Using system install of ansible-inventory CLI: /usr/bin/ansible-inventory
2017-09-20 18:04:09,569 INFO     awx.main.commands.inventory_import Reading Ansible inventory source: /var/lib/awx/projects/_6__example/inventory
Traceback (most recent call last):
  File "/usr/bin/awx-manage", line 9, in <module>
    load_entry_point('awx==1.0.0.513', 'console_scripts', 'awx-manage')()
  File "/usr/lib/python2.7/site-packages/awx/__init__.py", line 107, in manage
    execute_from_command_line(sys.argv)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
    utility.execute()
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/__init__.py", line 346, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/var/lib/awx/venv/awx/lib/python2.7/site-packages/django/core/management/base.py", line 661, in handle
    return self.handle_noargs(**options)
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 955, in handle_noargs
    self.is_custom)
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 210, in load_inventory_source
    is_custom=is_custom).load()
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 179, in load
    data = self.command_to_json(base_args + ['--list'])
  File "/usr/lib/python2.7/site-packages/awx/main/management/commands/inventory_import.py", line 163, in command_to_json
    self.method, proc.returncode, stdout, stderr))
RuntimeError: ansible-inventory failed (rc=4) with stdout:

stderr:
ERROR! Attempting to decrypt but no vault secrets found

AWX version: 1.0.0.513 Ansible version: 2.4.0.0

AlanCoding commented 6 years ago

If you look in tasks.py, you can see some existing cases where we utilize --ask-vault-pass. It will probably be fairly easy to extend this to inventory updates, although we might need a schema change to attach a vault credential (most consistent with existing use).

But even if we do that, we'll need to equip the inventory import command to accept the flag, and then do its own prompting, so it can then go on to pass it to the ansible-inventory invocation.

This is extra complication strictly due to the implementation details. I have wanted to break up the inventory import into 2 parts. First, call ansible-inventory to get the JSON content (using run_pexpect from tasks.py), then send that content into the command to load into database. When I was restructuring the code, I had this end-goal in mind. If we did this first, it would avoid the need to manage a new flag for the inventory import command.

naisanza commented 6 years ago

Does Tower have the feature, to use Ansible Vault?

AlanCoding commented 6 years ago

There are plenty of things in AWX that use vault credentials. It just needs extra work to implement it for SCM inventory sources. This is a good feature request.

pmozdzynski commented 6 years ago

according to the documentation : http://docs.ansible.com/ansible/latest/playbooks_vault.html you could potentially add en environment variable, e.g. ANSIBLE_VAULT_PASSWORD_FILE=~/.vault_pass.txt and Ansible will automatically search for the password in that file. it is not ideal and I guess awx tower should have that feature added.

AlanCoding commented 6 years ago

I present to all of you - my inventory vars example from which I will demo this new feature.

https://github.com/AlanCoding/Ansible-inventory-file-examples/tree/master/vault

This is going through the --ask-vault-pass mechanism, which is a pattern I will maintain parity with. The rest of the data model / command / task changes seem relatively straightforward to me.

naisanza commented 6 years ago

@AlanCoding How about for playbooks that have passwords that I would like to be encrypted.

And how do you pass --ask-vault-pass in AWX?

For example:

  - name: dokuwiki conf
    debconf:
      name: dokuwiki
      question: dokuwiki/wiki/password
      vtype: password
      # change to ansible-vault
      value: passwordtobeencrypted

Or how to use an Ansible Vault encrypted playbook with AWX? Is that even possible?

AlanCoding commented 6 years ago

You can put encrypted content in your playbook directory. There are several ways to do this, like encrypting your vars file in a role. You can encrypt single variables inside of the YAML, and have Ansible vault decrypt it.

If this encrypted content is inside of the source control that contains your playbook, then you would associate the vault credential with your job template. This change is to enable the same thing for the source control that is your inventory source. It would be sensible to use the same vault credential for both, but this is not required.

naisanza commented 6 years ago

@AlanCoding I don't think I understand what you mean.

In AWX, when creating a Job Template, the credential used is for accessing the Machine (see below) and not for the Source Control:

screenshot from 2017-09-30 16-26-09

And the SCM Credential used for the Project is used to access the SCM machine, not for accessing Ansible Vault (see below):

screenshot from 2017-09-30 16-29-53

There's only one place under Credentials that let me create a Vault password, but no where in a Job Template to use it:

screenshot from 2017-09-30 16-31-44

AlanCoding commented 6 years ago

You can go to /api/v2/job_templates/, and you should see that every job template has a related vault_credential field. The way that the UI handles it is to lump it into the CREDENTIAL selector, and you can select the vault credential in addition to other cloud/machine credentials.

screen shot 2017-09-30 at 6 16 19 pm

If you add the vault credential (again, in addition to any other credentials you have), then check the API, you should use that the UI set it as the vault_credential related field.

naisanza commented 6 years ago

@AlanCoding ah I see. It wasn't intuitive at first

naisanza commented 6 years ago

@AlanCoding going off your example https://github.com/AlanCoding/Ansible-inventory-file-examples/blob/master/vault/file_vars/group_vars/unencrypted

If I wanted to encrypt the password in value: password, is it correct to encrypt a file that contains just password or value: password?

  - name: dokuwiki conf
    debconf:
      name: dokuwiki
      question: dokuwiki/wiki/password
      vtype: password
      value: password

Encrypting password:

root@awx-world0:~# cat unencrypted 
password
root@awx-world0:~# ansible-vault encrypt_string unencrypted  --name 'value'
New Vault password: 
Confirm New Vault password: 
value: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          63383732373761336164313836316666396666383064633339666132633465653561633537303362
          6631666562393966646433626233323162353461363766340a366339666638346536616338653332
          37386431666564376436623566623639316538323336313234636463656536393065363830626431
          3332343634393539650a636363663438643937333638663231636363303334303762353563663535
          3937
Encryption successful

Is this correct? I just put that into the playbook?


  - name: dokuwiki conf
    debconf:
      name: dokuwiki
      question: dokuwiki/wiki/password
      vtype: password
      value: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          63383732373761336164313836316666396666383064633339666132633465653561633537303362
          6631666562393966646433626233323162353461363766340a366339666638346536616338653332
          37386431666564376436623566623639316538323336313234636463656536393065363830626431
          3332343634393539650a636363663438643937333638663231636363303334303762353563663535
          3937
AlanCoding commented 6 years ago

Yes, you are using the correct officially-documented steps for a vaulted value inside of ansible-playbook YAML.

http://docs.ansible.com/ansible/2.4/vault.html#use-encrypt-string-to-create-encrypted-variables-to-embed-in-yaml

Contrary to that, my example did whole-file encryption, which has just a slight syntax marker different.

This should work in tasks or other places, provided you give the vault credential to the job template. Using it in inventory imports is the new thing here. My example was 1 use case, but there are more that would be valuable to check. I'm interested in trying a YAML inventory file and seeing if vaulted single values will be decrypted from that.

AlanCoding commented 6 years ago

Raised issue in Ansible core for use of a single vaulted value inside of YAML inventory file. Have not tried other inventory file types.

https://github.com/ansible/ansible/issues/31141

AlanCoding commented 6 years ago

not merging right now, as solution will be reformulated to jive with https://github.com/ansible/awx/issues/352

otdouglasm commented 6 years ago

(In my RedHat support case, they recommended I provide my use case here.)

We're in the process of migrating from Tower 2.4.5 to 3.2.1. What I really want is the same exact functionality as Tower 2.4.5's tower-manage inventory_import, since it simply ignored vaulted variables and kept variables at the level at which they were defined. It wasn't integrated into Tower, but it worked well enough.

Now, Tower 3.2.1 fails outright if it can't decrypt vaulted files, and puts all group_vars at the host-level, which is a big step backwards. I know I can pass ANSIBLE_VAULT_PASSWORD_FILE in environment variables of the inventory source, but it imports variables in plaintext, which we obviously don't want.

Using the UI to manually manage our large inventories would be a nightmare (time-consuming, error-prone, no version control, no rollback, etc).

If we use a source from project, we can't have any vaulted files, which means we would need to maintain two versions of each inventory (one without vaulted files used for importing, and one with vaulted files used in job templates).

If we use a custom inventory script, we have to manually parse inventory files, or use external sources which we don't have.

wenottingham commented 6 years ago

@otdouglasm so, I could see three different potential behaviors, some of which can coexist:

The first two of these should be relatively practical... the third seems much more complex.

otdouglasm commented 6 years ago

@wenottingham I agree, and we currently only have a need for the first behavior, and definitely wouldn't want the second behavior (at least I can't think of any cases at the moment).

I imagine the third behavior might be useful for executing ad-hoc commands on a group of hosts that cannot use the same Machine credentials. By specifying vault credentials on an ad-hoc command, it could select the Machine credentials dynamically if ansible_user/password were imported as vaulted/secured host vars. This would be "nice to have" in environments with several authentication domains, but certainly not a requirement.

hassek commented 6 years ago

Is there any possible work around if you currently have vaulted variables in your sourced inventory?

As of now, I was able to configure the vault_password_file in the ansible.cfg file but it's quite an ugly hack, at least it works for the moment.

otdouglasm commented 6 years ago

@hassek As you pointed out, there are ways to provide Tower with the vault password so that it can decrypt vaulted variables during synchronization. Another method is to set ANSIBLE_VAULT_PASSWORD_FILE in the inventory source's environment variables.

But the problem with any of these methods is that the decrypted variables will show up in plain text in host vars, which we don't want (otherwise, they wouldn't be encrypted to begin with).

The best workaround in my case is to maintain a separate directory structure which contains no vaulted files.

For example, if you have an inventory source pointing to my_project/inventory_file in this project directory:

my_project/
    group_vars/
        vaulted_file.yml
        unvaulted_file.yml
    inventory_file

Create a new sub-directory, and link ONLY to files that are not vaulted:

my_project/
    group_vars/
        vaulted_file.yml
        unvaulted_file.yml
    inventories/
        group_vars/
            unvaulted_file.yml -> ../../group_vars/unvaulted_file.yml
        inventory_file -> ../inventory_file
    inventory_file

Then point the inventory source to my_project/inventories/inventory_file instead of my_project/inventory_file. Since there are no vaulted files to decrypt, the synchronization will succeed without a vault password.

hassek commented 6 years ago

@otdouglasm I didn't knew about them showing up in plain text on _hostvars, thanks for pointing that out.

I do own many complex inventories already for production, qa and dev and links have proven to be a bad way to switch between environments (that's why I am so excited about ansible tower supporting them now). But I get the point is to let the inventory sync succeed and then use vaulted files for the playbooks only. I can work with that.

Bests!

kkolk commented 6 years ago

So I fixed it so it could decrypt it, accepting it would show up in host_vars and it's decrypting but still not working. Mine every time it hits one of my encrypted values, throws this message in the logs:

ERROR! Unexpected Exception, this is probably a bug: Cannot json serialize SECRETPASS

With SECRETPASS being the decrypted value.

HalisCz commented 6 years ago

Is there any conclusion or roadmap so far? I need central machine running ansible playbooks till end of January, and I prefer ansible awx, but vault_pass unsupport is a no-go for my use case, so I want to know if I should wait or switch to Jenkins

xoxys commented 6 years ago

@HalisCz @hassek You can bypass this issue using a custom inventory script which parse the project inventory file. I use this one https://gist.github.com/sivel/3c0745243787b9899486 For me, this workaround fit my uses.

You can customize the script and use somethin like ANSIBLE_INVENTORY = "/var/lib/awx/projects/YOUR_PROJECT/inventory instead of sys.argv[1]]

iJebus commented 6 years ago

@otdouglasm's workaround doesn't work for me but I suspect that's due to using Ansible's _best practice_ of referring to vault encrypted variables from variables 🤦‍♂️.

What's the actual implementation with the vault_password_file method? I'm presuming that it means I'll have to locally bake the awx docker image with the vault password file included, or is that mistaken?

lucasreed commented 6 years ago

@AlanCoding just clarifying that this is being blocked by https://github.com/ansible/ansible/issues/31141

Is that accurate?

AlanCoding commented 6 years ago

I don't think that issue, or any other open Ansible core issue, is blocking this.

The real issue is that the work done in #328 is obsolete because of what changed in #595. The inventory source doesn't need any model changes on itself, just needs to surface the related credentials, and make a host of supporting API validation changes, and reference the correct vault credential list inside of tasks.py.

I'm not quite sure when enough resources will be available to get this done. Nonetheless, I think we are all agreed that this should be done. A notable change in its scope is that the feature should really support multiple vault credentials from the get-go.

wenottingham commented 6 years ago

That being said, the 'simple' implementation as described above would lead to vaulted secrets being stored in plaintext in the API after import, which may not be desirable.

AlanCoding commented 6 years ago

Now we have the multi-vault & multi-credential blockers out of the way. With the linked PR, I pushed up the inventory source credential to the base model's plural credentials field. Now we have a place to put vault credentials in the model.

@wenottingham in terms of keeping vaulted secrets hidden, we would need to start off with a feature request to do something different with ansible-inventory. I would imagine this as either:

I really do not like the first option, and while the 2nd option would be fine by me, it might not go over well with Ansible core. I'm positive that the changes there would not be limited to ansible-inventory, and will percolate deeper into their code base.

As a stop-gap, I advocate for a well-documented version of the 'simple' implementation, where all variables on inventory / group / host remain plaintext.

There's still a use-case where this helps security. It would offer a way to move those secrets through source control (which custom credentials won't do) in an encrypted form into AWX.

wenottingham commented 6 years ago

I don't think the 'simple' implementation can ever be the default. It's a rather obvious information leak. If we want to consider it as an option (and if it's off, as the default, we ignore the vaulted variables without failing), we could.

AlanCoding commented 6 years ago

we ignore the vaulted variables without failing

It seems like that would also have to start off as a new request to Ansible core. At a quick glance, I don't see any kind of configurable you can set to pass over the vault errors.

https://github.com/ansible/ansible/blob/060001b08d98969217156b2b696613ade44eb8c5/lib/ansible/parsing/vault/__init__.py#L698

AlanCoding commented 6 years ago

"import vaulted variables in a secure vaulted-way"

@wenottingham believe it or not, this is implemented and actually functional in #1337 now. I had anticipated on first filing a feature request from Ansible core, but then I discovered an easter egg with ansible-inventory --yaml option, that it will return the vaulted values as-is. The other side of it, passing our own inventory structure in a way that can be un-vaulted, was the other side of it, which also works.

This is really the best-case scenario for the implementation of this, because it involves writing no new encryption logic on our part, it just sends the encrypted content from one Ansible command onto the next Ansible command.

However, this comes at a cost. I was able to get the API to accept vault-laden YAML content, but this content is not yet consumable by the UI. There will be a significant testing burden for switching our core operations from JSON to YAML (remember unicode bugs?).

But that's not the most major blocker. It's hard to even understand what was intended by the --yaml option for ansible-inventory, and using this option would expose all inventory updates to its use. It does not just return YAML format instead of JSON. It changes the entire structure of the output to be like the --graph option, listing the apex group parents followed by children, meaning that children are repeated. This exposes us to a scaling problem like in https://github.com/ansible/ansible/issues/36431, but inside of memory. Extremely large outputs are generated for just 15 groups by my examples, and larger inventories would easily OOM this.

So we'll still need action from Ansible core. We need the vault behavior of the --yaml option with the normal output structure.

bcoca commented 6 years ago

FYI, the --yaml option is meant to be compatible with the 'yaml' inventory plugin, while the --json one is compatible with the 'script' inventory plugin.

AlanCoding commented 6 years ago

Alright @bcoca I think we're almost synced up on the expectation for ansible-inventory. The behavior I was relying on by using the --yaml flag will probably be counted as a bug by you.

Nonetheless, I still want that behavior, and I filed a PR at https://github.com/ansible/ansible/pull/36862 which adds an option for the behavior I'm looking for (specifically ansible-inventory delaying vault decryption, passing through the encrypted form). It fixes the (previously known) JSON decryption problem, but falls short of fixing the --yaml failure to decrypt, but I think I might be able to get that with a little help.

The reason I'm trying to jump into this quickly is because, while the AWX method for temporary handling of vault remains unclear, we will need this vault pass-through feature regardless of what solution we use for that. Our rollout would also be blocked if Ansible core did not have the ansible-inventory vault functionality working by the time that we tried to roll out the AWX feature (that looks like the next development cycle, but Ansible core releases take time too).

I had been getting very confused about the behavior of the vars managers. Here is the important distinction that I missed:

The pass-through kind of feature plays just fine with the vars plugin, but a pass-through kind of feature categorically cannot hope to work with the encrypted file example. Just fundamentally, the encryption obfuscates the keys of the variables that it defines, so you wouldn't know where to put the content inside of the namespace.

So we would have to be upfront that, whenever this feature gets working, it can only hope to pass-through single encrypted values, as opposed to encrypted vars files. We could still implement the original feature idea to decrypt any vault contents plaintext, but the aggregate complexity of all this is getting so much that I don't want to deal with that if it can be avoided.

bcoca commented 6 years ago

Yes, they are 2 diff features: vaulted files vs vaulted values, the former makes no sense in a 'passthrough' context, the latter does.

So I see ansible-inventory behaving in 1 of 2 ways:

I'm guessing this is attempting to support the use case in which user wants to import everything into tower but wants to keep vaulted things vaulted, but not use/move to tower's own encrypted facilities.

I'm not sure that is going to work with vaulted files, when it comes to vaulted values it probably will require a tower inventory plugin or have tower export a YAML inventory file.

AlanCoding commented 6 years ago

New attempt, given the feedback from prior approach https://github.com/ansible/ansible/pull/37029

If this is accepted, much more minor changes will be required on the AWX side. The content could be represented in the UI (by introducing a new "magic" string "!vault", similar to how we use "$encrypted$"). AWX would have to inspect each value as it exports its own inventory, and then it could probably return them through a vars plugin for playbook runs.

dhartford commented 6 years ago

Just want to make sure the 'vaulted files' versus the vaulted values do not get lost -- For our usecase, 'vaulted files' in the inventory/group_vars/all/ is critical need as we deploy the same application with the same keys to multiple target locations, each target location needing different vaulted key-values (username/password) per inventory/target location. The key is the same, but the 20+ values are different per target location.

In a larger scale deployment, keeping these in a vaulted file per inventory makes way more sense from a usability and maintainability point of view.

AlanCoding commented 6 years ago

@dhartford I'm not sure why your example necessitates the use of "vaulted files" (I will use this term for consistency now) as opposed to vaulted variables. Your project may contain inventory/group_vars/all.yml.

Here, I made an example and will push it to my examples repo

ansible-inventory -i scripts/vault/file_value/foobar.py --list --export --vault-id=alan@scripts/vault/passwords/password
{
    "_meta": {
        "hostvars": {
            "foobar": {}
        }
    }, 
    "all": {
        "children": [
            "ungrouped"
        ], 
        "vars": {
            "should_be_artemis_here": "artemis\n"
        }
    }, 
    "ungrouped": {
        "hosts": [
            "foobar"
        ]
    }
}

https://github.com/AlanCoding/Ansible-inventory-file-examples/tree/master/scripts/vault/file_value

Support for "vaulted files" is on the chopping block. It would require a lot of technical work and expose secrets while the problem seems completely solvable through vaulted vars.

tuxcrafter commented 6 years ago

I am using AWX 1.0.4.97 and I am new to AWX.

I am trying to use AWX to run my playbook that is is fully in an mercurial version repository (playbooks, inventory, roles etc)

I have a vault file ansible/group_vars/all/vault.yml with "$ANSIBLE_VAULT;1.1;AES256"

I configured a vault credential with the password, a machine credential with ssh private key.

When I try to run an template that has the vault and machine credentials I get:

ERROR! Attempting to decrypt but no vault secrets found

I am looking for assistance? Thank you.

jesusvazquez commented 6 years ago

I'm going to push this a little too! It would be nice to have this feature running.

I was thinking that a possible workaround could be setting up an inventory script that iterates through the inventory and the variables decripting each one of them and then override the inventory on each project update.

Have anyone attempted anything like this? Would it make any sense?

Regards.

bmalynovytch commented 6 years ago

I worked around this issue using some evil trick: I let AWX load all variable files except those that are vaulted, which are moved away in a different directory structure, when syncing inventory, and load the vaulted files in the playbook.

Here's my directory structure:

├── README
├── Vagrantfile
├── ansible.cfg
├── inventory
│   ├── group_vars
│   │   └── all
│   │       └── settings.yml
│   ├── my_inventory
│   ├── vagrant -> ../.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory
│   └── vault_group_vars
│       └── all
│           └── secrets.yml
├── playbook.yml
├── requirements.txt
├── roles
│   ├── ...
│   └── ...
└── tasks
    ├── late-variables-inclusions.yml
    └── sanity-checks.yml

Task file is loaded in playbook with:

    - import_tasks: "tasks/late-variables-inclusions.yml"
      tags: always
      check_mode: false
      delegate_to: localhost
      become: false
      run_once: true

Task file contains:

---
- name: Check which encrypted group_vars should be loaded
  stat:
  args:
    path: "inventory/vault_group_vars/{{ item }}"
  register: stat_vault_group_vars
  with_items: "{{ groups | list }}"

- name: Include encrypted group_vars
  include_vars:
  args:
    dir: "{{ playbook_dir ~ '/' ~ item.invocation.module_args.path }}"
  with_items: "{{ stat_vault_group_vars.results }}"
  when: item.stat.exists and item.stat.isdir | default(false)
cpbills commented 6 years ago

Assuming I could set 'ANSIBLE_VAULT_PASSWORD_FILE' in the 'Environment Variables' YAML/JSON field for adding inventory sourced from a project, where would AWX be looking for that file? Is the "suggestion" to add your ansible vault password file to your Ansible SCM controlled project, so that the docker image can see that file?

runtman commented 6 years ago

What is the deal here, is the workaround approved I see conflicting posts in this thread?

bmalynovytch commented 6 years ago

Well, the workaround I suggest allows to deal with the fact that AWX can't load encrypted variables when syncing inventory from SCM by removing the variables from the native directories (group_vars / host_vars) and loading them directly at runtime by a set of dedicated tasks, always run even in check mode. It works perfectly in several projects and is fully compatible with ansible-playbook in CLI.