Naming things is hard
There are only two hard things in Computer Science: cache invalidation and naming things. – Phil Karlton Coming up with a consistent naming …
Read ArticleHaving 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.
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
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.
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.
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
.....
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.
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>
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'
If you don’t have jq already installed in your WSL2 environment you can install it as follows:
sudo apt install jq
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
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.
Note: All the shell based helpers will focus on Zsh and Oh-My-Zsh as these are what I use as my shell environment.
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
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
There are only two hard things in Computer Science: cache invalidation and naming things. – Phil Karlton Coming up with a consistent naming …
Read ArticleRFC1918 defines the following 3 blocks for private internets / networks leaving the choice up to the network administrator of which is most …
Read Article