rationale Link to heading
let’s be honest it’s a pain in the ass to maintain a static inventory in proxmox infrastructure.
let’s have a dynamic one
requirements : Link to heading
- ansible controller with plugins and proxmoxer
- proxmox 7 or 8 with proxmoxer and api user
- a bunch of ct/vm with ip and correct ssh setup
setup proxmox user Link to heading
- we use api instead of pam credentials
as we need this user to deploy ct/vm in the future we give him/her Administrator role
pveum group add admin -comment "System Administrators"
pveum acl modify / -group admin -role Administrator
we create a new admin user and attach him/her to the sysadmin group :
pveum user add 6admin@pve -comment "sysadmin"
pveum user modify 6admin@pve -group admin
now we need to create the token :
- warning : we use privsep 0 because we’ll use this token to do some administrative stuff. read the documentation to use a privilege separation.
pveum user token add 6admin@pve Administrator -privsep 0
┌──────────────┬──────────────────────────────────────┐
│ key │ value │
╞══════════════╪══════════════════════════════════════╡
│ full-tokenid │ 6admin@pve!Administrator │
├──────────────┼──────────────────────────────────────┤
│ info │ {"privsep":0} │
├──────────────┼──────────────────────────────────────┤
│ value │ redacted │
└──────────────┴──────────────────────────────────────┘
note that token there is no way to find it afterwards
check users permissions :
pveum user token permissions 6admin@pve Administrator
check if your token works from a remote client :
- never keep a cleartext token in your shell history use a space at the beginning of the command to exclude it from the history.
curl -k -H 'Authorization: PVEAPIToken=6admin@pve!Administrator=redacted' https://xxx.xxx.xxx.xxx:8006/api2/json/
you should see this
{"data":[{"subdir":"version"},{"subdir":"cluster"},{"subdir":"nodes"},{"subdir":"storage"},{"subdir":"access"},{"subdir":"pools"}]}
if not make sure you followed the aforementioned steps and read tha mothafuckin doc
setup proxmoxer on proxmox Link to heading
simply install the packaged proxmoxer
sudo apt install -y python3-proxmoxer
if it’s buggy or doesnt fit your need you should get it with pip
sudo apt install python3-pip && pip install proxmoxer
setup your ansible controller Link to heading
we assume your ansible directory is ~/ansible
we need some ansible collection
ansible-galaxy collection install community.general
enable the correct options
ansible.cfg
[defaults]
inventory_plugins = ~/ansible/plugins/inventory
[inventory]
enable_plugins = host_list, yaml, constructed, ini, auto, community.general.proxmox
use_extra_vars = true
generate on the fly vaulted secrets Link to heading
you can generate your vaulted passwords or anything on the fly as follows
- remember never keep cleartext secrets in your history
echo -n 'YOURSUPERTOKEN' | ansible-vault encrypt_string
- the ansible vault password has to be the same as your real vault password if you have a big fat vault.
you’ll have this output :
!vault |
$ANSIBLE_VAULT;1.1;AES256
32623338643462356533313438646136346464346432353437623839663635323466323133333732
3733363633373565363330633235643762326133383131330a376665313934626531613331373031
38633339383363346536616464343066336464646636323766313533613731343162333762663464
3031663039303363620a633964373866633435623330313130326666373739636166633162333461
6139
setup the plugin Link to heading
create the plugin directory whithin you ansible directory and edit the file matching your setup
mkdir -p ~/ansible/plugins/inventory
- the filename of your plugin must end as follows
*.proxmox.yml
~/ansible/plugins/inventory/myserver.proxmox.yml
plugin: community.general.proxmox
url: https://xxx.xxx.xxx.xxx:8006
user: 6admin@pve
token_id: Administrator
# generated via echo -n 'YOURSUPERTOKEN' | ansible-vault encrypt_string
# the password has to be the same as your vault for more convenience
token_secret: !vault |
$ANSIBLE_VAULT;1.1;AES256
32623338643462356533313438646136346464346432353437623839663635323466323133333732
3733363633373565363330633235643762326133383131330a376665313934626531613331373031
38633339383363346536616464343066336464646636323766313533613731343162333762663464
3031663039303363620a633964373866633435623330313130326666373739636166633162333461
6139
validate_certs: false
want_facts: true
# create groups based on proxmox tags
groups:
preprod: "'preprod' in (proxmox_tags_parsed|list)"
prod: "'prod' in (proxmox_tags_parsed|list)"
public: "'public' in (proxmox_tags_parsed|list)"
lab: "'lab' in (proxmox_tags_parsed|list)"
decom: "'decom' in (proxmox_tags_parsed|list)"
staff: "'staff' in (proxmox_tags_parsed|list)"
# create hostvars
compose:
ansible_port: 50022
ansible_user: "'ansible'"
ansible_ssh_private_key_file: "'~/.ssh/ansible_srv'"
ansible_become_method: "'sudo'"
# it seems the plugin cannot interpret external vars or vault so you can use -K with cli
# or simply specify extra-vars with -e "ansible_become_password="$(bw get password ansible_pass)" "
# this example get a password from a vaultwarden instance
# parse the IP address of host (split is used to strip '/CIDR' notation) thanks @asshall
ansible_host: proxmox_agent_interfaces[1]["ip-addresses"][0] | default("") | split('/') | first
# filters are a way to target specific hosts
#filters:
# only add hosts that have an ip address via agent
# - proxmox_agent_interfaces is defined
# for testing purposes
#strict: true
setup ct/vm Link to heading
setup user/ssh on your targeted vm
quick and dirty steps
useradd -m -s /bin/bash -m -G sudo ansible
passwd ansible
add your pubkey then modify your sshd_config
to fit your settings and restart sshd service
systemctl restart sshd
naturally check if ssh connectivity is ok.
exploit tha dynamic thing Link to heading
finally you can list your inventory with
ansible-inventory -i plugins/inventory/myserver.proxmox.yml --graph
|--@lab:
| |--netbox
| |--deblab4
| |--pxelab
| |--rhelab
|--@prod:
| |--pgsql
| |--gitea
| |--download
now the real game begin.
to execute a playbook against all your proxmox’s ct/vm.
example playbook to get informations about vm/ct
gather_inventory.yml
---
- hosts: all
tasks:
- name: 'Gather vm/lxc informations'
set_fact:
hostname: "{{ ansible_hostname }}"
os_version: "{{ ansible_distribution }} {{ ansible_distribution_version }}"
kernel: "{{ ansible_kernel }}"
cpu: "{{ ansible_processor_count }} cores"
ram: "{{ ansible_memtotal_mb }} MB"
interface_name: "{{ ansible_default_ipv4.interface }}"
mac: "{{ ansible_default_ipv4.macaddress }}"
ip: "{{ ansible_default_ipv4.address }}"
- name: 'Append informations to file on controller'
lineinfile:
dest: "{{ ansible_host }}.inventory.txt"
line: " hostname : {{ hostname }} os: {{ os_version }} kernel : {{ kernel }} cpu : {{ cpu }} ram : {{ ram }} interface : {{ interface_name }} mac : {{ mac }} ip : {{ ip }} "
create: true
insertbefore: EOF
delegate_to: localhost
...
ansible-playbook -i plugins/inventory/tifa.proxmox.yml playbooks/gather_inventory.yml -Kk
-K
is for asking ansible_become_password
you can use extra vars to automate the process
in this example i fetch ansible_become_password
from a vaultwarden instance i already setup/unlocked on my ansible controller
ansible-playbook -i plugins/inventory/tifa.proxmox.yml playbooks/deploy_stuff_with_sudo.yml -e "ansible_become_password="$(bw get password ansible_pass)" "
to limit :
- specific group i use
-l prod
- specific group and exclude another
-l 'proxmox_all_running,!lab'
so anynone with no ansible skills can tag a vm/ct via webui can automate some process when further ansible roles are deployed
some tag like upgrade
destroy
etc …
enjoy
troubleshooting : Link to heading
some vm/ct can have this error :
fatal: [deblab2]: UNREACHABLE! => {
"changed": false,
"msg": "Failed to connect to the host via ssh: ssh: Could not resolve hostname deblab2: Name or service not known",
"unreachable": true
}
could be due to this
sudo: unable to resolve host deblab4: Name or service not known
double check your /etc/hostname
and /etc/hosts
inside vm/ct
ressources : Link to heading
- proxmox users api token :
https://pve.proxmox.com/pve-docs/pve-admin-guide.html#pveum_tokens
https://pve.proxmox.com/pve-docs/chapter-pveum.html#pveum_tokens
https://pve.proxmox.com/wiki/User_Management#pveum_tokens
- ansible stuff :
https://docs.ansible.com/ansible/latest/vault_guide/vault_encrypting_content.html
https://docs.ansible.com/ansible/latest/collections/community/general/proxmox_user_info_module.html
https://docs.ansible.com/ansible/latest/collections/community/general/proxmox_inventory.html
- connect to vm/lxc via tty
- proxmox.yml name problem
https://stackoverflow.com/questions/74431714/ansible-build-dynamic-inventory-with-proxmox
- awx proxmox