# Ansible Plugin

![](https://762006384-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MJXOXEifAmpyvNVL1to%2F-MkdG-_u0H2AJBEVfeYf%2F-MkdG4aCrzLanoVIXeNo%2Fansible-plugin-header.jpg?alt=media\&token=70c9a583-5939-48cc-990b-65c60094663a)

## Features

* Retrieve secrets from the Keeper vault to use in Ansible Playbooks
* Update the value of secrets in the Keeper Vault from Ansible
* Create records from Ansible
* Copy files from the Keeper Vault

{% hint style="info" %}
For a complete list of Keeper Secrets Manager features see the [Overview](https://docs.keeper.io/en/keeperpam/secrets-manager/overview)
{% endhint %}

## Prerequisites

This page documents the Secrets Manager Ansible integration. In order to utilize this integration, you will need:

* Keeper Secrets Manager access (See the [Quick Start Guide](https://docs.keeper.io/en/keeperpam/secrets-manager/quick-start-guide) for more details)
  * Secrets Manager add-on enabled for your Keeper account
  * Membership in a Role with the Secrets Manager enforcement policy enabled
* A Keeper [Secrets Manager Application](https://docs.keeper.io/en/keeperpam/about/terminology#application) with secrets shared to it
  * See the [Quick Start Guide](https://docs.keeper.io/en/keeperpam/quick-start-guide#2.-create-an-application) for instructions on creating an Application
* An initialized Keeper [Secrets Manager Configuration](https://docs.keeper.io/en/keeperpam/secrets-manager/about/secrets-manager-configuration)
  * The Ansible integration accepts both Base64 and JSON format configurations

## Installation

Due to the flexibility of Ansible, where you install the plugins depends on your Ansible installation and playbook locations.

### Install Keeper Ansible Module

#### Installation via Ansible Galaxy

The collection can be found on the [Ansible Galaxy website](https://galaxy.ansible.com/ui/repo/published/keepersecurity/keeper_secrets_manager/). You can install the collection with the follow command line.

```bash
$ ansible-galaxy collection install keepersecurity.keeper_secrets_manager
```

Ansible Galaxy collection uses long plugin names. The name is the collection name combined with the plugin name. For example, the `keeper_copy` plugin name when using Ansible Galaxy is `keeper_security.keeper_secrets_manager.keeper_copy`*.* If you want to use the short plugin name, add `keepersecurity.keeper_secrets_manager` to the `collections` block of your playbook.

```yaml
- name: Keeper Copy
  hosts: my_hosts
  collections: 
    - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Copy a password
      keeper_copy:
        uid: RECORD UID
        ...
```

{% hint style="info" %}
Installing via Ansible Galaxy assumes you already have Ansible installed. Ansible Galaxy cannot install dependencies. The following dependencies will need to be installed manually, via pip, into your the python library or virtualenv used by Ansible.

* keeper-secrets-manager-core>=17.2.0
* keeper-secrets-manager-helper>=1.1.0
  {% endhint %}

#### Installation via Pypi

The Ansible module for Keeper is installed with the command below. Make note of the location where the module is installed, as this will be needed in the Ansible playbook configuration.

```bash
$ pip3 install -U keeper_secrets_manager_ansible
```

{% hint style="info" %}
Requires Python 3.9 or later
{% endhint %}

For more information see the [PyPi page](https://pypi.org/project/keeper-secrets-manager-ansible/).

Find the Keeper Secrets Manager Ansible Plugin source code in the [GitHub repository](https://github.com/Keeper-Security/secrets-manager/tree/master/integration/keeper_secrets_manager_ansible).

The Keeper ansible plugins are installed in the site-packages directory of your version of Python or your current virtual environment. You can find the plugin locations using the following command:

```bash
$ keeper_ansible --config

# Below are the directory paths to action and lookup plugins.
ANSIBLE_ACTION_PLUGINS=...site-packages/keeper_secrets_manager_ansible/plugins/action_plugins
ANSIBLE_LOOKUP_PLUGINS=...site-packages/keeper_secrets_manager_ansible/plugins/lookup_plugins
```

Those paths can be used in your *ansible.cfg.*

```ini
[defaults]
action_plugins = ...site-packages/keeper_secrets_manager_ansible/plugins/action_plugins
lookup_plugins = ...site-packages/keeper_secrets_manager_ansible/plugins/lookup_plugins
```

### Generate a Config File

Prior to proceeding with this guide, make sure you meet all the [prerequisites](#prerequisites) and have the following:

* KSM Application and it's [One-Time Access Token](https://docs.keeper.io/en/keeperpam/quick-start-guide#create-a-secrets-manager-client-device-1)
* [Keeper Ansible module](#install-keeper-ansible-module) installed

In order to use the Ansible plugin for Keeper Secrets Manager, a [Keeper config file](https://docs.keeper.io/en/keeperpam/secrets-manager/about/secrets-manager-configuration) is required. Once you have a config file, the configuration values can be placed into the [Ansible variable](#ansible-variables) files. These variable files can be encrypted with Ansible vault.

Using the Keeper Ansible module and the generated One-Time Access Token, generate a Configuration file:

```bash
$ keeper_ansible --token XX:XXXXXX
Config file create at location client-config.json
```

This will generate the Keeper JSON configuration file in the current directory.

If you do not have your Python module bin path added your **PATH** environment variable, you can create a config with the following command.

```bash
$ python3 -m keeper_secrets_manager_ansible --token XX:XXXXXX
Config file create at location client-config.json
```

The default name for the JSON configuration file is client-config.json. The content of the file will look like the following:

```json
{
    "appKey" : "XXXXXXXX",
    "appOwnerPublicKey": "XXXXXXX",
    "clientId": "XXXXXXXX",
    "hostname": "XXXXX",
    "privateKey": "XXXXXXXX",
    "serverPublicKeyId": "XX"
}

```

This config file allows your Ansible playbook to authenticate and retrieve designated secrets from the vault.

### Ansible Variables

The Keeper Secrets Manager plugins can use multiple configuration methods. For example, the Base64 encode configuration can be used.

```yaml
---
keeper_config: U09NRVRFc2R ... GFzZGFzZGFzZHNhWFQK==
```

Ansible can use the client-config.json config file directly. It can be specified in the Ansible variables using the keeper\_config\_file variable key.

```yaml
---
keeper_config_file: /path/to/client-config.json
```

Another solution is to place the values in your client-config.json file into an Ansible variable file. For example, the values can be placed into the *group\_vars, host\_vars, or in the task files:*

```yaml
---
keeper_app_key: XXXXX
keeper_client_id: XXXXX
keeper_token: XXXXX
keeper_private_key: XXXXX
keeper_app_owner_public_key: XXXXX
keeper_server_public_key_id: XX
```

For security, the *group\_vars* or *host\_vars* files can be encrypted with ansible-vault.

A list of valid Ansible Variables for the Keeper plugin are below:

<table data-header-hidden><thead><tr><th width="277.3333333333333">Ansible Variable</th><th width="185">JSON Key</th><th>Description</th></tr></thead><tbody><tr><td>Ansible Variable</td><td>JSON Key</td><td>Description</td></tr><tr><td>keeper_config</td><td>--</td><td>A Base64 encoded configuration string.</td></tr><tr><td>keeper_config_file</td><td>--</td><td>An alternative path and name for the JSON configuration file, if not current directory or named differently than <em>client-config.json</em>.</td></tr><tr><td>keeper_token</td><td>clientKey</td><td>The one time access token, also known as the client key. Only used to initialize the configuration.</td></tr><tr><td>keeper_client_id</td><td>clientId</td><td>The client id provided from Secrets Manager after the one time access token is used. Required.</td></tr><tr><td>keeper_app_key</td><td>appKey</td><td>The app key provided from the secret management service after the one time access token is used. Required.</td></tr><tr><td>keeper_private_key</td><td>privateKey</td><td>The private key provided from the secret management service after the one time access token is used. Required.</td></tr><tr><td>keeper_app_owner_public_key</td><td>appOwnerPublicKey</td><td>The public key used for creating records. Required if using the <code>keeper_create</code> plugin.</td></tr><tr><td>keeper_server_public_key_id</td><td>serverPublicKeyId</td><td>Selects which public key to use when connecting to the server. If the server wants a different public key the SDK will handle switching. Not required, but will reduce number of web service calls.</td></tr><tr><td>keeper_hostname</td><td>hostname</td><td>The Secrets Manager backend hostname. Defaults to US. Supports "US", "EU", "AU" and "US_GOV" values depending on your Keeper data center location. Required.</td></tr><tr><td>keeper_log_level</td><td>--</td><td>Set the log level of the SDK. Acceptable levels are DEBUG, INFO, WARNING, ERROR, and CRITICAL. Defaults to ERROR.</td></tr><tr><td>keeper_record_cache_secret</td><td>--</td><td>Required for the <code>keeper_cache_records</code> action. Used to encrypt records in cache. The value of this variable can be created in the playbook. See action example.</td></tr><tr><td>keeper_use_cache</td><td>--</td><td>Use a cache of the vault. Defaults to False. Cache file are only used as backup for network problems.</td></tr><tr><td>keeper_cache_dir</td><td>--</td><td>The directory to write and read the cache file.</td></tr><tr><td>keeper_record_types</td><td>--</td><td>An list of Keeper Commander record type definitions.</td></tr></tbody></table>

{% hint style="info" %}
There are two caching methods in the plugin. They are not the same.\
\
`keeper_record_cache_secret` is used to cache records for a playbook run. After the playbook run, the cache is removed. The cache is stored in memory encrypted. This cache can be used to reduce the number of API called to the Keeper Secret Manager service. Since this cache is stored in memory, the more records retrieved the more memory is used.\
\
`keeper_use_cache` and `keeper_cache_dir` are used for Disaster Recovery caching of the Keeper Vault. This cached is used when connection to the Keeper Secret Manager service cannot be reached. This cache is stored encrypted on disk.
{% endhint %}

### **Command Line Variables**

As an optional method, values can be passed in through the `ansible-playbook` command. Example:

```bash
$ ansible-playbook my_playbook.yml \
    -e "keeper_app_key=XXXXX" \
    -e "keeper_client_id=XXXXX" \
    -e "keeper_token=XXXXX" \
    -e "keeper_private_key=XXXXX"
```

## Ansible Plugin Usage

There are eleven Keeper action plugins, one lookup, and one lookup plugin.

For all the plugins, the following arguments are used. Either the `uid` or `title` is required.

* `uid` - The Record UID of the desired record.
* `title` - The Record Title of the desired record.
* `field` - Retrieve the value with specified label from the record.
* `custom_field` - Retrieve the value with the specific custom field name.
* `file` - Retrieve the file with the specified name from the record.

The `uid` value is required, and you need either `field` or `file` populated.

{% hint style="info" %}
To find out what fields and custom fields are available for a specific vault secret, use the Keeper Secrets Manager CLI "`ksm secret get -u XXXX`" command. More info [here](https://docs.keeper.io/en/keeperpam/secrets-manager-command-line-interface/secret-command#secret-command).
{% endhint %}

{% hint style="info" %}
The plugin example are shown with the short plugin names. If you installed the collection via Ansible Galaxy, you will need to use the longer plugin name or add the collection name to the list of collections used in your playbook.
{% endhint %}

Actions can either use [Keeper Notation](https://docs.keeper.io/en/keeperpam/secrets-manager/about/keeper-notation) or the record UID or Title, combined with the task attributes `array_index` and `value_key` to get a specific value.

For example, a complex value like Phone number is an array of objects.

```json
[
    {
        'number': '(555) 123-1234', 
        'type': 'Work', 
        'ext': '11'
    }, 
    {
        'region': 'AD', 
        'number': '111-2223333', 
        'ext': '5555', 
        'type': 'Mobile'
    }
]
```

The example below shows how to use **Keeper Notation** and `array_index` and `value_key` to get the same result.

```yaml
---
- name: Keeper Get
  hosts: my_hosts
  # Include line below if installed via ansible galaxy or use long plugin names.
  # collections: 
  #   - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Get the second phone number using Keeper Notation
      keeper_get:
        notation: "RECORD UID/field/phone[1][number]"
      register: second_number_notation
      
    - name: Get the second phone number using array_index and value_key
      keeper_get:
        uid: "RECORD UID"
        field: phone
        array_index: 1
        value_key: "number"
      register: second_number_non_notation
```

### Plugin: keeper\_cache\_records

The plugin `keeper_cache_records` is used to retrieve a select amount of records to be stored in a cache. The cache can then be used by other actions. This is used to reduce the number of API calls by getting all required record up front.

```yaml
---
- name: Cache records
  hosts: my_hosts
  # Include line below if installed via ansible galaxy or use long plugin names.
  # collections: 
  #   - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Generate a Keeper Record Cache secret
      keeper_password:
        length: 64
      register: generated_password
      no_log: True

    - name: Store the Keeper Record Cache secret into variables.
      set_fact:
        keeper_record_cache_secret: "{{ generated_password.password }}"
      no_log: True
      
    - name: Cache records. Will use keeper_record_cache_secret from above.
      keeper_cache_records:
        uids:
          - RECORD UID
          - RECORD UID
        titles:
          - My Record Title
          - My Record Title Too
      register: my_records
      no_log: True
        
    - name: Copy a file
      keeper_copy:
        cache: "{{ my_records.cache }}"
        uid: RECORD UID
        file: my_cert_file.crt
        dest: /etc/special.crt
        owner: root
        group: root
        mode: "0644"
        backup: yes
```

The records can be retrieved by the record UID or by the record title. The result of the action is an encrypted serialization of the records. The result should be stored in Ansible by using the register variable so it can be used by other actions. The encrypted serialization of the records can be quite long. For security and reducing log noise, it is recommended to set `no_log` to **True**.

`keeper_cache_records` caches records only. It does not cache attached files. If an action attempts to retrieve an attached file from a record that came from the cache, an API call will be made to download the file.

Use templating to set the attributes in other actions. For example `cache: "{{ my_records.cache }}"`

`keeper_cache_records` requires the `keeper_record_cache_secret` to be set. This can be done in the host, group, task variables, or generated in a task and then set as a fact (variable). In the example above, the `keeper_password` action is used to generate a password which is then stored as `keeper_record_cache_secret`. The `no_log` attribute is set to True to prevent the secret from being logged.

The cache will not update. The cache will not contain records created or updated after it has been generated. To get new records or changes in the cache, `keeper_cache_records` will need to be called again.

#### Required Attributes

* `uids` - A list of Keeper Vault record UID.
* `titles` - A list of titles of Keeper Vault records.

The attributes `uids` and `titles` can be used at the same time. At least one of them needs to be set.

### Plugin: `keeper_copy`

The plugin `keeper_copy` is an extension of the [built-in copy plugin](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html)*.* Example:

```yaml
---
- name: Keeper Copy
  hosts: my_hosts
  # Include line below if installed via ansible galaxy or use long plugin names.
  # collections: 
  #   - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Copy a password.
      keeper_copy:
        uid: RECORD UID
        field: password
        dest: /tmp/my_password
        mode: "0600"

    - name: Copy a file
      keeper_copy:
        uid: RECORD UID
        file: my_cert_file.crt
        dest: /etc/special.crt
        owner: root
        group: root
        mode: "0644"
        backup: yes
        
    - name: Copy record notes to file
      keeper_copy:
        uid: RECORD UID
        notes: yes
        dest: /tmp/record_notes.txt
        mode: "0600"
```

In the examples, a password will be copied from the Keeper vault record and stored in the file `/tmp/my_password` on the remote system. It will use the Ansible built-in copy plugin's mode attributes to change the permissions of the file.

The last task example from above, the file "*my\_cert\_file.crt*" will be copied from the Keeper vault record and stored at the location "*/tmp/special.crt"*. Several of the built-in copy plugin functions will be applied to the file.

#### Required Attributes

* `uid` - A Keeper Vault record UID.
* `title` - Title of a Keeper Vault records.
* `notation` - Use Keeper Notation to get the field from a record.

The attributes `uids` and `titles` can be used at the same time. At least one of them needs to be set.

#### Optional Attributes

* `cache` - The record cache from the `keeper_cache_records` action.
* `field` - Get the content from the standard Keeper Vault record.
* `custom_field` - Get the content from the custom Keeper Vault record.
* `file` - Get the content from the files attach to the Keeper Vault record by file title.
* `notes` - Set to `yes` to copy the notes field from the record. The notes field contains text notes attached to the record. Notes is a singleton field (only one per record), so it uses a boolean flag instead of a field name. Added in v1.3.0.
* `array_index` - Defaults to 0. If the field value contains multiple values, this attribute will allow you to select which item to return. The first item will have the `array_index` of **0**, and the next will be **1**, etc.
* `value_key` - If the field value is a complex object, this will allow you to select the key of the key/value pair to return.

Additional optional attributes are the same as the [built-in copy plugin](https://docs.ansible.com/ansible/latest/collections/ansible/builtin/copy_module.html) attributes. The attributes `src, remote_src`, and `content` are not allowed and will be ignored.

### Plugin: `keeper_get`

{% hint style="success" %}
**New in v1.3.0**: You can now retrieve record notes using the `notes` parameter.
{% endhint %}

The plugin `keeper_get` will retrieve a field or file from a Keeper vault record. Example:

```yaml
---
- name: Keeper Get
  hosts: my_hosts
  # Include line below if installed via ansible galaxy or use long plugin names.
  # collections: 
  #   - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Get login name. Loading record from Keeper Vault.
      keeper_get:
        uid: RECORD UID
        field: login
      register: my_login
      
    - name: Print login name
      debug:
        var: my_login.value
        verbosity: 0
        
    - name: Make a sudoer
      copy:
        dest: "/etc/sudoers.d/{{ my_login.value }}"
        content: |
          # Auto added by Ansible
          {{ my_login.value }} ALL=(ALL:ALL) ALL
          
    - name: Get record notes
      keeper_get:
        uid: RECORD UID
        notes: yes
      register: my_notes

    - name: Display notes
      debug:
        var: my_notes.value

    - name: Write notes to file
      copy:
        content: "{{ my_notes.value }}"
        dest: /tmp/record_notes.txt
```

The `keeper_get` plugin returns a dictionary. The key "value" in the dictionary will contain the desired field or file content. This plugin is normally paired with the Ansible `register` instruction and the returned value is stored in memory so it can be accessed by other tasks.

In the example above, a record containing user's login name is retrieved. The login name is then stored under the name my\_login. The second task will print the login name to your console for debug purposes. The third task will add a sudoer file for the login name with ability to execute all applications.

#### Required Attributes

* `uid` - A Keeper Vault record UID.
* `title` - Title of a Keeper Vault records.
* `notation` - Use Keeper Notation to get the field from a record.

The attributes `uids` and `titles` can be used at the same time. At least one of them needs to be set.

#### Optional Attributes

* `cache` - The record cache from the `keeper_cache_records` action.
* `field` - Get the value from the standard Keeper Vault record.
* `custom_field` - Get the value from the custom Keeper Vault record.
* `file` - Get the value from the files attach to the Keeper Vault record by file title.
* `notes` - Set to `yes` to retrieve the notes field from the record. The notes field contains text notes attached to the record. Unlike other fields, notes is a singleton field (only one per record), so it uses a boolean flag instead of a field name. Added in v1.3.0.
* `allow_array` - By default is **False**. If set to **True**, an array of values will be returned. This is needed if the field contains multiple values such as Phone numbers. If **True**, `array_index` and `value_key` will be ignored.
* `array_index` - Defaults to 0. If the field value contains multiple values, this attribute will allow you to select which item to return. The first item will have the `array_index` of 0, and the next will be 1, etc.
* `value_key` - If the field value is a complex object, this will allow you to select the key of the key/value pair to return.

{% hint style="info" %}
To **update** record notes, use the [`keeper_set`](#plugin-keeper_set) plugin with `notes: yes` and `value:`.
{% endhint %}

### Plugin: `keeper_get_record`

The plugin `keeper_get_record` will retrieve all the fields in the record and return them in a dictionary. Example:

```yaml
---
- name: Keeper Get Record
  hosts: my_hosts
  # Include line below if installed via ansible galaxy or use long plugin names.
  # collections: 
  #   - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Get a record from the vault.
      keeper_get_record:
        uid: RECORD UID
        allow:
          - login
          - password
      register: my_record
      
    - name: Print login name
      debug:
        var: my_record.record.login[0]
        verbosity: 0
```

The `keeper_get_record` plugin returns a dictionary. The keys of the dictionary are the normalized field labels, or types. The keys will be alphanumeric and the underscore characters. If there are duplicate key, a number will be appended to the end of the key.

In the example above, a record is retrieved using the UID. The fields will be stored in a dictionary, in memory, using the `register` instruction. Since the `allow` attribute is used, the dictionary will only contain **login** and **password** .The field values can be accessed using the normal the templating in Ansible. The values will be stored as arrays. This is due to some fields returning arrays of the values, such as `phone`.

#### Required Attributes

* `uid` - A Keeper Vault record UID.
* `title` - Title of a Keeper Vault records.

Either `uids` and `titles` is required.

#### Optional Attributes

* `cache` - The record cache from the `keeper_cache_records` action.
* `allow` - A list of keys to allow. If set, if the key is not in the list, it will not be inclued in the dictionary.

### Plugin: `keeper_set`

The `keeper_set` plugin has the ability to write a value into an existing Keeper vault record.

{% hint style="success" %}
**New in v1.3.0**: You can now update record notes fields using `keeper_set` with `notes: yes` and `value:`.
{% endhint %}

{% hint style="info" %}
To **retrieve** record notes, use the [`keeper_get`](#plugin-keeper_get) plugin with `notes: yes`.
{% endhint %}

Example:

```yaml
---
- name: Keeper Set
  hosts: my_hosts
  # Include line below if installed via ansible galaxy or use long plugin names.
  # collections: 
  #   - keepersecurity.keeper_secrets_manager
  
  tasks:
    - name: Get login name of new user.
      keeper_get:
        uid: RECORD UID
        field: login
      register: my_login
      
    - name: Add new user of remote machine.
      user:
        name: "{{ my_login.value }}"
        comment: "User {{ my_login.value }}"
      register: new_user
        
    - name: Update record with user's home directory in the Keeper Vault
      keeper_set:
        uid: RECORD UID
        custom_field: my_home_directory
        value: "{{ new_user.home }}"
        
    - name: Update Record Notes
      keeper_set:
        uid: RECORD UID
        notes: yes
        value: "Updated by Ansible on {{ ansible_date_time.iso8601 }}"
```

In this example, a new user's login name is retreived. The new user is created on the remote system with the login name from the record. The home directory on the remote machine is then updated in the record.

The `keeper_set` action does not have the ability of set individual values of an array or complex values. It simplely replaces the existing value with a new value. For example, for a **Hostname and Port** field type there is no way to just update the port. The entire value including the **hostName** needs to be included in the object value.

`keeper_set` will set the update the record in the vault. It will not update the cache, if used. To update the cache, a step will need to run the `keeper_cache_records` action again with the **UID** or **Title** of the record that was updated.

#### Required Attributes

* `uid` - A Keeper Vault record UID.
* `title` - Title of a Keeper Vault records.
* `notation` - Use Keeper Notation to get the field from a record.

The attributes `uids` and `titles` can be used at the same time. At least one of them needs to be set.

#### Optional Attributes

* `field` - Update the existing standard Keeper Vault record field.
* `custom_field` - Update the existing custom Keeper Vault record field.
* `notes` - Set to `yes` to update the notes field in the record. The notes field contains text notes attached to the record. Notes is a singleton field (only one per record), so it uses a boolean flag instead of a field name. Added in v1.3.0.
* `value` - The new value to write to the record field.

### Plugin: `keeper_create`

The `keeper_create` plugin creates a record in the Keeper vault. See the [Field/Record Types ](https://docs.keeper.io/en/keeperpam/secrets-manager/about/field-record-types)document for available record types, and the field types used to build the records. The action plugin will return the `record_uid` upon successful creation.

{% hint style="info" %}
The Ansible variable `keeper_app_owner_public_key` is required to create a record. In the client-config.json, the JSON key is `appOwnerPublicKey.` If your configuration does not contain this key, create a new One-Time Access Token and initialize it.
{% endhint %}

Example:

```yaml
---
- name: Keeper Create
  hosts: my_hosts
  
  tasks:
    - name: "Create A Record"
      keeper_create:
        shared_folder_uid: XXXXXX
        record_type: login
        generate_password: True
        password_complexity:
          length: 64
          allow_symbols: False
        title: "My New Record"
        notes: "Created by Ansible"
        version: v3
        fields:
          - type: login
            value: johndoe@localhost
          - type: url
            value: https://localhost
        custom_fields:
          - type: text
            label: "My Custom Label"
            value: "My custom value"
      register: my_new_record

    - name: "New Record UID"
      debug:
        msg: "New record uid is {{ my_new_record.record_uid }}"
```

The following fields are required.

* `shared_folder_uid` - The Shared Folder UID from the vault. The record will be created within this folder.
* `record_type` - The type of record. This will included all the default record types. If the `keeper_record_types` is set, those record types can be used.
* `title` - The title of record

The following fields are optional.

* `version` - The record schema version to use. Defaults to `v3` (recommended). Accepts `v2` or `v3`. Available since v1.1.2.
* `generate_password` - If set to true, any password field where the password has not been set, will be populated with a random generated password.
* `password_complexity` - Sets the complexity of the password. All parameters of password\_complexity are optional.
  * `length` - Length of password. Defaults to **64**.
  * `allow_lowercase` - Defaults to **True**. If set to **False**, no lowercase letters will be used.
  * `allow_uppercase` - Defaults to **True**. If set to **False**, no uppercase letters will be used.
  * `allow_digits` - Defaults to **True**. If set to **False**, no digits will be used.
  * `allow_symbols` - Defaults to True. If set to **False**, no symbols will be used.
  * `filter_characters` - A list of characters to exclude from the password. This allows to remove characters a services will reject. For example, '%' in SQL. If not set, the password will not be filtered.
* `notes` - Attach a note to the record.

{% hint style="info" %}
Password generation will use the following symbols: "!@#$%()+;<>=?\[]{}^.,
{% endhint %}

Based on the Record Types, certain fields maybe required. Custom fields are optional. Both `fields` and `custom_fields` are an array of values.

* `fields/custom_fields`
  * `type` - Field type
  * `label` - Label to display with the value.
  * `value` - Field value. Can be a string or dictionary based on field type.

#### Creating Custom Record Types

To create a record with a particular Custom Record Type, first export the custom record types using Keeper Commander and the `record-type-info` command. KSM does not sync down the custom type definitions, so this must be added directly to the playbook as a variable.

Keeper Commander will output a JSON Array ("content"). Only the JSON object is required.

Example:

```
My Vault> record-type-info --format json -lr "My Custom"
[
  {
    "recordTypeId": 18,
    "content": "{\"$id\":\"My Custom\",\"categories\":[\"login\"],
      \"description\":\"SSH key template\",\"fields\":[
        {\"$ref\":\"login\"},
        {\"$ref\":\"keyPair\"},
        {\"$ref\":\"password\",\"label\":\"passphrase\"},
        {\"$ref\":\"host\"},
        {\"$ref\":\"fileRef\"}]}"
  }
]
```

In your Ansible YAML file, add the value of the "content" object to the variable key called `keeper_record_types`. The variable is an array, and the JSON is to be treated as a string value. The pipe, after the array item, will treat the following JSON as a string. The variable will accept multiple record types.

Example:

```yaml
- name: My Playbook
  collections:
   - keepersecurity.keeper_secrets_manager
  hosts: "my_hosts"
  vars:
    keeper_record_types:
      - |
        {
          "recordTypeId": 35,
          "content": "{\"$id\":\"My Custom\",\"fields\":[{\"$ref\":\"fileRef\",\"label\":\"File or Photo\"},{\"$ref\":\"login\",\"label\":\"Login\"},{\"$ref\":\"password\",\"label\":\"Password\",\"required\":true,\"enforceGeneration\":false,\"privacyScreen\":false,\"complexity\":{\"length\":8,\"caps\":0,\"lowercase\":0,\"digits\":0,\"special\":0}},{\"$ref\":\"text\",\"label\":\"System Login\",\"required\":true},{\"$ref\":\"secret\",\"label\":\"System Password / Pin Code\"},{\"$ref\":\"url\",\"label\":\"Keeper VPN Wiki\",\"required\":true},{\"$ref\":\"url\",\"label\":\"Password Best Practices FAQ's and Tips\",\"required\":true}]}"
        }
```

To check if this worked, the `keeper_info` plugin can be used to show which record types are available.

When creating a record of a particular custom type, the Ansible task will reference the record type name in the `record_type` parameter as seen below:

```yaml
- name: "Create A Custom Record"
      keeper_create:
        shared_folder_uid: XXXXXXXXXXXX
        record_type: "My Custom"
        title: "Example Custom Record"
        notes: "Created by Ansible"
        fields:
          - type: login
            label: Login
            value: johndoe@localhost
          - type: password
            label: Password
            value: "ABC123"
      register: my_new_record
```

### Plugin: `keeper_remove`

v1.2.1\
Released on: 10/27/2023

The keeper\_remove plugin will remove a record from the Keeper vault.

```yaml
---
- name: Keeper Remove
  hosts: my_hosts
  
  tasks:
    - name: Remove by UID
      keeper_remove:
        uid: RECORD UID
        
    - name: Remove by Title
      keeper_remove:
        title: RECORD TITLE
     
```

#### Required Attributes

* `uid` - A Keeper Vault record UID.
* `title` - Title of a Keeper Vault records.

The attributes `uid` and `title` cannot be used at the same time. At least one of them needs to be set.

#### Optional Attributes

* `cache` - The record cache from the `keeper_cache_records` action. The record will not be removed from the cache. The cache will be used for looking up the record title.

### Plugin: `keeper_password`

The `keeper_password` plugin will generate a random password. The action plugin will return the `password`.

Example:

```yaml
---
- name: Keeper Password
  hosts: my_hosts
  
  tasks:
    - name: Generate a long password
      keeper_password:
        length: 128
      register: long_password
    - name: Show long password
      debug:
        msg: "Long password {{ long_password.password }}"
        
    - name: Generate an all digit password
      keeper_password:
        length: 32
        allow_lowercase: False
        allow_uppercase: False
        allow_symbols: False
      register: digit_password
    - name: Show digit password
      debug:
        msg: "Digit password {{ digit_password.password }}"
        
    - name: Generate a PostgreSQL password (no % character)
      keeper_password:
        length: 64
        filter_characters: 
          - "%"
      register: pg_password
    - name: Show PostgreSQL password
      debug:
        msg: "PG password {{ pg_password.password }}"    
```

All parameters are optional. If no parameters are set, the defaults will be used.

* `length` - Length of password. Defaults to **64**.
* `allow_lowercase` - Defaults to **True**. If set to **False**, no lowercase letters will be used.
* `allow_uppercase` - Defaults to **True**. If set to **False**, no uppercase letters will be used.
* `allow_digits` - Defaults to **True**. If set to **False**, no digits will be used.
* `allow_symbols` - Defaults to True. If set to **False**, no symbols will be used.
* `filter_characters` - A list of characters to exclude from the password. This allows to remove characters a services will reject. For example, '%' in SQL. If not set, the password will not be filtered.

{% hint style="info" %}
Password generation will use the following symbols: "!@#$%()+;<>=?\[]{}^.,
{% endhint %}

Based of record types, certain fields maybe required. Custom fields are optional. Both fields and custom\_field are an array of values.

### Plugin: `keeper_lookup`

The `keeper_lookup` plugin retrieves a field from the Keeper vault record and inserts the value into a text string. Example:

```yaml
---
- name: Keeper Lookup
  hosts: my_hosts
  
  tasks:
    - name: Write login to file. Get record from the Keeper Vault
      copy:
        content: "My login is {{ lookup('keeper', uid='RECORD UID', field='login') }}"
        dest: "/tmp/my_login.txt"
      no_log: True
      
    - name: Using the array_index and value_key on complex values
      debug:
        msg: >-
          Second phone number is 
          {{ lookup('keeper', uid='RECORD UID', custom_field='My Phone', array_index=1, value_key='number') }}
 
```

In the example above, the first task the content of a file is created by templating the login name of a user from a Keeper record.

The second task displays as debug the second phone of number from a field with a complex value using the `array_index` and `value_key` task attributes. An `array_index` starts at 0, the next item in the array will be 1, the next is 2, a so on. The `value_key` is the name of key in a key/pair dictionary.

#### Required Attributes

* `uid` - A Keeper Vault record UID.
* `title` - Title of a Keeper Vault records.
* `notation` - Use Keeper Notation to get the field from a record.

The attributes `uids` and `titles` can be used at the same time. At least one of them needs to be set.

#### Optional Attributes

* `cache` - The record cache. Used for getting multiple records, will not update the cache.
* `field` - Get the value from the standard Keeper Vault record.
* `custom_field` - Get the value from the custom Keeper Vault record.
* `file` - Get the value from the files attach to the Keeper Vault record by file title.
* `allow_array` - By default is **False**. If set to **True**, an array of values will be returned. This is needed if the field contains multiple values such as Phone numbers. If **True**, `array_index` and `value_key` will be ignored.
* `array_index` - Defaults to 0. If the field value contains multiple values, this attribute will allow you to select which item to return. The first item will have the `array_index` of 0, and the next will be 1, etc.
* `value_key` - If the field value is a complex object, this will allow you to select the key of the key/value pair to return.

#### Important Notes

* To avoid leaking secret values when using the lookup plugin, add `'no_log: True'` to the task. The stdout information will not be logged if the value is True.
* If the plugin was installed by Ansible Galaxy the longer name is required for the lookup plugin (i.e. keepersecurity.keeper\_secrets\_manager.keeper). Listing collections appears not to work with lookup plugins.
* To find out what fields and custom fields are available for a specific vault secret, use the Keeper Secrets Manager CLI "`ksm secret get -u XXXX`" command. More info [here](https://docs.keeper.io/en/keeperpam/secrets-manager-command-line-interface/secret-command#secret-command).

### Plugin: `keeper_init`

The `keeper_init` plugin initialize a configuration from a one time access token. This is similar to the `keeper_ansible --keeper_token` command. The plugin accepts the following options.

* `token` - The one time access token. It's best to template this value and pass in the value.
* `filename` - The configuration file name to generate with config values. If not included, the configuration will not be created.
* `show_config` - A flag to indicate if the configuration values should be returned in the task log. By default this is `False`. Only set to True if you are unable to generate the configuration via other methods or do not have access to a generated configuration file. If True, the configuration will be logged. This might not be a problem if running the playbook via the command line, however if running via Ansible Tower to will be log file which is retained.

```yaml
---
- name: Keeper Lookup
  hosts: localhost
  connection: local
  
  tasks:
    - name: Init the one time access token
      keeper_init:
        token: "{{ keeper_token }}"
        filename: "{{ keeper_config_file }}"
        show_config: False
```

It's best not to hard code the token into the playbook since it's only good once. The token and the configuration file name can be passed into the playbook using the `extra vars`.

```bash
$ ansible-playbook my_init_playbook.yml \
  -e "keeper_token=US:XXX" \
  -e "keeper_config_file=my_keeper_config.yml"
```

The above will generate a file similar to the one below. The content of the file can be copied into a configuration file used by ansible, and optionally encrypted by `ansible-vault`.

```
keeper_app_key: +U5Ja ... 5FmXymVI=
keeper_client_id: Fokc ... WBdUPxPlBwzAKlMUgFZHqLg==
keeper_hostname: US
keeper_private_key: MIGHA ... yA7Oy
keeper_server_public_key_id: '10'
```

#### Ansible Galaxy Role

If the Keeper Secret Manager plugins were installed via Ansible Galaxy, a role called `keeper_init_token` was installed to initialize the one-time access token. This role can be used in a playbook.

```yaml
---
- name: Initialize One Time Access Token
  hosts: localhost
  connection: local
  collections: keepersecurity.keeper_secrets_manager

  roles:
    - keeper_init_token
```

The role will use the following options set via extra variables.

* `keeper_token` - Required one-time access token.
* `keeper_config_file` - Generate a file containing the configuration. If not set, no file will be created.
* `keeper_show_config` *= Default False. If set to True, it will show the config in the log if verbosity is enabled.*

Either `keeper_config_file` or `keeper_show_config` should be used, else the token will initialize and you will not be able to view the resulting configuration.

### Plugin: keeper\_info

The keeper\_info action will display information about the Keeper ansible plugin. The results include a list of record types, field types, and versions of Python modules. In order to see the results, the verbosity level needed to be set at 1 or higher.

```yaml
---
- name: Keeper Info
  hosts: localhost
  connection: local
  
  tasks:
    - name: Display Keeper Info
      keeper_info:
```

This can be used to verify custom record types are being picked up by the plugins.

### Plugin: `keeper_cleanup`

The `keeper_cleanup` plugin is used to clean up any files created by the keeper plugins. This is mainly used to delete a cache file, if you are using it. Disaster Recovey cache files are used when there are network problems as a fall back to get records. If you are running Ansible secret environment, there is no need to remove the Disaster Recovey cache. However this plugin gives you the ability to do so.

```yaml
- name: Keeper Lookup
  hosts: localhost
  connection: local
  vars:
    keeper_use_cache: True
  
  tasks:
    ... bunch of tasks
    
    - name: Remove the cache file
      keeper_cleanup:
    
```

### Plugin: `keeper_redact`

The `keeper_redact` stdout callback plugin is used to redact secrets from the standard out logs. This will work for the `keeper_redact` stdout callback plugin is used to redact secrets from the standard out logs. This will work for the `keeper_copy` and `keeper_get` plugins. It will not redact secret values for `keeper_lookup`. For `keeper_lookup`, use the `no_log: True` directive.

{% hint style="info" %}
See [How do I keep secrets data in my playbook?](https://docs.ansible.com/ansible/latest/reference_appendices/faq.html#keep-secret-data) Using `no_log` can hide all logging from a task. This plugin is for when you just want secrets returned by the Keeper Secrets Manager plugins to be hidden/redacted.
{% endhint %}

{% hint style="info" %}
The `keeper_redact` plugin will not work with Ansible Tower since it had its own stdout callback plugin to stream the log as the job runs. Highly recommend using the `no_log` option when you do not wish show information in the log.
{% endhint %}

To use the `keeper_redact` plugin, enable it in your *ansible.cfg.*

```ini
[defaults]
stdout_callback = keeper_redact
# Use long name if install via Ansible Galaxy
# stdout_callback = keepersecurity.keeper_secrets_manager.keeper_redact
```

For example, the following task would return all the phone numbers in the custom field *MyPhoneNumbers* and place them into the variable *phone\_numbers*.

```yaml
    - name: "Get Phone Numbers"
      keeper_get:
        uid: OlLZ6JLjnyMOS3CiIPHBjw
        custom_field: MyPhoneNumbers
        allow_array: True
      register: phone_numbers
```

If the playbook was run with any verbosity, the values being placed into the variable would be displayed. This would leak the secrets to the log. If the `keeper_redact` stdout callback plugin is enabled, the values in the log would be redacted.

```bash
TASK [Get Phone Numbers] **************************************************
ok: [my_server] => {
    "value": [
        {
            "number": "****",
            "type": "****",
            "ext": "****"
        },
        {
            "region": "****",
            "number": "****",
            "ext": "****",
            "type": "****"
        }
    ],
    "changed": false
}
```

## Ansible Vault Password Retrieval

You can use the Keeper Secret Manager CLI ("ksm") to provide the decryption password for your Ansible vaults. This is done using the ANSIBLE\_VAULT\_PASSWORD\_FILE environment variable or the vault\_password\_file in the ansible.cfg field to specify an executable file that will return a password.

A executable shell script can be created that returns the password using the "ksm" secret notation ([learn more](https://docs.keeper.io/en/keeperpam/secrets-manager-command-line-interface/secret-command#notation) about ksm secret notation). For example, the below script will output a specific secret password for the given Record UID:

```bash
#!/bin/sh
ksm secret notation keeper://XXXX/field/password
```

Replace XXXX with the Vault Record UID. Running this script simply outputs the secret password.

To override the environmental variable "ANSIBLE\_VAULT\_PASSWORD\_FILE", execute the following, replacing /path/to/script with the location of the above script.

```bash
$ ANSIBLE_VAULT_PASSWORD_FILE=/path/to/script.sh ansible-playbook playbook_with_vault.yml
```

Now, when Ansible needs to decrypt any vaults used by `playbook_with_vault.yml`, it will execute that shell script. The shell script will retrieve the password from the Keeper Vault.

## Logging

By default, the Ansible plugins will only display errors. If you use the Ansible verbosity level, different SDK logging will be displayed. An Ansible verbosity level of `-v` will display any SDK messages INFO and higher, while a verbosity level of `-vvv` will display any SDK messages DEBUG and higher.

## Troubleshooting

### \_\_NSPlaceholderDate in progress in another thread when fork() called error.

This appears to be specific to Ansible running on MacOS. While running a playbook you may get the following error:

```
objc[6763]: +[__NSPlaceholderDate initialize] may have been in progress in 
another thread when fork() was called. We cannot safely call it or ignore 
it in the fork() child process. Crashing instead. Set a breakpoint on 
objc_initializeAfterForkError to debug
```

This is known problem with Ansible. This can be fixed with the following environmental variable.

```
OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES ansible-playbook ...
```

### Missing Configuration file

```
TASK [Copy file from Keeper into the file] ********************************************************************************************
An exception occurred during task execution. To see the full traceback, use -vvv. The error was: Exception: Keeper Ansible error: There is no config file and the Ansible variable contain no config keys. Will not be able to connect to the Keeper server.
fatal: [localhost]: FAILED! => {"msg": "Unexpected failure during module execution.", "stdout": ""}
```
