# Puppet

<figure><img src="https://762006384-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MJXOXEifAmpyvNVL1to%2Fuploads%2FbiquqcqGv3mpB5xWyQqM%2Fkeeper%2Bpuppet.png?alt=media&#x26;token=6b17130d-ff4a-4ab2-aaa8-4d2e1396f21d" alt=""><figcaption></figcaption></figure>

## About

Puppet is a powerful infrastructure automation platform that enables consistent and scalable configuration management across your entire IT environment. A solution that supports successful infrastructure as code (IaC), automated provisioning, and continuous compliance within your DevOps process.

The module facilitates secure integration between Puppet and Keeper Secret Manager, enabling the retrieval of secrets during catalog execution.

## Features

* Use secrets from the Keeper vault in Puppet at catalog execution.
* Supports Base64, JSON and Token authentication configuration.
* Supports secret output to JSON response, files and environment variables

## Prerequisites

* 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 subscription
  * 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)
  * Puppet module accepts Base64, Token, JSON format configurations
* System Requirements
  * **Puppet**: 7.24 or later (for `preprocess_deferred` support)
  * **Python**: 3.6 or later on agent nodes
  * **Supported Operating Systems**: Linux, macOS, Windows
* Critical Configuration
  * **Required**: Add this setting to your agent's `puppet.conf`:

    ```ini
    [agent]
    preprocess_deferred = false
    ```

    This ensures deferred functions execute during catalog enforcement, not before.

## Secrets Notation Format <a href="#secrets-notation-format" id="secrets-notation-format"></a>

#### Notation Format <a href="#notation-format" id="notation-format"></a>

The notation follows the pattern: `"KEEPER_NOTATION > OUTPUT_SPECIFICATION"`

