Skip to content

redjax/Ansible

Repository files navigation

Homelab

GitHub Created At GitHub last commit GitHub commit activity GitHub repo size GitHub code size in bytes

Warning

This project is undergoing a fairly significant refactor. The documentation will probably lag behind a bit. Until this message is removed, some of the commands and setup instructions may no longer work.

My Ansible monorepo, with roles grouped into importable collections, playbooks, mise for tools installation, go-task/task for automations, and direnv for environment variables.

Table of Contents

Requirements

mise is really the only requirement for this repository. The included .mise.toml handles installing all the other tools.

If you are not using mise, the requirements are:

  • Python
  • uv - uv is used to manage the MkDocs site's dependencies.
  • ansible
  • direnv - For setting environment variables any time you cd into this repository.
    • This is optional, but makes using the repository locally much easier.
  • go-task/task - For repository automations

Setup

If you are using mise, just run:

mise trust
mise install

direnv allow

task ansible-requirements

If you are not using mise, make sure you install all of the requirements. You can use a Python virtualenv to install Ansible, if you want:

direnv allow

python -m pip install -U virtualenv
python -m virtualenv .venv
./.venv/bin/activate
pip install -U ansible

task ansible-requirements

Note

You can install Ansible's requirements manually with ansible-galaxy install -r .config/ansible/requirements.yml.

Now you're ready to create an inventory and run some playbooks.

SSH setup

Note

If you are using direnv, the .envrc file sets the ANSIBLE_SSH_DIR variable for you.

This repository uses a .ssh/ directory to define SSH sessions. This keeps Ansible-specific SSH sessions isolated from your ~/.ssh/config, and your Ansible keys contained in this repository. You can tell Ansible to look in another directory for SSH configuration using the ANSIBLE_SSH_DIR environment variable.

On a new machine, if you are setting up fresh managed infrastructure and do not already have an SSH keypair, start by generating an ansible_svc key (you can use whatever name you want for the keys, I just use ansible_svc/ansible_svc.pub):

ssh-keygen -t ed25519 -b 4096 -f .ssh/ansible_svc -N ""

Copy this key to the host(s) you want to manage with Ansible. Then, copy .ssh/example_config to .ssh/config and edit with your host(s) you want to manage with Ansible.

Tip

You can use the run-onboarding.yml playbook to automatically copy your ansible_svc SSH key to the remote during onboarding. This assumes the remote host has password connections enabled so Ansible can prompt you for the remote connection's password.

The onboarding playbook requires a user with root or sudo privileges. If you provision a machine with just a root account, use the root user in your .ssh/config file and pass -k to your commands.

Example (assumes you have created an onboarding inventory):

ansible-playbook -i inventories/onboard/inventory.yml [--limit <limit-name>] plays/onboard/run-onboarding.yml -k

You can also tell Ansible to prompt you for sudo password when required by passing an uppercase -K along with -k (prompt for SSH connection password).

The onboarding playbook will create an ansible_svc user on the remote. You cannot use a password to authenticate as this user, you must use the ansible_svc SSH key. After running the onboarding playbook, you can run ssh -i .ssh/ansible_svc ansible_svc@<your-hostname-or-ip> to ensure connectivity.

To validate Ansible's SSH connection, run ansible <hostname-or-inventory-group> -m ansible.builtin.ping, or run the ping playbook.

Direnv setup

The .envrc file sets default environment variables to configure the repository. You can create a .envrc.local (copy the contents at the bottom of the .envrc file into the .envrc.local file) and override individual settings.

Whenever you make a change to either .envrc or .envrc.local, you will need to re-run direnv allow.

Whenever you cd into this repository after allowing the .envrc file, direnv will automatically source the file and set your environment variables, and when you leave the repository path it will unset them.

VSCode Setup

If you're editing in VSCode, you need to tell Code where to find your python, ansible, and ansible-config executables. If you are using mise, you can copy the .vscode/example.settings.json file to .vscode/settings.json and use mise's shim paths for the executables.

Links to the binaries for mise-managed tools are in ~/.local/share/mise/shims, but VSCode doesn't expand ~, $HOME, or ${env:HOME}/${userHome} vars in settings.json. That's why you need to create your own settings.json, to paste the path to your mise/shims/ directory:

{
    // ---- Python (used by language server, linting, etc.) ----
    "python.defaultInterpreterPath": "/home/YOUR-USERNAME/.local/share/mise/shims/python",
    // ---- Ansible extension (actual executables) ----
    "ansible.ansible.path": "/home/YOUR-USERNAME/.local/share/mise/shims/ansible",
    "ansible.ansibleConfig.path": "/home/YOUR-USERNAME/.local/share/mise/shims/ansible-config",
    "ansible.python.interpreterPath": "/home/YOUR-USERNAME/.local/share/mise/shims/python",
    // ---- Project defaults ----
    "ansible.inventory": "inventories/homelab/inventory.yml",
    "ansible.playbookDir": "plays",
    "ansible.useFullyQualifiedCollectionNames": true
}

