Сегодня хочу разобрать, как для моей системы виртуализации в лице связки Debian 11 + Proxmox 7.4-3 создать API Token. Мне это нужно, т.к. я хочу практически познакомиться, как взаимодействовать с Proxmox через Ansible в рамках управления, развертывания и т.д. И вот в чтении различных источников я вышел на этап, где говорится что нужен будет API Token. А как его создать, что это такое и как его практически использовать, как посмотреть перед тем как уже через Ansible все разбирать, одним словом куча вопросов.

Ну а вроде как можно подключаться к Proxmox не используя логин и пароль, а через API вызовы.

API Token =

  • привязан к пользователю
  • не требует пароля
  • имеет строго заданные права
  • идеально для Ansible / Terraform / скриптов

В наличии: Debian 11 + Proxmox 7.4-3

Шаг №1: Запускаю браузер и обращаюсь к своему Proxmox:

https://172.35.35.102:8006 - user&pass (Linux PAM standard authentication)

Шаг №2: Создаю группу:

https://172.35.35.102:8006 - user&pass - (Folder View) Datacenter - Permissions - Groups - Create

  • Name: GRP_PROVISION
  • Comment: GRP_PROVISION

и нажимаю Create

Шаг №3: Создаю пользователя:

https://172.35.35.102:8006 - user&pass - (Folder View) Datacenter - Permissions - Users - Add

  • User name: us_provision
  • Realm: Proxmox VE authentication
  • First Name: us_provision
  • Last Name: us_provision
  • E-Mail: support@ekzorchik.com
  • Password: Aa1234567aA
  • Confirm password: Aa1234567aA
  • Group: GRP_PROVISION
  • Expire: never
  • Enabled: отмечаю галочкой
  • Comment: ничего не указываю
  • Key IDs: ничего не указываю
  • Advanced: отмечено галочкой

и нажимаю Add

Шаг №4: Создаю роль разрешений:

https://172.35.35.102:8006 - user&pass - (Folder View) Datacenter - Permissions - Roles

это если заморочиться, но я пока не буду.

https://172.35.35.102:8006 - user&pass - (Folder View) Datacenter - Permissions - Add — выбираю Group Permission

  • Path: выбираю "/", т.е. все права
  • Group: GRP_PROVISION
  • Role: выбираю дефолтную роль "Administrator"
  • Propagate: отмечаю галочкой

и нажимаю "Add"

Шаг №5: Создаю API Token:

https://172.35.35.102:8006 - user&pass - (Folder View) Datacenter - Permissions - API Tokens - Add

  • User: выбираю us_provision@pve
  • Token ID: к примеру наберу ansible
  • Privilege Separation: отмечаю галочкой
  • Expire: never
  • Comment: ничего не указываю

и нажимаю Add

На заметку:

В Proxmox VE токен API (API Token ID) имеет формат {username}!{tokenname}. Максимальная длина полного токена определяется ограничениями Proxmox на имя пользователя и имя токена: имя пользователя до 32 символов, восклицательный знак, и имя токена также до 32 символов.

Формат: userid!tokenname

Пример: root@pam!mytoken

после получаю окно где сгенерирован на основе указанно Token ID секретный ключ:

Как выглядит создаваемый API Token для Proxmox 7.

На заметку: Secret: Сгенерированный секрет появится автоматически.

На заметку: Скопируйте и сохраните Secret, так как он отображается только один раз.

На заметку: Потом его восстановить нельзя — только пересоздать токен.

Нажимаю "Copy Secret Value" и вот его (1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb) уже и буду в запросах использовать

после нажимаю на крестик окна "Token Secret"

Шаг №6: Как теперь API Token использовать?

Формат авторизации строго такой (т.е. должно быть два символа "=", а не один):

Authorization: PVEAPIToken=USER@REALM!TOKENID=SECRET