**Left side**: Uses [Keeper notation](https://docs.keeper.io/en/keeperpam/secrets-manager/about/keeper-notation) format

**Right side**: Output specification

* `VARIABLE_NAME` (eg: `Label2`)
* `env:VARIABLE_NAME` (eg: `env:Label2`)
* `file:/path/to/file-on-agent` (eg: `file:/opt/ssl/cert.pem`)

<table><thead><tr><th width="227">Notation\Destination prefix</th><th width="181">Default (empty)</th><th width="184">env:</th><th>file:</th></tr></thead><tbody><tr><td><code>field</code> or <code>custom_field</code></td><td>Notation query result<br>is placed into JSON output</td><td>Notation query result<br>is exported as environment variable on agent</td><td>Not allowed</td></tr><tr><td><code>file</code></td><td>file is downloaded and<br>placed into agent's destination</td><td>file is downloaded and<br>placed into agent's destination</td><td>file is downloaded and<br>placed into agent's destination</td></tr></tbody></table>

#### Examples: <a href="#examples" id="examples"></a>

**1. Default (empty)**

{% code overflow="wrap" %}

```puppet
"UID/custom_field/Label1 > Label2"
# Output JSON: { "Label2": "VALUE_HERE" }
```

{% endcode %}

**2. Environment Variable Output ( `env:` )**

{% code overflow="wrap" %}

```puppet
"secret-uid/field/password > env:DB_PASSWORD"
# Sets DB_PASSWORD environment variable on agent node
# Note: env:DB_PASSWORD will be exported as environment variable, and DB_PASSWORD will not be included in output JSON
```

{% endcode %}

**3. File Output (`file:`)**

{% code overflow="wrap" %}

```puppet
"secret-uid/file/ssl_cert.pem > file:/opt/ssl/cert.pem"
# Downloads file to specified path on agent node
# Output JSON: { "ssl_cert.pem": "/opt/ssl/cert.pem" }
# Note: filename becomes the key, file path on agent becomes the value
```

{% endcode %}

## Setup <a href="#configuring-discovery-credentials" id="configuring-discovery-credentials"></a>

### Step 1: Install the Module <a href="#step-1-install-the-module" id="step-1-install-the-module"></a>

{% code overflow="wrap" %}

```bash
# Install from Puppet Forge
puppet module install keepersecurity-keeper_secrets_manager_puppet
```

{% endcode %}

### Step 2: Configure Hiera <a href="#step-2-configure-hiera" id="step-2-configure-hiera"></a>

Create or update your Hiera configuration file (eg : `data/common.yaml`):

#### **Configuration Structure**

**Basic Configuration (Required)**

{% tabs %}
{% tab title="YAML" %}

```yaml
keeper::config:
  authentication:
    - "AUTH_TYPE"    # base64, token, or json
    - "AUTH_VALUE"   # your credentials or ENV:KEEPER_CONFIG
```

{% endtab %}

{% tab title="JSON" %}

```json
{
  "keeper::config": {
    "authentication": [
      "AUTH_TYPE", # base64, token, or json
      "AUTH_VALUE" # your credentials or ENV:KEEPER_CONFIG
    ]
  }
}

```

{% endtab %}
{% endtabs %}

**Adding Secrets (Optional)**

{% hint style="info" %}
These secrets will be retrieved when `Default Lookup` is used as the parameter type.
{% endhint %}

{% tabs %}
{% tab title="YAML" %}

```yaml
keeper::config:
  authentication:
    - "AUTH_TYPE"
    - "AUTH_VALUE"
  secrets: # Optional: List of secrets to retrieve
    - "your-secret-uid/title > title"
    - "your-secret-uid/field/login > login_name"
    - "your-secret-uid/field/password > env:DB_PASSWORD"
```

{% endtab %}

{% tab title="JSON" %}

```json
{
  "authentication": ["AUTH_TYPE", "AUTH_VALUE"],
  "secrets": [
    "your-secret-uid/title > title",
    "your-secret-uid/field/login > login_name",
    "your-secret-uid/field/password > env:DB_PASSWORD"
  ]
}

```

{% endtab %}
{% endtabs %}

**Configuration Details:**

* **`keeper::config`** (Required): Main configuration container
* **`authentication`** (Required): Array with exactly 2 elements:
  * `[0]`: Authentication type (`base64`, `token`, or `json`)
  * `[1]`: Authentication value (your credentials or `ENV:VARIABLE_NAME`)
* **`secrets`** *(Optional)*: Array of Secrets notation strings

{% hint style="info" %}
Passing the `secrets` array under `keeper::config` can be skipped if you are passing the <mark style="color:orange;">secrets array</mark> or <mark style="color:orange;">single secret</mark> directly as a parameter in the\
`Deferred('keeper_secrets_manager_puppet::lookup', [SECRETS_ARRAY_HERE])` function call.
{% endhint %}

### Step 3: Set Up Environment Variable (Optional) <a href="#step-3-set-up-environment-variable-optional" id="step-3-set-up-environment-variable-optional"></a>

If you're using `ENV:KEEPER_CONFIG` for *AUTH\_VALUE*, then set the environment variable on your `Puppet master`:

```bash
# For base64 authentication (recommended)
echo "KEEPER_CONFIG='your-base64-string-configuration'" >> /etc/environment

# For token authentication
echo "KEEPER_CONFIG='your-token-configuration'" >> /etc/environment

# For JSON authentication
echo "KEEPER_CONFIG='your-json-configuration-path-on-master'" >> /etc/environment
```

{% hint style="info" %}
Instead of using `KEEPER_CONFIG`, you may specify your own environment variable name when exposing the environment variable.
{% endhint %}

## Usage <a href="#usage" id="usage"></a>

### **Include the Module**

```puppet
# Include the module in your manifests
contain keeper_secrets_manager_puppet
```

### **Using the Custom Lookup Function with Deferred**

The module provides a custom function `keeper_secrets_manager_puppet::lookup` that must be used with Puppet's `Deferred()` wrapper for runtime execution. [Learn more about Deferred Functions](https://www.puppet.com/docs/puppet/7/deferred_functions)

The `Deferred('keeper_secrets_manager_puppet::lookup', [])` function accepts three parameter options:

<table><thead><tr><th width="152">Parameter Type</th><th width="138">Description</th><th>Example</th></tr></thead><tbody><tr><td><strong>No Parameters</strong></td><td>Uses secrets from Hiera configuration</td><td><code>Deferred('keeper_secrets_manager_puppet::lookup', [])</code></td></tr><tr><td><strong>Array[String]</strong></td><td>Uses secrets from parameters</td><td><code>Deferred('keeper_secrets_manager_puppet::lookup', [$secrets_array])</code></td></tr><tr><td><strong>String</strong></td><td>Uses secrets from parameters</td><td><code>Deferred('keeper_secrets_manager_puppet::lookup', ['UID/field/login > login_name'])</code></td></tr></tbody></table>

#### **Detailed Examples**

**Option 1: Default Lookup - No Parameters**

```puppet
# Uses secrets defined in Hiera configuration
$secrets = Deferred('keeper_secrets_manager_puppet::lookup', [])
```

**Option 2: Array of Strings**

```puppet
# Define secrets array
$secrets_array = [
  'UID/custom_field/Label1 > Label2',
  'UID/field/login > agent2_login',
  'UID/field/password > env:agent2_password',
  'UID/file/ssl_cert.pem > file:/etc/ssl/certs/agent2_ssl_cert.pem',
]

$secrets = Deferred('keeper_secrets_manager_puppet::lookup', [$secrets_array])
```

**Option 3: Single String**

```puppet
# Single secret lookup
$secrets = Deferred('keeper_secrets_manager_puppet::lookup', ['UID/field/login > agent2_login'])
```

## Complete Example <a href="#complete-example" id="complete-example"></a>

```puppet
node 'puppetagent' {
  # Include the keeper module
  contain keeper_secrets_manager_puppet

  # Define secrets to retrieve
  $secrets = [
    'UID/custom_field/Label1 > Label2',
    'UID/field/login > agent2_login',
    'UID/field/password > env:agent2_password',
    'UID/file/ssl_cert.pem > file:/etc/ssl/certs/agent2_ssl_cert.pem',
  ]

  # Fetch secrets using deferred function
  $secrets_result = Deferred('keeper_secrets_manager_puppet::lookup', [$secrets])
  
  # Access individual values from JSON response
  $agent2_login_value = Deferred('dig', [$secrets_result, 'agent2_login'])

  # Use retrieved secrets
  notify { 'Retrieved secrets':
    message => $agent2_login_value,
  }

  # Use environment variable set by the module
  exec { 'create_file_with_secret':
    command => '/bin/echo $agent2_password > /tmp/secret.txt',
    path    => ['/bin', '/usr/bin'],
  }
}
```

## Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

#### Debug Mode <a href="#debug-mode" id="debug-mode"></a>

Enable debug logging by setting the log level in your Puppet configuration:

```ini
[agent]
log_level = debug
```

#### Common Issues <a href="#common-issues" id="common-issues"></a>

1. **"preprocess\_deferred = false" Error**
   * **Problem**: Module fails with configuration error
   * **Solution**: Add `preprocess_deferred = false` to the `[agent]` section of your `puppet.conf`
2. **"KSM script not found" Error**
   * **Problem**: Deferred function fails on first run
   * **Solution**: Ensure the module is properly included and Python installation completes
3. **Authentication Failures**
   * **Problem**: "Authentication failed" errors or\
     `Error: access_denied, message=Unable to validate Keeper application access`
   * **Solution**: Verify Keeper authentication credentials in configuration and network connectivity
