Ansible Collection for 1Password Connect

1Password, updated πŸ•₯ 2023-03-18 18:15:24

1Password Connect Ansible Collection

The 1Password Connect collection contains modules that interact with your 1Password Connect deployment. The modules communicate with the 1Password Connect API to support Vault Item create/read/update/delete operations.

You can learn more about Secrets Automation and 1Password Connect on our website.

Table of Contents

Requirements

  • Python >= 3.6.0
  • 1Password Connect >= 1.0.0

Supported Ansible Versions

This collection has been tested against the following Ansible versions: * ansible-core: >=2.9, 2.11, 2.12 * ansible: >=4.0, <5.0

Installation

You can install the Ansible collection from Ansible Galaxy:

ansible-galaxy collection install onepassword.connect

Module Variables

All modules support the following variable definitions. You may either explicitly define the value on the task or let Ansible fallback to an environment variable to use the same value across all tasks.

Environment variables are ignored if the module variable is defined for a task.

| Module Variable | Environment Variable | Description | |----------------:|----------------------|-------------------------------------------------------------------------| | hostname | OP_CONNECT_HOST | URL of a 1Password Connect API Server | | token | OP_CONNECT_TOKEN | JWT used to authenticate 1Password Connect API requests | | vault_id | OP_VAULT_ID | (Optional) UUID of a 1Password Vault the API token is allowed to access |

connect.generic_item Module

πŸ”₯ Warning πŸ”₯ It is strongly recommended you define no_log: true on any tasks that interact with 1Password Connect. Ansible may print sensitive data if no_log is not set.

Example Usage

Create a new Item ```yaml


  • name: Create 1Password Secret hosts: localhost environment: OP_CONNECT_HOST: http://localhost:8001 OP_CONNECT_TOKEN: "api.jwt.here" tasks:
    • onepassword.connect.generic_item: vault_id: "qwerty56789asdf" title: Club Membership state: present fields:
      • label: Codeword value: "hunter2" section: "Personal Info" field_type: concealed
      • label: Random Code generate_value: on_create generator_recipe: length: 16 include_letters: yes include_digits: yes include_symbols: no no_log: true register: op_item ```

A note about state

The generic_item module follows Ansible's present/absent state pattern.

  • state: present
    • If the module cannot find a matching Item by its uuid or title, a new item is created with the defined values.
    • If the module finds a matching Item on the server, it will completely replace the old Item with a new Item defined by the playbook values.
  • state:absent
    • If the Item cannot be found, no action is taken.
    • If the Item is found, it is deleted. Otherwise, no action is taken.

Search order for an existing Item 1. Search by the Item's uuid, if provided. 2. Search by title, using a case-sensitive, exact-match query.

Generating field values

1Password can generate a field's value on the user's behalf when creating or updating an Item. Because generating random values is not idempotent, the user can specify one of three settings for generate_value:

generate_value setting | Effect | ---: | --- | never | (Default) The field value is not generated; uses value parameter instead. on_create | Generate the field's value if the field does not already exist. The field's stored value is preserved across playbook executions. always | Generate a new value for the field everytime the playbook is run. Overwrites value parameter.


Update an Item

❗️Note❗ The update operation will completely replace the Item matching the title or uuid field. Any properties not provided in the task definition will be lost.

We recommend storing the Items created by Ansible in a Vault that only 1Password Connect may access.

```yaml

  • name: Update a 1Password Secret hosts: localhost environment: OP_CONNECT_HOST: http://localhost:8001 OP_CONNECT_TOKEN: "valid.jwt.here" OP_VAULT_ID: "zyzzyz1234example" tasks:
    • onepassword.connect.generic_item: title: Club Membership # uuid: 1ff75fa9fexample -- or use an Item ID to locate an item instead state: present fields:
      • label: Codeword field_type: concealed
      • label: Dashboard Password generate_value: always # new value is generated every time playbook is run generator_recipe: length: 16 include_symbols: no no_log: true ```

