This repository provides an Ansible configuration for managing Proxmox VMs and LXCs, with:
ssh vs
community.proxmox.proxmox_pct_remote) based on LXC tags
(sshd vs nosshd).ansible-vault
password storage (no plaintext passwords on disk).ansibledo
user – privilege escalation is seamless.Before using this repository, ensure the following are set up:
| Requirement | Details |
|---|---|
| HashiCorp Vault | A running Vault instance with AppRole
authentication enabled. You need a Role ID and Secret ID with read
access to the secret paths used (e.g.,
ifri/data/infra/proxmox/ansibledo-api-auth). |
| Proxmox API Token | A Proxmox API token (or user/password) with permissions to list
VMs/LXCs, read facts, and execute pct exec for
nosshd containers. The token is stored in Vault (not in
this repo). |
ansibledo user |
A non‑root user (e.g., ansibledo) that exists on
all managed hosts (VMs and LXCs) with
passwordless sudo configured
(/etc/sudoers.d/ansibledo). The SSH public key must be
deployed for SSH‑based connections. |
| GNOME Keyring | Installed and running (secret-tool available). Used to
store the ansible-vault passwords for the vault identities
ansiblevid-apps and ansiblevid-infra. |
| Python 3.11+ | With venv support. |
| Ansible Collections | community.hashi_vault (≥7.0) and
community.proxmox (≥1.0) must be installed. |
| File / Directory | Purpose |
|---|---|
ansible.cfg |
Main configuration: inventories, SSH settings, and
vault_identity_list pointing to the GNOME Keyring
script. |
ansible.cfg.d/gnome-keyring-client.sh |
Script to retrieve ansible-vault passwords from GNOME
Keyring. |
ansible.cfg.d/inventory-conf.proxmox.yml |
Dynamic inventory plugin config for Proxmox – uses HashiCorp Vault for token lookup. |
ansible.cfg.d/requirements.txt |
Python dependencies (Ansible 12, hvac, etc.). |
ansible.cfg.d/requirements.yaml |
Ansible Galaxy collections (e.g.,
community.proxmox). |
inventory/hosts.ini |
Static inventory fallback (localhost, static groups). |
inventory/group_vars/all/hvault.yaml |
Vault connection settings (AppRole). |
inventory/host_vars/localhost/env.yaml |
Local Python interpreter (uses virtualenv). |
.envrc |
Environment variables for HashiCorp Vault auth (source before running). |
| GNOME Keyring (local) | HashiCorp Vault (remote) |
|---|---|
Stores the ansible-vault password for encrypting YAML
variables. |
Stores runtime secrets (Proxmox tokens, DB passwords). |
Accessed via vault_identity_list in
ansible.cfg and secret-tool. |
Accessed via
lookup('community.hashi_vault.hashi_vault', ...). |
Configured once: secret-tool store ... |
Configured via VAULT_ADDR, VAULT_ROLE_ID,
VAULT_SECRET_ID in .envrc. |
The dynamic inventory (inventory-conf.proxmox.yml)
composes ansible_host and ansible_connection
based on the LXC tag:
compose:
ansible_host: "'prox68' if ( proxmox_vmtype == 'lxc' and 'nosshd' in (proxmox_tags_parsed|list) ) else ( proxmox_ipconfig0.ip.split('/')[0] if proxmox_ipconfig0.ip is defined else proxmox_net0.ip.split('/')[0] )"
ansible_connection: "'community.proxmox.proxmox_pct_remote' if ( proxmox_vmtype == 'lxc' and 'nosshd' in (proxmox_tags_parsed|list) ) else 'ssh'"
ansible_user: "'ansibledo'"With sshd tag or VM → SSH connection using the guest IP. With nosshd tag (LXC only) → Proxmox API connection via pct exec (no SSH needed).
source ~/.venvs/ansible12/bin/activate
Store ansible-vault passwords in GNOME Keyring (for identities ansiblevid-apps and ansiblevid-infra):
secret-tool store --label='Ansible Vault - INFRA' application ansible-vault vault-id ansiblevid-infra username $USER
secret-tool store --label='Ansible Vault - APPS' application ansible-vault vault-id ansiblevid-apps username $USERSet HashiCorp Vault environment (source .envrc with your actual AppRole credentials).
Needed vars for all hosts
cat inventory/group_vars/all/hvault.yaml
---
vault_addr: "https://vault.ifri.akl"
vault_auth_method: "approle"
vault_role_id: "{{ lookup('env', 'VAULT_ROLE_ID') }}"
vault_secret_id: "{{ lookup('env', 'VAULT_SECRET_ID') }}"
vault_validate_certs: true
# Pre-built auth string for hashi_vault lookups
_vault_auth: "url={{ vault_addr }} auth_method={{ vault_auth_method }} role_id={{ vault_role_id }} secret_id={{ vault_secret_id }} validate_certs={{ vault_validate_certs }}"Lookup example:
$ ansible localhost -m debug -a "msg={{ lookup('community.hashi_vault.hashi_vault', 'secret=ifri/data/infra/proxmox/ansibledo-api-auth').token_secret }}"
localhost | SUCCESS => {
"msg": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}Explanation: The Proxmox API token for ansibledo@pve user is retrieved securely from HashiCorp Vault – no secret is stored in the inventory or Git.
Example 1: LXC with SSH Enabled (sshd tag) izlan13 has
the sshd tag – Ansible connects via SSH using the container’s IP
(192.168.1.18).
$ ansible-inventory --host izlan13 | egrep -i "ansible_host|ansible_connection|tag"
"ansible_connection": "ssh",
"ansible_host": "192.168.1.18",
"proxmox_description": "Created by OpenTofu. Tags: debian13, sshd. TemplateID 13010\nlxc.apparmor.profile: unconfined\n",
"proxmox_tags": "debian13;sshd",
"proxmox_tags_parsed": [Example 2: LXC Without SSH (nosshd tag) reman13 has the
nosshd tag – Ansible connects via the Proxmox API (pct exec) through the
Proxmox host prox68. No SSH daemon is required in LXC
container.
$ ansible-inventory --host reman13 | egrep -i "ansible_host|ansible_connection|tag"
"ansible_connection": "community.proxmox.proxmox_pct_remote",
"ansible_host": "prox68",
"proxmox_description": "Created by OpenTofu. Tags: debian13, nosshd. TemplateID 13012\n",
"proxmox_tags": "debian13;nosshd",
"proxmox_tags_parsed": [