На заметку: Справа по обращениям (GET/POST), как через CLI, так и через http (https://pve.proxmox.com/pve-docs/api-viewer/index.html#/access)

ekzorchik@srv-us2204a:~$ curl -k -H "Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb"  https://172.35.35.102:8006/api2/json/version

-bash: !ansible=1ed9ec69: event not found

ekzorchik@srv-us2204a:~$

ошибка "-bash: !ansible=1ed9ec69: event not found" — это не ошибка запроса, это В bash символ ! — это history expansion.

ekzorchik@srv-us2204a:~$ curl -k -H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb'  https://172.35.35.102:8006/api2/json/version

{"data":{"version":"7.4-3","repoid":"9002ab8a","release":"7.4"}}

ekzorchik@srv-us2204a:~$

Ура ну наконец-таки я разобрал, а что вроде делаешь правильно, видишь пример, а в ответ ошибка, а ошибка не того что сделал правильно, а встроенного интерпретатора. Спрашивается зачем тогда приводить примеры. Вот всегда на этот и тратиться много времени пытаясь понять, как работает примеры, оторванные от практического применения.

На заметку: а можно экранировать символ "!" и строка начинающаяся с Authorization будет в двойных кавычках, получается @pve\!ansible.

если нужно вывод не в одну строку, а как JSON вывод построчно

ekzorchik@srv-us2204a:~$ sudo apt-get install -y jq

ekzorchik@srv-us2204a:~$ curl -k -H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb'  https://172.35.35.102:8006/api2/json/version | jq .

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

Dload  Upload   Total   Spent    Left  Speed

100    64  100    64    0     0   5766      0 --:--:-- --:--:-- --:--:--  6400

{

"data": {

"repoid": "9002ab8a",

"version": "7.4-3",

"release": "7.4"

}

}

ekzorchik@srv-us2204a:~$

Шаг №7: Т.к. у меня нет Cluster а одна нода, то узнаем имя ноды:

ekzorchik@srv-us2204a:~$ curl -k   -H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb'   https://172.35.35.102:8006/api2/json/nodes | jq .

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

Dload  Upload   Total   Spent    Left  Speed

100   218  100   218    0     0  17969      0 --:--:-- --:--:-- --:--:-- 18166

{

"data": [

{

"level": "",

"ssl_fingerprint": "D2:21:B4:E7:A3:37:49:AD:CA:50:5B:02:BD:01:2C:9A:D1:9F:74:D8:A4:1F:E5:DB:14:C0:44:64:EF:88:6C:3D",

"id": "node/srv-proxmox2",

"node": "srv-proxmox2",

"status": "online",

"type": "node"

}

]

}

На заметку: Вот это имя (node) и есть правильное.

Шаг №8: Получить список всех VM на хосте:

ekzorchik@srv-us2204a:~$ curl -k \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu \

| jq .

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

Dload  Upload   Total   Spent    Left  Speed

100    11  100    11    0     0    291      0 --:--:-- --:--:-- --:--:--   297

{

"data": []

}

ekzorchik@srv-us2204a:~$

начал читать по чему так, при вышел на упоминание, что API Token не получает права через группу, даже если:

Пользователь входит в группу

у группы роль Administrator

На заметку: Для API Token права нужно назначать явно и это логика Proxmox и вот с ней и происходит недопонимание. Т.е. сейчас схема, которую я сделал выше:

Group: GRP_PROVISION

└─ Role: Administrator (PVEAdmin)

└─ User: us_provision@pve

└─ API Token: ansible

и API Token не наследует роль группы.

Решением может служить, назначение роль на токен:

https://172.35.35.102:8006 - user&pass - (Folder View) Datacenter - Permissions - Add - API Token Permission

  • Path: /
  • API Token: выбираю us_provision@pve!ansible
  • Role: выбираю Administrator
  • Propagate: отмечаю галочкой

и нажимаю Add

После чего запрос получения списка всех VM на ноде возвращает их:

ekzorchik@srv-us2204a:~$ curl -k -H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb'   https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu | jq  '.data[] | {vmid,name,status}'

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

Dload  Upload   Total   Spent    Left  Speed

100  4369  100  4369    0     0   157k      0 --:--:-- --:--:-- --:--:--  164k

{

"vmid": 102,

"name": "srv-backup",

"status": "stopped"

}

{

"vmid": 115,

"name": "srv-mail-ekzorchik-com",

"status": "running"

}

{

"vmid": 116,

"name": "srv-mail-ekzorchik-ru",

"status": "running"

}

Шаг №9: Узнаем именование сети в своем Proxmox:

pvesh get /nodes/srv-proxmox2/network

curl -k \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/network | jq .

Шаг №10: Узнаем именование storage в своем Proxmox:

pvesh get /storage

curl -k \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

https://172.35.35.102:8006/api2/json/storage | jq .

Шаг №11: Проверяем, что VMID если занят:

ekzorchik@srv-us2204a:~$ curl -k -H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu | jq '.data[].vmid' | head -n 10

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current

Dload  Upload   Total   Spent    Left  Speed

100  4369  100  4369    0     0   205k      0 --:--:-- --:--:-- --:--:--  213k

204

205

206

101

103

116

115

100

107

102

ekzorchik@srv-us2204a:~$

Шаг №12: А можно ли создать контейнер VM:

На заметку: scsi0 должен быть типа storage:volume,size

curl -k -X POST \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

-d "vmid=600" \

-d "name=vm-ekz" \

-d "memory=2048" \

-d "cores=2" \

-d "net0=virtio,bridge=vmbr0" \

-d "scsi0=m2st:10" \

-d "ostype=l26" \

https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu

{"data":null,"errors":{"net0":"invalid format - duplicate key in comma-separated list property: model\n"}}ekzorchik@srv-us2204a:~$

Это писец какой-то не могу понять, чтобы запросом создать просто контейнер VM, читаю доку и не понимаю, как это задействовать. Блин.

curl -k -X POST \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

-d "vmid=600" \

-d "name=vm-ekz" \

-d "memory=2048" \

-d "cores=2" \

-d "ostype=l26" \

https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu

в ответ получил:

{"data":"UPID:srv-proxmox2:0029D3D8:0D50B306:69788A96:qmcreate:600:us_provision@pve!ansible:"}root@srv-proxmox2:~#

смотрю создался контейнер без диска и сети, ну хотя бы запрос верен, значит нужно разобраться с синтаксисом для диска и сетевого интерфейса.

root@srv-proxmox2:~# cat /etc/pve/nodes/srv-proxmox2/qemu-server/107.conf — изучаю уже существующие параметры созданных виртуальных машин.

На заметку: у меня диск m2st — это LVM Thin, параметр format=raw нельзя. Proxmox считает, что ты передаешь параметр file=, а format в таком случае конфликтует — поэтому идет ошибка "invalid format - duplicate key in comma-separated list property: file". Т.е. Proxmox думает, что ты создаешь диск как файл, а не как LVM. Для LVM Thin дисков format не нужен, потому что LVM всегда RAW.

curl -k -X POST \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

-d "vmid=600" \

-d "name=vm-ekz" \

-d "memory=2048" \

-d "cores=2" \

-d "scsihw=virtio-scsi-single"\

-d "scsi0=m2st:10" \

-d "ostype=l26" \

https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu

и контейнер создался:

Получилось создать контейнер VM в Proxmox 7 через curl посредством API Token.

Чтобы была еще сеть нужно оказалось указать MAC адрес (произвольный), синтаксис без MAC адреса, строка "net0=virtio0,bridge=vmbr0,firewall=1" — не работает, выдает ошибку, а вот ниже работает.

curl -k -X POST \

-H 'Authorization: PVEAPIToken=us_provision@pve!ansible=1ed9ec69-9f7e-4b6c-9455-e1d90a2036eb' \

-d "vmid=600" \

-d "name=vm-ekz" \

-d "memory=2048" \

-d "cores=2" \

-d "scsihw=virtio-scsi-single" \

-d "scsi0=m2st:10" \

-d "net0=virtio=BA:D4:45:09:87:6C,bridge=vmbr0,firewall=1" \

-d "ostype=l26" \

https://172.35.35.102:8006/api2/json/nodes/srv-proxmox2/qemu

{"data":"UPID:srv-proxmox2:0029F3BB:0D54A995:697894BB:qmcreate:600:us_provision@pve!ansible:"}root@srv-proxmox2:~#

Вот что, значит оформляя себе заметку и расписывая ее в шагах получаем что и как работает, выясняя что не так и почему-то что правильно указано не работает.

Пусть пока заметку завершу, главное, что я приобщился к теме как через API Token взаимодействовать, а вот уже все остальное, как создание VM, изменение, настройка — это дело наживное.

На этом все, встретимся чуть позже, с уважением автор блога Олло Александр aka ekzorchik.