Skip to content

Commit

Permalink
feat: support API tokens along with password based auth (#26)
Browse files Browse the repository at this point in the history
Co-authored-by: Nicolai Buchwitz <[email protected]>
  • Loading branch information
nbuchwitz and Nicolai Buchwitz authored Sep 10, 2021
1 parent ff25c96 commit e43002d
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 11 deletions.
40 changes: 34 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,37 @@ Create a user named ``monitoring`` and set password:

```
pveum useradd monitoring@pve --comment "The ICINGA 2 monitoring user"
```

#### Use token based authorization (recommended)

Create an API token named `monitoring` for the user `monitoring`:

```
pveum user token add monitoing@pve monitoring
```

Please save the token secret as there isn't any way to fetch it at a later point.

Assign role `monitoring` to token `monitoring`:

```
pveum acl modify / --roles Monitoring --tokens 'monitoring@pve!monitoring'
```


#### Use password based authorization

Set password for the user `monitoring`:

```
pveum passwd monitoring@pve
```

Assign ``monitoring`` role to user ``monitoring``

```
pveum aclmod / -user monitoring@pve -role Monitoring
pveum acl modify / --users monitoring@pve --roles Monitoring
```

For further information about the Proxmox VE privilege system have a look into the [documentation](https://pve.proxmox.com/pve-docs/pve-admin-guide.html#_strong_pveum_strong_proxmox_ve_user_manager).
Expand All @@ -56,8 +80,9 @@ For further information about the Proxmox VE privilege system have a look into t
The ``icinga2`` folder contains the command definition and service examples for use with Icinga2.

```
usage: check_pve.py [-h] -e API_ENDPOINT [--api-port API_PORT] -u API_USER -p API_PASSWORD [-k] -m {cluster,version,cpu,memory,storage,io_wait,updates,services,subscription,vm,vm_status,replication,disk-health,ceph-health,zfs-health,zfs-fragmentation}
[-n NODE] [--name NAME] [--vmid VMID] [--expected-vm-status {running,stopped,paused}] [--ignore-vm-status] [--ignore-service NAME] [--ignore-disk NAME] [-w THRESHOLD_WARNING] [-c THRESHOLD_CRITICAL] [-M] [-V MIN_VERSION]
usage: check_pve.py [-h] -e API_ENDPOINT [--api-port API_PORT] -u API_USER (-p API_PASSWORD | -t API_TOKEN) [-k] -m
{cluster,version,cpu,memory,storage,io_wait,updates,services,subscription,vm,vm_status,replication,disk-health,ceph-health,zfs-health,zfs-fragmentation} [-n NODE] [--name NAME] [--vmid VMID]
[--expected-vm-status {running,stopped,paused}] [--ignore-vm-status] [--ignore-service NAME] [--ignore-disk NAME] [-w THRESHOLD_WARNING] [-c THRESHOLD_CRITICAL] [-M] [-V MIN_VERSION]
Check command for PVE hosts via API
Expand All @@ -71,7 +96,9 @@ API Options:
-u API_USER, --username API_USER
PVE api user (e.g. icinga2@pve or icinga2@pam, depending on which backend you have chosen in proxmox)
-p API_PASSWORD, --password API_PASSWORD
PVE api user password
PVE API user password
-t API_TOKEN, --api-token API_TOKEN
PVE API token (format: TOKEN_ID=TOKEN_SECRET
-k, --insecure Don't verify HTTPS certificate
Check Options:
Expand All @@ -96,11 +123,12 @@ Check Options:
```

## Examples
## Check examples


**Check cluster health**
```
./check_pve.py -u <API_USER> -p <API_PASSWORD> -e <API_ENDPOINT> -m cluster
./check_pve.py -u <API_USER> -t <API_TOKEN> -e <API_ENDPOINT> -m cluster
OK - Cluster 'proxmox1' is healthy'
```

Expand Down
21 changes: 16 additions & 5 deletions check_pve.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,9 @@ def request(self, url, method='get', **kwargs):
response = requests.get(
url,
verify=not self.options.api_insecure,
cookies=self.ticket,
params=kwargs.get('params', None)
cookies=self.__cookies,
headers=self.__headers,
params=kwargs.get('params', None),
)
else:
self.output(CheckState.CRITICAL, "Unsupport request method: {}".format(method))
Expand Down Expand Up @@ -117,7 +118,7 @@ def get_ticket(self):
data = {"username": self.options.api_user, "password": self.options.api_password}
result = self.request(url, "post", data=data)

self.ticket = {'PVEAuthCookie': result['ticket']}
return result['ticket']

def check_api_value(self, url, message, **kwargs):
result = self.request(url)
Expand Down Expand Up @@ -620,7 +621,11 @@ def parse_args(self):
api_opts.add_argument("-u", "--username", dest='api_user', required=True,
help="PVE api user (e.g. icinga2@pve or icinga2@pam, depending on which backend you "
"have chosen in proxmox)")
api_opts.add_argument("-p", "--password", dest='api_password', required=True, help="PVE api user password")

group = api_opts.add_mutually_exclusive_group(required=True)
group.add_argument("-p", "--password", dest='api_password', help="PVE API user password")
group.add_argument("-t", "--api-token", dest="api_token", help="PVE API token (format: TOKEN_ID=TOKEN_SECRET")

api_opts.add_argument("-k", "--insecure", dest='api_insecure', action='store_true', default=False,
help="Don't verify HTTPS certificate")

Expand Down Expand Up @@ -701,9 +706,15 @@ def __init__(self):
self.check_result = CheckState.UNKNOWN
self.check_message = ""

self.__headers = {}
self.__cookies = {}

self.parse_args()
self.get_ticket()

if self.options.api_password is not None:
self.__cookies['PVEAuthCookie'] = self.get_ticket()
elif self.options.api_token is not None:
self.__headers["Authorization"] = "PVEAPIToken={}!{}".format(self.options.api_user, self.options.api_token)

pve = CheckPVE()
pve.check()

0 comments on commit e43002d

Please sign in to comment.