item_info Module

Get information about an Item, including fields and metadata.

Example Usage

Find an Item by Name ```yaml


hosts: localhost environment: OP_CONNECT_HOST: http://localhost:8001 OP_CONNECT_TOKEN: "valid.jwt.here" collections: - onepassword.connect tasks: - name: Find the item with the label "Staging Database" in the vault "Staging Env" item_info: item: Staging Database vault: Staging Env no_log: true register: op_item ```

View `item_info` result registered to `op_item`
``` { "changed": false, "failed": false, "op_item": { "category": "SERVER", "createdAt": "2020-11-23T15:29:07.312397-08:00", "fields": { "Test": { "id": "j6ao3EXAMPLEvmzbrtre", "label": "Test", "type": "STRING", "value": ".........." }, "notesPlain": { "id": "notesPlain", "label": "notesPlain", "purpose": "NOTES", "type": "STRING" } }, "id": "bactwEXAMPLEpxhpjxymh7yy", "tags": [], "title": "Test Item 2", "updatedAt": "2020-11-23T15:29:07.312397-08:00", "vault": { "id": "4ktuuifg2ad7m4vEXAMPLEm" } } } ```

field_info Module

Use the onepassword.connect.field_info module to get the value of an item field.

The field_info module will first find the item by name or UUID, then search for the requested field by name. If a section is provided, the module will only search within that item section. If no section is provided, the field name must be unique within the item.

The search method compares field names using the unicodedata.normalize function and the NKFD form.

Example Usage

```yaml

hosts: localhost environment: OP_CONNECT_HOST: http://localhost:8001 OP_CONNECT_TOKEN: "valid.jwt.here" collections: - onepassword.connect tasks: - name: Find a field labeled "username" in an item named "MySQL Database" in a specific vault. onepassword.connect.field_info: item: MySQL Database field: username vault: 2zbeu4smcibizsuxmyvhdh57b6 no_log: true register: op_item

- name: Print the field definition
  ansible.builtin.debug:
    var: "{{ op_item.field }}"

```

View output registered to the `op_item` variable
``` { "value": "mysql_username_example", "section": "", "id": "fb3b40ac85f5435d26e" } ```

Testing

Use the test Makefile target to run unit tests:

shell make test

For more information about testing, see tests/README.md

About 1Password

1Password is a privacy-focused password manager that keeps you safe online.

By combining industry-leading security and award-winning design, the company provides private, secure, and user-friendly password management to businesses and consumers globally. More than 60,000 business customers trust 1Password as their enterprise password manager.

Security

1Password requests you practice responsible disclosure if you discover a vulnerability.

Please file requests via BugCrowd.

For information about security practices, please visit our Security homepage.

Issues

Access to Documents/Files

opened on 2022-11-28 11:08:58 by beerygaz

Summary

Allow the collection to retrieve file/documents from 1Passwird

Use cases

We store certificates as files/documents in 1Password entries. It would be great for the sensible collection to expose access to this content

Proposed solution

Add support for the 1P Connect GET /v1/vaults/{vaultUUID}/items/{itemUUID}/files/{fileUUID}/content endpoint

Is there a workaround to accomplish this today?

Not using ansible collection and one password connect.

onepassword.connect.generic_item state=absent task fails if item is present

opened on 2022-10-11 03:42:07 by gav-

Your environment

Collection Version: 2.2.1

Connect Server Version: 1.5.7

OS: Ubuntu 20.04

Ansible Version: ansible==5.9.0 ansible-core==2.12.7

What happened?

Running onepassword.connect.generic_item module as a task, with state=absent returns FAILED when the item is present in the 1Password vault. The item is correctly deleted however. The error is the same if either "title" or "uuid" parameters are used. No error is returned if the item is not present in the vault.

What did you expect to happen?

Ansible should complete the task as 'ok'

