> ## Documentation Index
> Fetch the complete documentation index at: https://docs.futurex.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Validate the Ansible integration

> Prove CryptoHub-backed signing and native Ansible SSH authentication without exporting the private key.

Validate both supported Ansible paths with one CryptoHub-backed RSA key:

* Sign data from an OpenSSL command task.
* Authenticate Ansible's SSH connection plugin to a managed host.

## Generate the CryptoHub key

<Steps>
  <Step>
    Set the client-library configuration path and open the endpoint-provided
    manager:

    ```bash theme={null}
    export CHLIBS_CONFIG=/etc/ansible/cryptohub/cryptohub.json
    pkcs11-manager /etc/ansible/cryptohub/cryptohub.json
    ```

    Initialize the module and log in with the endpoint UserPass password.
  </Step>

  <Step>
    Generate an RSA-2048 key named `ansible_rsa_privatekey`.

    The template creates the key as `TRUSTED` with Sign and Verify usages. Both
    procedures below use this single RSA usage class.
  </Step>

  <Step>
    Install OpenSC, export the public key, and convert it to PEM:

    ```bash theme={null}
    sudo apt install -y opensc
    pkcs11-tool --module /usr/local/lib/libcryptohub-pkcs11.so \
      --read-object --type pubkey --label ansible_rsa_privatekey \
      --output-file /tmp/ansible-public.der
    openssl pkey -pubin -inform DER -in /tmp/ansible-public.der \
      -out /tmp/ansible-public.pem
    sudo install -m 644 /tmp/ansible-public.pem \
      /etc/ansible/cryptohub/ansible-public.pem
    ```

    The PEM file contains only the public key. The private key remains in
    CryptoHub.
  </Step>
</Steps>

## Sign data from a playbook

<Steps>
  <Step>
    Read the PKCS #11 token label from the endpoint configuration:

    ```bash theme={null}
    jq -r '.cryptohubs[0].label' /etc/ansible/cryptohub/cryptohub.json
    ```

    Use the returned label for `<token-label>` in the next step.
  </Step>

  <Step>
    Create `sign.yml`:

    ```yaml theme={null}
    ---
    - name: Sign with a CryptoHub key
      hosts: localhost
      connection: local
      gather_facts: false
      vars:
        pkcs11_uri: "pkcs11:token=<token-label>;object=ansible_rsa_privatekey;type=private"
      environment:
        OPENSSL_CONF: /etc/ansible/cryptohub/openssl-cryptohub.cnf
        CHLIBS_CONFIG: /etc/ansible/cryptohub/cryptohub.json
      tasks:
        - name: Create proof data
          ansible.builtin.copy:
            dest: /tmp/ansible-message.txt
            content: "Ansible CryptoHub signing proof"
            mode: "0600"

        - name: Sign with the CryptoHub key
          ansible.builtin.command:
            argv:
              - openssl
              - dgst
              - -provider
              - pkcs11
              - -provider
              - default
              - -sha256
              - -sign
              - "{{ pkcs11_uri }}"
              - -out
              - /tmp/ansible-signature.bin
              - /tmp/ansible-message.txt

        - name: Verify the signature
          ansible.builtin.command:
            argv:
              - openssl
              - dgst
              - -sha256
              - -verify
              - /etc/ansible/cryptohub/ansible-public.pem
              - -signature
              - /tmp/ansible-signature.bin
              - /tmp/ansible-message.txt
          register: verify_result
          changed_when: false

        - name: Require a valid signature
          ansible.builtin.assert:
            that:
              - verify_result.rc == 0
              - "'Verified OK' in verify_result.stdout"
    ```
  </Step>

  <Step>
    Run the playbook:

    ```bash theme={null}
    ansible-playbook -i localhost, sign.yml
    ```

    The **Verify the signature** task reports `ok`, the assertion reports
    `All assertions passed`, and the play recap reports `failed=0`.
  </Step>
</Steps>

## Authenticate Ansible SSH with the CryptoHub key

Ansible Core 2.12 and later provides the
`ansible_ssh_pkcs11_provider` connection option. The plugin uses `sshpass` to
supply the PKCS #11 PIN through a protected input pipe.

