Creating an Ansible workspace with 1Password integration

post-thumb

Having set myself the aim of automating as much as possible within my HomeLab, setting up my admin workstation and configuring this ready to control everything is a clear first step.

With a range of Infrastructure as Code (IaC) tools and platforms out there and each of them have their own pros and cons, there’s a lot of choice and making a decision can impact the direction of how automation will be built. For me, the agentless nature and push vs pull model of Ansible alongside the large community were clear standouts for my use case and given I’ve used Ansible previously it seemed like a sensible choice going forward.

Something I was keen to look at was integrating my Ansible workflow with 1Password which I’ve used for years as my password manager both personally and professionally to better store secrets and allow easy management of the Ansible vault password but also retrieving secrets in the future. For now I’m going to go down the traditional Ansible model of using the Ansible Vault and retrieving the vault password from 1Password at run time.

The rest of this post goes through setting up Ansible on Ubuntu 20.04 in WSL2 running on Windows 11.

Installing Ansible

Running the following commands within WSL2 should give us the latest version of Ansible including all the collections. At the time of writing this installed Ansible 5.8.0-1.

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible

Verify Ansible installation

To check ansible is installed and configured correctly we can request the version information which will also give us some useful path info as well.

ansible --version

Output

ansible [core 2.12.6]
  config file = /etc/ansible/ansible.cfg
  configured module search path = ['/home/stephen/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /usr/lib/python3/dist-packages/ansible
  ansible collection location = /home/stephen/.ansible/collections:/usr/share/ansible/collections
  executable location = /usr/bin/ansible
  python version = 3.8.10 (default, Mar 15 2022, 12:22:08) [GCC 9.4.0]
  jinja version = 2.10.1
  libyaml = True

Note: Versions of libraries and Ansible may vary as new versions are released.

Installing 1Password CLI

The 1Password developer documentation has some great instructions for installing the 1Password CLI from their Apt repo and the following instructions are taken from there.

1 - Add the GPG key for 1Password Apt repository

curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
 sudo gpg --dearmor --output /usr/share/keyrings/1password-archive-keyring.gpg

2 - Add the 1Password Apt repository

echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/1password-archive-keyring.gpg] https://downloads.1password.com/linux/debian/$(dpkg --print-architecture) stable main" |
 sudo tee /etc/apt/sources.list.d/1password.list

3 - Add the policy for checking the signature

sudo mkdir -p /etc/debsig/policies/AC2D62742012EA22/
curl -sS https://downloads.1password.com/linux/debian/debsig/1password.pol | \
 sudo tee /etc/debsig/policies/AC2D62742012EA22/1password.pol
sudo mkdir -p /usr/share/debsig/keyrings/AC2D62742012EA22
curl -sS https://downloads.1password.com/linux/keys/1password.asc | \
 sudo gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg

4 - Install 1Passowrd CLI

sudo apt update && sudo apt install 1password-cli

5 - Verify the installation by checking the version

op --version

Output

2.4.0

Note: Your version may differ if a later one has been released.

Configuring 1Password CLI

With 1Password CLI installed we need to login and link it to our 1Password account. If you’re using a personal or family plan in the EU region then you can use the following command.

op account add --address my.1password.eu

If you’re in the US region or using a work based 1Password account then the login will be similar to

op account add --address <your-account-domain>.1password.com

This will then prompt you to sign in to your 1Password account:

Enter the email address for your account on my.1password.eu:
Enter the Secret Key for <YOUR_EMAIL_ADDRESS> on my.1password.eu:
Enter the password for <YOUR_EMAIL_ADDRESS> at my.1password.eu:

Now we have added our account we can sign in to it and make the op CLI use our account.

eval $(op signin)

This will prompt you for your 1Password master password and then set the necessary environment variables ready for use.

Enter the password for <YOUR_EMAIL_ADDRESS> at my.1password.eu:

Now we are signed in we can check everything is working by listing the 1Password vaults

op vault ls

Output

ID                            NAME
aaaaaaaaaaaaaaaaaaaaaaaaaa    Private
bbbbbbbbbbbbbbbbbbbbbbbbbb    Homelab
cccccccccccccccccccccccccc    Shared
.....

Linking Ansible to 1Password

With 1Password CLI now configured and working its time to tell Ansible to retrieve the vault password from 1Password.

As you can see above I have a vault within 1Password called Homelab which contains all the credentials related to my Homelab with a vault ID of bbbbbbbbbbbbbbbbbbbbbbbbbb.

Creating the 1Password entry

If you don’t already have an entry in your 1Password vault for Ansible then we can create one using the following command.

op item create \
	--category password \
    --title "Ansible Vault" \
    --vault Homelab \
    --generate-password='letters,digits,symbols,32'