Steps to reproduce

  1. Make sure that "myitem" is in the 1Password vault
  2. Simple ansible task to delete "myitem" from 1Password vault: ```
  3. name: Ensure myitem is NOT in 1password Ansible vault onepassword.connect.generic_item: hostname: '{{ onepassword_connect_host }}' token: '{{ onepassword_connect_token }}' vault_id: '{{ onepassword_vault_id }}' title: myitem state: absent connection: local register: op_item ```
  4. Ansible returns: TASK [onepassword : Ensure myitem is NOT in 1password Ansible vault] *************************************************************************************** fatal: [localhost]: FAILED! => {"changed": false, "msg": "OK (unknown bytes)", "op_item": {}}

Loss of item properties on update is complex to work around in ansible

opened on 2022-10-07 01:03:59 by gav-

Summary

Updating an existing item with onepassword.connect.generic_item module, results in the loss of properties if those properties are not supplied. This is non-trivial to work around in ansible.

Use cases

It should be possible to update or add a single property to an existing 1password item without the destruction of existing properties. This behaviour should be possible with "fields" or "urls".

Proposed solution

Consider ansible.builtin.user module and how it handles a list of groups, by default the provided list will replace any groups the user is a member of, removing the user from groups not in the list (so far, the same behaviour as generic_item). An optional "append" parameter may be provided to only add the user to groups in the list, and not remove the user from any.

Additional parameters could be used to provide this same functionality to "fields" and "urls" (and any other list-type properties).

Is there a workaround to accomplish this today?

Use onepassword.connect.item_info to read the data first, concatenate with data to be submitted, then submit combined data with onepassword.connect.generic_item task. This is non-trivial in ansible (1password items can be quite complex) and would be better handled in the module.

Update is not very "ansible like" when same data results in "changed: true"

opened on 2022-10-07 00:44:38 by gav-

Summary

Updating an existing item with onepassword.connect.generic_item module, with the same exact properties and values, results in "changed: true". This is not very ansible-like, it should really be "changed: false"

Use cases

No changes should result in no changes.

Proposed solution

No changes should result in no changes.

Is there a workaround to accomplish this today?

Use onepassword.connect.item_info to read the data first, compare with data to be submitted, and skip onepassword.connect.generic_item task if they are the same. This is non-trivial in ansible (1password items can be quite complex) and would be better handled in the module.

References & Prior Work

Compare to ansible.builtin.user module where the same properties result in no change

Example for field_info not correct

opened on 2022-09-02 11:17:29 by rooso

Collection Version 2.2.0

Connect Server Version: n/a

OS: n/a

Ansible Version: core 2.13.1

What happened?

The example in this README.MD is not correct. If the Ansible Module debug is used with var a variable is expected. With your example you got the error <class 'dict'>": "VARIABLE IS NOT DEFINED!: as debug output.

```

hosts: localhost environment: OP_CONNECT_HOST: http://localhost:8001 OP_CONNECT_TOKEN: "valid.jwt.here" collections: - onepassword.connect tasks: - name: Find a field labeled "username" in an item named "MySQL Database" in a specific vault. onepassword.connect.field_info: item: MySQL Database field: username vault: 2zbeu4smcibizsuxmyvhdh57b6 no_log: true register: op_item

- name: Print the field definition
  ansible.builtin.debug:
    var: "{{ op_item.field }}"

```

Please change the last line in your example to the following:

msg: "{{ op_item.field }}"

This will might save someone's valuable time in searching for solution :)

Ability to set notesPlain, purpose=NOTES, or at least document why we cant set notes

opened on 2022-08-22 14:04:09 by jilleJr

Summary

Took me a while to finally understand why my notesPlain didn't show up, while all other fields showed up. But it's written in this Python comment hidden in the code:

https://github.com/1Password/ansible-onepasswordconnect-collection/blob/e126355bd11b17e5af733918ea3f775d18cc766b/plugins/module_utils/fields.py#L30-L34