<Steps>
  <Step>
    Install `sshpass` and convert the public key to OpenSSH format:

    ```bash theme={null}
    sudo apt install -y sshpass
    ssh-keygen -i -m PKCS8 \
      -f /etc/ansible/cryptohub/ansible-public.pem > ansible-public.ssh
    ```

    `sshpass -V` must report version 1.06 or later.
  </Step>

  <Step>
    Add `ansible-public.ssh` to the target account's
    `~/.ssh/authorized_keys`.

    The target account now trusts the public half of the CryptoHub key.
  </Step>

  <Step>
    Create a protected variable file. The command reads the endpoint UserPass
    password without echoing it and JSON-encodes the value as valid YAML:

    ```bash theme={null}
    sudo install -m 640 -o root -g <ansible-runner-group> /dev/null \
      /etc/ansible/cryptohub/ssh-pin-vars.yml
    read -r -s -p "Endpoint UserPass password: " ANSIBLE_PKCS11_PIN
    printf '\n'
    printf '%s' "$ANSIBLE_PKCS11_PIN" | \
      python3 -c 'import json, sys; print("ansible_password: " + json.dumps(sys.stdin.read()))' | \
      sudo tee /etc/ansible/cryptohub/ssh-pin-vars.yml >/dev/null
    unset ANSIBLE_PKCS11_PIN
    sudo chown root:<ansible-runner-group> /etc/ansible/cryptohub/ssh-pin-vars.yml
    sudo chmod 640 /etc/ansible/cryptohub/ssh-pin-vars.yml
    ```

    Encrypt this variable with Ansible Vault or supply it from your approved
    controller credential store when your policy requires encrypted secrets at
    rest.
  </Step>

  <Step>
    Create `inventory.ini`. Replace `<target-host>` and `<target-user>`:

    ```ini theme={null}
    [pkcs11_targets]
    target ansible_host=<target-host> ansible_user=<target-user> ansible_connection=ssh ansible_ssh_pkcs11_provider=/usr/local/lib/libcryptohub-pkcs11.so ansible_ssh_common_args='-o PreferredAuthentications=publickey -o PasswordAuthentication=no -o KbdInteractiveAuthentication=no'
    ```

    Do not add `IdentitiesOnly=yes`. That option prevents OpenSSH from trying keys
    enumerated through the PKCS #11 provider.
  </Step>

  <Step>
    Create `ssh.yml`:

    ```yaml theme={null}
    ---
    - name: Authenticate SSH with a CryptoHub key
      hosts: pkcs11_targets
      gather_facts: false
      vars_files:
        - /etc/ansible/cryptohub/ssh-pin-vars.yml
      tasks:
        - name: Read the managed host name
          ansible.builtin.command:
            argv:
              - hostname
          register: hostname_result
          changed_when: false

        - name: Display the managed host name
          ansible.builtin.debug:
            var: hostname_result.stdout
    ```
  </Step>

  <Step>
    Set `CHLIBS_CONFIG` in the controller shell and run the playbook:

    ```bash theme={null}
    export CHLIBS_CONFIG=/etc/ansible/cryptohub/cryptohub.json
    ansible-playbook -i inventory.ini ssh.yml
    ```

    Set this variable in the controller shell, not the playbook `environment:`
    block. The Ansible environment keyword applies to remote tasks, not the SSH
    connection plugin.

    A successful run prints the target hostname and reports `unreachable=0` and
    `failed=0`.
  </Step>
</Steps>

## Troubleshoot the validation

* `No configuration file found`: export `CHLIBS_CONFIG` in the process that
  loads the module.
* `operation not supported for this keytype` from `openssl dgst`: confirm that
  `OPENSSL_CONF` loads `pkcs11-provider` 1.2.0 instead of the Ubuntu 24.04
  distribution's 0.3 provider.
* `to use pkcs11_provider you must specify a password/pin`: load the endpoint
  UserPass password from the protected Ansible variable source.
* `Permission denied (publickey)` after OpenSSH enumerates the matching key:
  confirm that the public key is in `authorized_keys` and remove
  `IdentitiesOnly=yes` from the SSH arguments.
