Ansible lookup plugin error throws a <class 'TypeError'> string indices must be integers, not 'str'

Hello.

Trying to get ansible lookup plugin working. I’m following the procedure of this tutorial:

Only difference is that im running all of this from a container in a gitlab CI/CD pipeline.
Basically the container gets the encrypted key mounted at runtime, decrypted using a gitlab ci/cd variable and then imported and parsed. I can confirm that my key gets successfully imported inside the container.

The error that comes up is the following:

TASK [test_hosts : Test!] ******************************************************
task path: REDACTED/tasks/main.yml:2
Loading collection anatomicjc.passbolt from /home/ansibleuser/.ansible/collections/ansible_collections/anatomicjc/passbolt
exception during Jinja2 execution: Traceback (most recent call last):
  File "/usr/lib/python3.11/site-packages/ansible/template/__init__.py", line 856, in _lookup
    ran = instance.run(loop_terms, variables=self._available_variables, **kwargs)
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ansibleuser/.ansible/collections/ansible_collections/anatomicjc/passbolt/plugins/lookup/passbolt.py", line 284, in run
    self.passbolt_init(variables, kwargs)
  File "/home/ansibleuser/.ansible/collections/ansible_collections/anatomicjc/passbolt/plugins/lookup/passbolt.py", line 254, in passbolt_init
    self.p = PassboltAPI(dict_config=self.dict_config)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ansibleuser/.local/lib/python3.11/site-packages/passbolt/__init__.py", line 52, in __init__
    self.login()
  File "/home/ansibleuser/.local/lib/python3.11/site-packages/passbolt/__init__.py", line 173, in login
    self.get_cookie()
  File "/home/ansibleuser/.local/lib/python3.11/site-packages/passbolt/__init__.py", line 156, in get_cookie
    self.user_id = user_id["body"]["id"]
                   ~~~~~~~~~~~~~~~^^^^^^
TypeError: string indices must be integers, not 'str'
fatal: [REDACTED]: FAILED! => {
    "msg": "An unhandled exception occurred while running the lookup plugin 'anatomicjc.passbolt.passbolt'. Error was a <class 'TypeError'>, original message: string indices must be integers, not 'str'. string indices must be integers, not 'str'"
}
PLAY RECAP *********************************************************************

And this is the playbook i’m running:

---
- name: Configure servers
  hosts: testservers
  gather_facts: false
  become: true
  vars:
    ansible_ssh_pass: "{{ lookup('anatomicjc.passbolt.passbolt', 'testhost').password }}"
    ansible_become_password: "{{ lookup('anatomicjc.passbolt.passbolt', 'testhost').password }}"
  roles:
    - test_hosts

Any idea what this could be about? Every error i’ve seen in this forum has been different…

Hi,

Are you able to run your playbook outside gitlab?

If yes, you can try to add a debug task to print your private key. You can also add another task to compute md5sum of the key.

Then run this debug task inside your gitlab CI/CD and compare the output.

I guess the private key format is not correct. It could be the reason you cannot authenticate.

Cheers,

Hi,

I can confirm the md5sum of the key is the same in the container as it is outside of the container, after decrypting it. I compared it with the file i downloaded from passbolt. As its imported i see the name of the passbolt account in the verbose ouput aswell.
In the container I’m running the following commands:

    - gpg -vvv --batch --yes --passphrase "$PGP_PASSPHRASE" --output /tmp/passbolt-key --decrypt /path/to/privkey/privkey.gpg
    - gpg -vvv --import --batch --yes /tmp/passbolt-key
    - gpg -vvv --fingerprint
    - md5sum /tmp/passbolt-key
    - export PASSBOLT_FINGERPRINT=<key-fingerprint>
    - export PASSBOLT_GPG_LIBRARY=gnupg
    - export PASSBOLT_BASE_URL=https://passbolt.domain.com
    - export ANSIBLE_HOST_KEY_CHECKING=False
    - ansible-playbook -i "$ANSIBLE_INVENTORY" site.yml -vvvv

Edit:
I tried doing it locally aswell, without the container. I get a bit different error…

[user@host]$ export PASSBOLT_FINGERPRINT=<fingerprint>
[user@host]$ export PASSBOLT_GPG_LIBRARY=gnupg
[user@host]$ export PASSBOLT_BASE_URL=https://passbolt.domain.com
[user@host]$ export ANSIBLE_HOST_KEY_CHECKING=False
[user@host]$ ls
privkey  test_hosts
[user@host]$ nano play.yml
[user@host]$ ansible-playbook -i test_hosts play.yml -vvv
ansible-playbook [core 2.15.12]
  config file = None
  configured module search path = ['/home/user/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/user/.local/lib/python3.9/site-packages/ansible
  ansible collection location = /home/user/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/user/.local/bin/ansible-playbook
  python version = 3.9.18 (main, Oct  4 2024, 00:00:00) [GCC 11.4.1 20231218 (Red Hat 11.4.1-3)] (/usr/bin/python3)
  jinja version = 3.1.4
  libyaml = True
No config file found; using defaults
host_list declined parsing /home/user/ans/test_hosts as it did not pass its verify_file() method
script declined parsing /home/user/ans/test_hosts as it did not pass its verify_file() method
auto declined parsing /home/user/ans/test_hosts as it did not pass its verify_file() method
Parsed /home/user/ans/test_hosts inventory source with ini plugin
Skipping callback 'default', as we already have a stdout callback.
Skipping callback 'minimal', as we already have a stdout callback.
Skipping callback 'oneline', as we already have a stdout callback.

PLAYBOOK: play.yml ***************************************************************************************************************************************************************************************************************************************************************************
1 plays in play.yml

PLAY [Configure servers] *********************************************************************************************************************************************************************************************************************************************************************

TASK [Test!] *********************************************************************************************************************************************************************************************************************************************************************************
task path: /home/user/ans/play.yml:13
exception during Jinja2 execution: Traceback (most recent call last):
  File "/home/user/.local/lib/python3.9/site-packages/ansible/template/__init__.py", line 879, in _lookup
    ran = instance.run(loop_terms, variables=self._available_variables, **kwargs)
  File "/home/user/.ansible/collections/ansible_collections/anatomicjc/passbolt/plugins/lookup/passbolt.py", line 284, in run
    self.passbolt_init(variables, kwargs)
  File "/home/user/.ansible/collections/ansible_collections/anatomicjc/passbolt/plugins/lookup/passbolt.py", line 254, in passbolt_init
    self.p = PassboltAPI(dict_config=self.dict_config)
  File "/home/user/.local/lib/python3.9/site-packages/passbolt/__init__.py", line 52, in __init__
    self.login()
  File "/home/user/.local/lib/python3.9/site-packages/passbolt/__init__.py", line 173, in login
    self.get_cookie()
  File "/home/user/.local/lib/python3.9/site-packages/passbolt/__init__.py", line 156, in get_cookie
    self.user_id = user_id["body"]["id"]
TypeError: string indices must be integers
fatal: [remote_host]: FAILED! => {
    "msg": "An unhandled exception occurred while running the lookup plugin 'anatomicjc.passbolt.passbolt'. Error was a <class 'TypeError'>, original message: string indices must be integers. string indices must be integers"
}

PLAY RECAP *************************************************************************************************************************************************************************************************************************


Just tested. It only works when i set the PASSBOLT_BASE_URL, PASSBOLT_PRIVATE_KEY and PASSBOLT_PASSPHRASE variables but not when the privkey is gpg imported and i use the PASSBOLT_GPG_LIBRARY and PASSBOLT_FINGERPRINT instead… which is the usecase i kind of need.