Would be great to be able to set the notesPlain from Ansible, or at least create a different field with purpose=NOTES (as shown possible in the ref docs: https://developer.1password.com/docs/connect/connect-api-reference/#item-field-object)

Use cases

We want to put some YAML text into 1Password. Kubeconfigs to be more precise.

Using only a field is OK, but the text isn't really viewable from 1Password apps as it's missing the linebreaks in the display (copying the secret field does include the newlines, so that's OK at least)

Proposed solution

To be able to either allow setting notesPlain field.

Or if you insist that Ansible should not be able to set the notes field (why though?) then at least document it in this repo's README.md file, with clearly stating the purpose.

Is there a workaround to accomplish this today?

We've been using any other field in the meantime. Though the lack of multiline is quite annoying.

References & Prior Work

N/A

Releases

2022-09-02 07:33:52

Fixes

  • Connect responses of type HTTPError or null are now properly handled. (#59, #64)
  • Added an Ansible Automation Hub tag (security) to add compliance with the Automation Hub guidelines. Credits to @JohnLieske for the contribution. (#52)
  • Added required meta/runtime.yml for Ansible Galaxy compat. (#50)

v2.2.0 2022-01-05 15:33:34

Features

  • Introduce the onepassword.connect.field_info module (#39)

Fixes

  • Add flatten_fields_by_label option to the onepassword.connect.field_info module. (#34)
    • The new option defaults to true and preserves the behavior seen in versions <=2.1.1.
    • The default behavior will change to false in release v3.0.0
    • See PR #39 for more details.
  • Creating a one-time password (OTP) field within an item now uses the correct field type. (#46)

v2.1.1 2021-06-24 21:28:30

This release improves compatibility with all Python runtimes supported by Ansible 2.9+.

We are making this change to better support customers downloading this collection through RedHat's Ansible Automation Hub.

Fixes

  • Replace Python 3.6+ features with backwards-compatible implementations. (#31)

v2.1.0 2021-06-22 22:11:53

This version fixes several bugs, introduces more supported item types, and improves how the module handles special fields for certain item types.

Note there is a breaking change when defining an Item with type: login or type: password:

  • Creating a type: password Item without a concealed field named password will raise an error
  • If the Item type is password and there are multiple concealed fields named password, Ansible raises an error
  • If the Item type is login and there are multiple string fields named username, Ansible raises an error.

Features

  • :star: Change default item type to API_CREDENTIAL (#25)
  • Add more supported item type choices (#24)

Fixes

  • get_item_by_name client method now returns the full item response instead of the overview. (#29)
  • Fix field_purpose assignment when item type is PASSWORD or LOGIN (#28)
  • Use UTF-8 string normalization while searching for fields when updating an item. (#27)
  • The generic_item module now preserves the notes field without it being present in the module parameters (#27)
  • Fix sed regex for currentVersion lookup in release tool. (#23)

v2.0.0 2021-05-25 15:08:43

v2.0.0

This release introduces two breaking changes to the generic_item module. You will need to update any playbooks using this collection after upgrading to v2.0.0.

  • The Item options state: upserted and state: created have been replaced by state: present. Please refer to the README for usage details.

  • You now have fine-grained controls for defining when 1Password Connect should generate a field's value. The generate_value setting now accepts on_create, always, and never (default).

Features

  • You can now use the familiar state: absent and state: present when defining 1Password vault items in your playbooks. (#15)
  • Introduce on_create / always / never options for a field's generate_value setting (#15).
  • Add support for API_CREDENTIAL item type (#17)

Fixes

  • Makefile now uses the correct path to the testing script. (#14)

v1.0.1 2021-04-13 14:47:38

Changes Minor release with updates to the Ansible Galaxy manifest.

  • Resolves small issues with the Ansible Galaxy manifest file
  • Exclude the test/ directory from the build artifact.

Install via ansible-galaxy ansible-galaxy collection install onepassword.connect

1Password

1Password remembers all your passwords for you. It keeps your digital life secure and always available, safe behind the one password that only you know.

GitHub Repository Homepage