Usage

  • Run task -l to see predefined Ansible tasks.
  • Run individual playbooks with ansible-playbook [--limit <hostname-in-inventory>] plays/path/to/playbook-name.yml
    • By default, the homelab inventory is used.
    • You can target a different inventory with ansible-playbook -i inventories/inventoryName/inventory.yml.
    • Instead of passing -i path/to/inventory.yml, you can also set the ANSIBLE_INVENTORY environment variable.
    • You can also set the value of ANSIBLE_INVENTORY in a .envrc.local file to override the default inventory.

Project directories

Inventories

The inventories/ path is where server infrastructure can be configured. Use an inventory's group_vars/all.yml to set variables for the inventory group, then use ansible-playbook -i inventories/<inventory_name>/inventory.yml ....

To create a new inventory, create a new directory and add inventory and vars files:

  • mkdir inventories/new_inventory/group_vars
    • Create the inventory directory, "new_inventory/", and the group_vars/ directory, where variables for the inventory group are set.
  • touch inventories/new_inventory/inventory.yml
  • touch inventories/new_inventory/group_vars/all.yml
    • Create the group variables file, where you can define variables that apply to the whole inventory.

Tip

If you use an existing directory in inventories/, you should be able to just copy the example.inventory.yml to inventory.yml and edit it.

Example inventory.yml

---
## Define a cluster group, with 2 agents and 2 servers
all:
  hosts:
    ## Add localhost to allow running plays against this machine
    localhost:
      ansible_connection: local
      ansible_python_interpreter: "{{ ansible_playbook_python }}"
    host1:
      ansible_host: "192.168.1.15"
    host2:
      ansible_host: "192.168.1.16"
      ## Remote has SSH on a different port than 22
      ansible_ssh_port: 222
    host3:
      ansible_host: "192.168.1.60"
      ## Login as the root user on this machine
      ansible_user: root
    host4:
      ansible_host: "192.168.1.64"
      ## One of the roles can enable passwordless sudo
      setup_user_passwordless_sudo: true
      ## This host defines ports to allow through a UFW firewall
      ufw_tcp_allowed_ports: ["80", "443", "29281"]
    host5:
      ## This machine was configured before and can use an SSH key for connection.
      #  Tell Ansible where to find that key.
      ansible_ssh_private_key_file: "/home/username/.ssh/id_rsa"
  ## Variables set here apply to the hosts above across all inventory groups
  vars:
    ## Assumes the SSH user for setup is 'root', and that the playbook
    #  will disable SSH login as root
    ansible_user: "root"

## Create a group specifically for onboarding into Ansible management.
onboard:
  hosts:
    ## Re-declare hosts from above. Variables like ansible_host and ansible_user are inherited from the "all" group.
    host1:
    host2:
    host3:
    host4:

  ## Vars set here will only apply when ansible-playbook -i ... --limit onboard is used
  vars:

    ## NOTE: Both of these are set with direnv. They are only here as an example.

    ## Set private key to use for connections.
    ansible_ssh_private_key_file: ".ssh/ansible_svc"
    ## Set public key variable, which is used in the onboard play
    ansible_ssh_public_key_file: ".ssh/ansible_svc.pub"

Plays

Playbooks join collections and roles into repeatable steps/tasks that can be applied to an inventory.

For example, the plays/maint/update-system.yml playbook will run apt or dnf updates/upgrades, and reboot the remote host if required after an update. The playbook uses variables from the inventory's group_vars/all.yml file, and pulls in the update_system role from the my.homelab collection.

Collections

Collections are a distribution format for Ansible content that can include playbooks, roles, modules, and plugins. You can install and use collections through a distribution server, such as Ansible Galaxy, or a Pulp 3 Galaxy server.

Ansible docs: Using Ansible collections

Collections in ./ansible_collections/my/ are built & installed using the `requirements.yml file. Any time a collection changes, it must be rebuilt.

Using Ansible Vault

Encrypting secret variables with Ansible Vault allows for passing secrets like passwords to playbooks/roles. Your vault is encrypted with a vault password, which can be read a number of ways. This project stores the password in a file.

Vault Setup

Password file

This project is relatively small, and with only a single user (me). I've opted to store my password in a file (option 2, 'configuring vault_password_file' in ansible.cfg).

Steps:

  • Edit ansible.cfg and specify the vault_password_file in the [defaults] section:
[defaults]
vault_password_file = /path/to/vault_password_file
  • (Optional) You can also set your vault password as an environment variable, and set vault_password_file to a Bash script that echoes your Ansible vault password:
#!/bin/bash
#
# Assumes you have set an env variable $ANSIBLE_VAULT_PASS to a value matching your vault password
#

echo $ANSIBLE_VAULT_PASS

Each time you run your playbook, Ansible will unlock the vault by reading from the vault_password_file, or echoing the value from the environment (if you set the value to a Bash script).

Devpod/Devcontainer

This repository includes a devcontainer.json. This file is compatible with VSCode Devcontainers and Devpod. The devcontainer builds an environment from the included Dockerfile, then runs it in an isolated environment.

If you're using Devpod, you can setup the environment with the following steps:

  • Add the Docker provider: devpod provider add docker
  • Build/run the workspace: devpod up . --id devpod-ansible
    • To build the workspace & open in VSCode: devpod up . --id devpod-ansible --ide vscode

You can also open the repository in the Devpod GUI, if you've installed that.

Links

About

My Ansible IAC repository for my homelab

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •