ansible-collections / community.general

Ansible Community General Collection
https://galaxy.ansible.com/ui/repo/published/community/general/
GNU General Public License v3.0
818 stars 1.5k forks source link

onepassword lookup plugin - get filecontents from item-type document #7246

Closed ogaida closed 10 months ago

ogaida commented 1 year ago

Summary

Dear Developers,

I tried to get the filecontent with the onepassword lookup plugin. I had a look into the python script and it seems that there is no implementation for that kind of item yet. I would like to use it, because i have some secrets like private keys inside my 1password, which i want to deploy via ansible.

with the op_cli_v2 i would do a:

op read op://<vault>/<document-name>/<file-name>

to get the content.

Thanks in Advance and best regards Olli

Issue Type

Feature Idea

Component Name

community.general.onepassword

Additional Information

- name: Retrieve filecontent for myprivate.key when already signed in to 1Password
  ansible.builtin.debug:
    var: lookup('community.general.onepassword', 'myprivate.key', vault='myvault', type='document', filename='myprivate.key')

Code of Conduct

ansibullbot commented 1 year ago

Files identified in the description:

If these files are incorrect, please update the component name section of the description or use the !component bot command.

click here for bot help

ansibullbot commented 1 year ago

cc @azenk @samdoran @scottsb click here for bot help

samdoran commented 1 year ago

There was a PR (https://github.com/ansible/ansible/pull/51520) to create a new onepassword_doc lookup a while ago but it didn't get finished.

I still think it should be a separate lookup plugin rather than a type toggle. It can use the existing classes in onepassword.py.

samdoran commented 1 year ago

I think the interface for onepassword_doc could be like this:

This should use the op document get command. That is a better interface than op read since it doesn't require vault or filename be specified.

"{{ lookup('community.general.onepassword_doc', 'document name') }}"
samdoran commented 1 year ago

Since this is a new plugin, it should only support op CLI v2. That will make things much easier.

ogaida commented 1 year ago

I use it like this op document get myDocumentName --vault myVaultName and op cli v2 output the file content to stdout.

samdoran commented 1 year ago

That's exactly the command the plugin should run, capturing the output and returning it. Do you want to work on implementing this? Otherwise I would probably start on it.

ogaida commented 1 year ago

It would be very very nice if you could do this, my python knowledge is not so great. And unfortunately, I don't understand the source code of the existing Ansible module very well. Especially the part, where the module interact with the op_cli it is not clear for me. Thanks in advance samdoran!

samdoran commented 1 year ago

Sure thing!

ogaida commented 11 months ago

Hello Sam,

did you find time to do something on that topic? It would be great.

best regards Oliver

samdoran commented 11 months ago

Not yet. On my list.

samdoran commented 11 months ago

I started working on this Friday. I'll have a draft PR up this week.

VirtualWolf commented 11 months ago

Would this also work for files attached to regular items (like a secure note for example)? My use-case is similar to @ogaida but I've got some Cloudflare SSL origin certificates stored as files attached to a secure note (as opposed to the specific "Document" type of item). With op I can read the content quite happily:

$ op read "op://VMs/Cloudflare Origin Certificates/example.com.crt"
-----BEGIN CERTIFICATE-----
[...]
-----END CERTIFICATE-----

But running the current community.general.onepassword lookup just returns an empty string:

- name: Testing
  hosts: localhost
  gather_facts: false
  tasks:
    - ansible.builtin.debug:
        msg: "{{ lookup('community.general.onepassword', 'Cloudflare Origin Certificates', field='example.com.crt') }}"

$ ansible-playbook playbooks/test.yml 

PLAY [Testing] **********************************************************************************************

TASK [ansible.builtin.debug] ********************************************************************************
ok: [localhost] => {
    "msg": ""
}

PLAY RECAP **************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   
ogaida commented 11 months ago

@samdoran : I have copied your changed files from the pr. And it is working for me. I did export OP_SERVICE_ACCOUNT_TOKEN and then run:

ansible localhost -m shell -a "echo \"{{ lookup('community.general.onepassword_doc', 'my_document_name', vault='my_vault') }}\""

very nice!

samdoran commented 11 months ago

@VirtualWolf onepassword_doc will only work for documents, not other item types.

Getting an attached file is actually a bit complicated and there isn't a way to do that with the lookup plugins. First, you need to get the item with the attached file. Then you need to get the content_path from the files. Lastly, you need to construct a URL to pass to op read.

As an example, for this Secure Note with an attached file:

Secure Note with file attached ``` > op item get "Example Note" --format json { "id": "qkzi2x343bdted3pllgotbp2r4", "title": "Example Note", "version": 1, "vault": { "id": "stpebbaccrq72xulgouxsk4p7y", "name": "Personal" }, "category": "SECURE_NOTE", "last_edited_by": "LSGPJERUYBH7BFPHMZ2KKGL6AU", "created_at": "2023-11-09T16:10:37Z", "updated_at": "2023-11-09T16:10:37Z", "additional_information": "Message stored in the note", "sections": [ { "id": "add more" } ], "fields": [ { "id": "notesPlain", "type": "STRING", "purpose": "NOTES", "label": "notesPlain", "value": "Message stored in the note", "reference": "op://Personal/Example Note/notesPlain" } ], "files": [ { "id": "irkebpghapv7jdugas4eepu3aq", "name": "Google.pem", "size": 4994, "content_path": "/v1/vaults/stpebbaccrq72xulgouxsk4p7y/items/qkzi2x343bdted3pllgotbp2r4/files/irkebpghapv7jdugas4eepu3aq/content", "section": { "id": "add more" } } ] } ```

The command to then get the file contents is

op read op://stpebbaccrq72xulgouxsk4p7y/qkzi2x343bdted3pllgotbp2r4/irkebpghapv7jdugas4eepu3aq
# or
op read op://Personal/"Example Note"/Google.pem

If you are signed into to op, you could use the pipe lookup to run the command directly.

- hosts: localhost
  tasks:
    - debug:
        msg: "{{ data }}"
      vars:
        data: "{{ lookup('pipe', 'op read op://Personal/Example\\ Note/Google.pem') }}"

I would suggest moving those file attachments to Documents. Otherwise, we would probably need to create a onepassword_read lookup plugin.

VirtualWolf commented 11 months ago

Ahhh, very interesting. Many thanks for the example!

The main reason I wanted to have a single note with several files attached was so all the certificates were just in one related place rather than have multiple documents floating around freely. :)