This will add a generate a new 32 character password called “Ansible Vault” and add place it in the Homelab vault. The output of this command is some basic information about the entry including the generated password

ID:          hhhhhhhhhhhhhhhhhhhhhhhhhh
Title:       Ansible Vault
Vault:       Homelab (bbbbbbbbbbbbbbbbbbbbbbbbbb)
Created:     now
Updated:     now
Favorite:    false
Version:     0
Category:    PASSWORD
Fields:
  password:    <YOUR GENERATED_PASSWORD_HERE>

Retrieve the 1Password entry

Now that we have an entry in 1Password for our Ansible Vault password we can go and retrieve is using the get commands, formatting as json will allow us to interact with the output programmatically later.

op item get --vault Homelab "Ansible Vault" --format json

Output

{
  "id": "hhhhhhhhhhhhhhhhhhhhhhhhhh",
  "title": "Ansible Vault",
  "version": 1,
  "vault": {
    "id": "bbbbbbbbbbbbbbbbbbbbbbbbbb",
    "name": "Homelab"
  },
  "category": "PASSWORD",
  "last_edited_by": "MY_ID",
  "created_at": "2022-06-03T12:38:17Z",
  "updated_at": "2022-06-03T12:38:17Z",
  "additional_information": "Fri Jun  3 13:38:17 BST 2022",
  "fields": [
    {
      "id": "password",
      "type": "CONCEALED",
      "purpose": "PASSWORD",
      "label": "password",
      "value": "YOUR_ANSIBLE_VAULT_PASSWORD",
      "entropy": 189.70021057128906,
      "reference": "op://Homelab/Ansible Vault/password",
      "password_details": {
        "entropy": 189,
        "generated": true,
        "strength": "FANTASTIC"
      }
    },
    {
      "id": "notesPlain",
      "type": "STRING",
      "purpose": "NOTES",
      "label": "notesPlain",
      "reference": "op://Homelab/Ansible Vault/notesPlain"
    }
  ]
}

By piping this output through jq and using a path filter we can get the raw password value to use for our ansible commands.

By passing the ‘-r’ parameter to jq we can get the raw value instead of the quoted value as can be seen in the output above.

op item get --vault Homelab "Ansible Vault" --format json | jq -r '.fields[] | select(.id=="password").value'

Install JQ

If you don’t have jq already installed in your WSL2 environment you can install it as follows:

sudo apt install jq

Creating an ansible vault script

Now we have a command to retrieve the vault password we can put this into a script that can be used when running ansible commands to retrieve the value.

mkdir ~/.bin

cat <<EOF > ~/.bin/op-ansible-vault
#!/bin/bash
OP_VAULT_NAME="Homelab"
OP_VAULT_PASSWORD_NAME="Ansible Vault"

op item get --vault \$OP_VAULT_NAME "\$OP_VAULT_PASSWORD_NAME" --format json | jq -r '.fields[] | select(.id=="password").value'
EOF

chmod +x ~/.bin/op-ansible-vault

Checking it all works

Ansible Vault CLI

Lets encrypt a super secret password using ansible vault.

ansible-vault encrypt_string 'my_super_secret_password' \
	--name 'ansible_password' \
    --vault-password-file=~/.bin/op-ansible-vault

If you’ve used the helper below to set the default ansible vault password file you can omit the ‘vault-password-file’ parameter and run the command as follows:

ansible-vault encrypt_string 'my_super_secret_password' \
	--name 'ansible_password' \

Output

ansible_password: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          62636232633163373234363036643536343463656262656636383037666134383938303638306333
          3064373861623835643835303066643961326233313934620a653431363433353966663837346533
          64626563363066316163333132313164636537666231666235353661323034353234303562383864
          3838376539323364350a303831343537363032383235343731303361636634333364373330616135
          35616338313530316333353032313137623561613461353562613761373338323565
Encryption successful

With everything now setup in the ansible workspace we can move forward with automating everything in the Homelab.

Some nice to haves

Note: All the shell based helpers will focus on Zsh and Oh-My-Zsh as these are what I use as my shell environment.

Add our bin directory to path

If we want quick and easy access to the op-ansible-vault command we can add our bin directory to the path so we can access this everywhere.

cat <<EOF > ~/.oh-my-zsh/custom/path.zsh
path+=('/home/stephen/.bin')
EOF

Set Ansible default password file

So we don’t have to specify the parameter to the password file every time we run an ansible command we can set an environment variable that specifies the default file to use when the parameter is not specified.

cat <<EOF > ~/.oh-my-zsh/custom/ansible.zsh
export ANSIBLE_VAULT_PASSWORD_FILE=~/.bin/op-ansible-vault
EOF

References

You May Also Like