Last past year, I created an ansible lookup plugin for passbolt, which allow you to use passbolt as an alternative to ansible-vault to store your secrets.

You can read a very complete blog post about this on passbolt offical blog.

We will start this blog post with a practical example by setup a MySQL database and user with ansible and store the user password in passbolt.

Let’s go.

Requirements

  • A vanilla Ubuntu server on which you will setup the MySQL database
  • You are able to make sudo commands on this server without password
  • A working passbolt instance
  • Your passbolt recovery kit, aka your private GPG key
  • You are able to connect to your server with ansible
ansible -m ping your-server
your-server | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Setup passbolt ansible lookup plugin

You can install the lookup plugin with this command:

ansible-galaxy collection install anatomicjc.passbolt

As it relies on py-passbolt library, you need to install it as well:

python -m pip install py-passbolt

Import your passbolt-recovery-kit, aka private GPG key

the passbolt recovery kit is your private GPG key, you can get a copy from your passbolt personal profile, in Key inspector section

As we will use the python-gnupg backend, you need to import your private key in your GPG keychain:

gpg --import your-passbolt-recovery-kit.txt

You will be prompted for your passphrase.

Set passbolt environment variables

You need to set some environment variables.

export PASSBOLT_FINGERPRINT=064DE03152856A227FEFB0AD56BB3FB586945488
export PASSBOLT_GPG_LIBRARY=gnupg
export PASSBOLT_BASE_URL=https://passbolt.your-domain.com
export PASSBOLT_CREATE_NEW_RESOURCE=true
export PASSBOLT_NEW_RESOURCE_PASSWORD_LENGTH=20
export PASSBOLT_NEW_RESOURCE_PASSWORD_SPECIAL_CHARS=true

We will use the python-gnupg library and you will have to set your own GPG fingerprint. You can get it by listing your registered gpg secrets keys with gpg --list-secret-keys command.

Of course, you need to set your passbolt URL. We also let the ansible lookup plugin create passwords if they don’t exists. We set the default password lenght to 20 and enable special characters.

MySQL setup playbook

Here we go. In the below playbook, we will:

  • Setup mysql-server and adminer, a tool to manage MySQL databases
  • Create “bob” database
  • Create “bob” database user
    • the lookup plugin will search for the passbolt password field of “bob-database” passbolt resource
    • if this resource doesn’t exists, it will be created thanks to the PASSBOLT_CREATE_NEW_RESOURCE environment variable

Once the playbook executed, you will be able to connect to the adminer web UI through http://your-server/adminer and use passbolt web extension to fill the database credentials :-)

- hosts: mysql-server
  gather_facts: no
  become: true
  tasks:
    - name: Install MySQL packages
      ansible.builtin.package:
        name:
          - mysql-server
          - adminer
          - python3-pymysql

    - name: Setup adminer
      ansible.builtin.file:
        src: /etc/apache2/conf-available/adminer.conf
        dest: /etc/apache2/conf-enabled/adminer.conf
        owner: root
        group: root
        state: link
      notify:
        - Restart apache

    - name: Create bob database
      community.mysql.mysql_db:
        name: bob
        state: present
        login_unix_socket: /run/mysqld/mysqld.sock

    - name: Create 'bob' database user
      community.mysql.mysql_user:
        name: bob
        password: "{{ lookup('anatomicjc.passbolt.passbolt', 'bob-database').password }}"
        priv: 'bob.*:ALL'
        state: present
        login_unix_socket: /var/run/mysqld/mysqld.sock

    - name: "Display bob-database password"
      debug:
        var: lookup('anatomicjc.passbolt.passbolt', 'bob-database').password

  handlers:
    - name: Restart apache
      ansible.builtin.service:
        name: apache2
        state: restarted

How to use the lookup plugin

Basically, the lookup plugin will use the first occurence found. Let’s say you have multiple OVH entries.

This lookup will use the first one:

"{{ lookup('anatomicjc.passbolt.passbolt', 'OVH') }}"

If you want the one where username is [email protected], you can filter by username like this:

"{{ lookup('anatomicjc.passbolt.passbolt', 'OVH', username='[email protected]') }}"

If you want to get a specific passbolt resource uuid, you can use the per_uuid filter:

"{{ lookup('anatomicjc.passbolt.passbolt', 'b9dcba41-5880-4a23-8a4c-3ac3564cfa18', per_uuid='true') }}"

Give me more use-cases!!

Setup awscli

You can install awscli and configure the ~/.aws/credentials file with this playbook:

- name: Install awscli package
  ansible.builtin.package:
    name: awscli
    state: installed

- name: Create ~/.aws directory if it does not exist
  ansible.builtin.file:
    path: ${HOME}/.aws
    state: directory
    mode: '0700'

- name: Generate AWS credentials profile
  ansible.builtin.copy:
    dest: ${HOME}/.aws/credentials
    mode: "0600"
    content: |
      [default]
      aws_access_key_id={{ lookup('anatomicjc.passbolt.passbolt', 'AWS').password }}
      aws_secret_access_key={{ lookup('anatomicjc.passbolt.passbolt', 'AWS').description }}

I assume the AWS credentials are stored in passbolt AWS resource, with aws_access_key_id in password field and aws_secret_access_key in description field

Create a Gitlab project

To create a Gitlab project, you need a secret token used with the ansible.builtin.uri ansible module.

- name: Create new Gitlab project
  uri:
    url: "https://gitlab.example.com/api/v4/projects"
    method: POST
    headers:
      PRIVATE-TOKEN: "{{ lookup('anatomicjc.passbolt.passbolt', 'Gitlab').password }}"
      Content-Type: "application/json"
    body_format: json
    body:
      name: "my-new-gitlab-project"
      description: "Some description"

I assume your token is stored in password field of the passbolt Gitlab resource.

Example playbook from official repository

You can also have a look at this example playbook from the passbolt git repository.

Look at the README of the repository. It contains some other infos ;-)

Please enjoy!