Draft - Auto-enrolment api docs
Overview
This document provides comprehensive API documentation for PatchMon's Proxmox integration, focusing on how to leverage the auto-enrollment API endpoints for automated device management using tools like Ansible.
The PatchMon Proxmox integration provides a secure, token-based API for automatically enrolling LXC containers from Proxmox hosts into PatchMon for centralized patch management.
Table of Contents
- API Architecture
- Authentication
- Admin Endpoints
- Enrollment Endpoints
- Host Management Endpoints
- Ansible Integration Examples
- Error Handling
- Rate Limiting
- Security Considerations
- API Reference
API Architecture
Base URL Structure
https://your-patchmon-server.com/api/v1/
Note: The API version is configurable via the API_VERSION
environment variable (defaults to v1
).
Endpoint Categories
- Admin Endpoints (
/auto-enrollment/tokens/*
) - Token management - Enrollment Endpoints (
/auto-enrollment/*
) - Host enrollment - Host Endpoints (
/hosts/*
) - Host management and agent installation
Two-Tier Security Model
Tier 1: Auto-Enrollment Token
- Purpose: Create new host entries
- Scope: Limited to enrollment operations
- Authentication: Token key + secret
- Rate Limited: Yes (hosts per day)
Tier 2: Host API Credentials
- Purpose: Agent communication and data reporting
- Scope: Per-host unique credentials
- Authentication: API ID + key
- Rate Limited: No (per-host)
Authentication
Admin Endpoints Authentication
Admin endpoints require JWT authentication:
curl -H "Authorization: Bearer <jwt_token>" \
-H "Content-Type: application/json" \
https://your-patchmon-server.com/api/v1/auto-enrollment/tokens
Enrollment Endpoints Authentication
Enrollment endpoints use token-based authentication:
curl -H "X-Auto-Enrollment-Key: patchmon_ae_abc123..." \
-H "X-Auto-Enrollment-Secret: def456ghi789..." \
-H "Content-Type: application/json" \
https://your-patchmon-server.com/api/v1/auto-enrollment/enroll
Host Endpoints Authentication
Host endpoints use API credentials:
curl -H "X-API-ID: patchmon_abc123" \
-H "X-API-KEY: def456ghi789" \
https://your-patchmon-server.com/api/v1/hosts/install
Admin Endpoints
Create Auto-Enrollment Token
Endpoint: POST /api/v1/auto-enrollment/tokens
Headers:
Authorization: Bearer <jwt_token>
Content-Type: application/json
Request Body:
{
"token_name": "Proxmox Production",
"max_hosts_per_day": 100,
"default_host_group_id": "uuid-of-host-group",
"allowed_ip_ranges": ["192.168.1.10", "10.0.0.0/24"],
"expires_at": "2026-12-31T23:59:59Z",
"metadata": {
"integration_type": "proxmox-lxc",
"environment": "production",
"description": "Token for production Proxmox cluster"
}
}
Response: 201 Created
{
"message": "Auto-enrollment token created successfully",
"token": {
"id": "uuid",
"token_name": "Proxmox Production",
"token_key": "patchmon_ae_abc123...",
"token_secret": "def456ghi789...",
"max_hosts_per_day": 100,
"default_host_group": {
"id": "uuid",
"name": "Proxmox LXC",
"color": "#3B82F6"
},
"created_by": {
"id": "uuid",
"username": "admin",
"first_name": "John",
"last_name": "Doe"
},
"expires_at": "2026-12-31T23:59:59Z"
},
"warning": "⚠️ Save the token_secret now - it cannot be retrieved later!"
}
List Auto-Enrollment Tokens
Endpoint: GET /api/v1/auto-enrollment/tokens
Response: 200 OK
[
{
"id": "uuid",
"token_name": "Proxmox Production",
"token_key": "patchmon_ae_abc123...",
"is_active": true,
"allowed_ip_ranges": ["192.168.1.10"],
"max_hosts_per_day": 100,
"hosts_created_today": 15,
"last_used_at": "2025-10-11T14:30:00Z",
"expires_at": "2026-12-31T23:59:59Z",
"created_at": "2025-10-01T10:00:00Z",
"default_host_group_id": "uuid",
"metadata": {"integration_type": "proxmox-lxc"},
"host_groups": {
"id": "uuid",
"name": "Proxmox LXC",
"color": "#3B82F6"
},
"users": {
"id": "uuid",
"username": "admin",
"first_name": "John",
"last_name": "Doe"
}
}
]
Get Token Details
Endpoint: GET /api/v1/auto-enrollment/tokens/{tokenId}
Response: 200 OK
(same structure as single token in list)
Update Token
Endpoint: PATCH /api/v1/auto-enrollment/tokens/{tokenId}
Request Body:
{
"is_active": false,
"max_hosts_per_day": 200,
"allowed_ip_ranges": ["192.168.1.0/24"],
"expires_at": "2027-01-01T00:00:00Z"
}
Delete Token
Endpoint: DELETE /api/v1/auto-enrollment/tokens/{tokenId}
Response: 200 OK
{
"message": "Auto-enrollment token deleted successfully",
"deleted_token": {
"id": "uuid",
"token_name": "Proxmox Production"
}
}
Enrollment Endpoints
Download Proxmox Enrollment Script
Endpoint: GET /api/v1/auto-enrollment/proxmox-lxc
Query Parameters:
token_key
(required): Auto-enrollment token keytoken_secret
(required): Auto-enrollment token secretforce
(optional):true
to enable force install mode
Example:
curl "https://patchmon.example.com/api/v1/auto-enrollment/proxmox-lxc?token_key=KEY&token_secret=SECRET&force=true"
Response: 200 OK
(bash script with credentials injected)
Enroll Single Host
Endpoint: POST /api/v1/auto-enrollment/enroll
Headers:
X-Auto-Enrollment-Key: patchmon_ae_abc123...
X-Auto-Enrollment-Secret: def456ghi789...
Content-Type: application/json
Request Body:
{
"friendly_name": "webserver",
"machine_id": "proxmox-lxc-100-abc123",
"metadata": {
"vmid": "100",
"proxmox_node": "proxmox01",
"ip_address": "10.0.0.10",
"os_info": "Ubuntu 22.04 LTS",
"container_type": "lxc"
}
}
Response: 201 Created
{
"message": "Host enrolled successfully",
"host": {
"id": "uuid",
"friendly_name": "webserver",
"api_id": "patchmon_abc123",
"api_key": "def456ghi789",
"host_group": {
"id": "uuid",
"name": "Proxmox LXC",
"color": "#3B82F6"
},
"status": "pending"
}
}
Error Responses:
400 Bad Request
- Validation errors:
{
"errors": [
{
"msg": "Friendly name is required",
"param": "friendly_name",
"location": "body"
}
]
}
{
"error": "Auto-enrollment credentials required"
}
403 Forbidden
- IP not authorized:
{
"error": "IP address not authorized for this token"
}
409 Conflict
- Host already exists:
{
"error": "Host already exists",
"host_id": "uuid",
"api_id": "patchmon_abc123",
"machine_id": "proxmox-lxc-100-abc123",
"friendly_name": "webserver",
"message": "This machine is already enrolled in PatchMon (matched by machine ID)"
}
429 Too Many Requests
- Rate limit exceeded:
{
"error": "Rate limit exceeded",
"message": "Maximum 100 hosts per day allowed for this token"
}
Bulk Enroll Hosts
Endpoint: POST /api/v1/auto-enrollment/enroll/bulk
Headers:
X-Auto-Enrollment-Key: patchmon_ae_abc123...
X-Auto-Enrollment-Secret: def456ghi789...
Content-Type: application/json
Request Body:
{
"hosts": [
{
"friendly_name": "webserver",
"machine_id": "proxmox-lxc-100-abc123",
"metadata": {
"vmid": "100",
"proxmox_node": "proxmox01"
}
},
{
"friendly_name": "database",
"machine_id": "proxmox-lxc-101-def456",
"metadata": {
"vmid": "101",
"proxmox_node": "proxmox01"
}
}
]
}
Limits:
- Minimum: 1 host
- Maximum: 50 hosts per request
Response: 201 Created
{
"message": "Bulk enrollment completed: 2 succeeded, 0 failed, 0 skipped",
"results": {
"success": [
{
"id": "uuid",
"friendly_name": "webserver",
"api_id": "patchmon_abc123",
"api_key": "def456"
},
{
"id": "uuid",
"friendly_name": "database",
"api_id": "patchmon_ghi789",
"api_key": "jkl012"
}
],
"failed": [],
"skipped": []
}
}
Host Management Endpoints
Download Agent Installation Script
Endpoint: GET /api/v1/hosts/install
Headers:
X-API-ID: patchmon_abc123
X-API-KEY: def456ghi789
Query Parameters:
force
(optional):true
to enable force install mode
Response: 200 OK
(bash script with credentials injected)
Download Agent Script
Endpoint: GET /api/v1/hosts/agent/download
Headers:
X-API-ID: patchmon_abc123
X-API-KEY: def456ghi789
Response: 200 OK
(agent script with credentials injected)
Host Data Update
Endpoint: POST /api/v1/hosts/update
Headers:
X-API-ID: patchmon_abc123
X-API-KEY: def456ghi789
Content-Type: application/json
Request Body:
{
"packages": [
{
"name": "nginx",
"currentVersion": "1.18.0",
"availableVersion": "1.20.0",
"needsUpdate": true,
"isSecurityUpdate": false
}
],
"agentVersion": "1.2.3",
"cpuModel": "Intel Xeon E5-2680 v4",
"cpuCores": 8,
"ramInstalled": 16.0,
"swapSize": 2.0,
"diskDetails": [
{
"device": "/dev/sda1",
"mountPoint": "/",
"size": "50GB",
"used": "25GB",
"available": "25GB"
}
],
"gatewayIp": "192.168.1.1",
"dnsServers": ["8.8.8.8", "8.8.4.4"],
"networkInterfaces": [
{
"name": "eth0",
"ip": "192.168.1.10",
"mac": "00:11:22:33:44:55"
}
],
"kernelVersion": "5.4.0-74-generic",
"selinuxStatus": "disabled"
}
Ansible Integration Examples
Basic Ansible Playbook for Proxmox Enrollment
---
- name: Enroll Proxmox LXC containers in PatchMon
hosts: proxmox_hosts
become: yes
vars:
patchmon_url: "https://patchmon.example.com"
token_key: "{{ vault_patchmon_token_key }}"
token_secret: "{{ vault_patchmon_token_secret }}"
host_prefix: "prod-"
tasks:
- name: Install dependencies
apt:
name:
- curl
- jq
state: present
- name: Download enrollment script
get_url:
url: "{{ patchmon_url }}/api/v1/auto-enrollment/proxmox-lxc?token_key={{ token_key }}&token_secret={{ token_secret }}"
dest: /root/proxmox_auto_enroll.sh
mode: '0700'
- name: Run enrollment
command: /root/proxmox_auto_enroll.sh
environment:
HOST_PREFIX: "{{ host_prefix }}"
DEBUG: "true"
register: enrollment_output
- name: Show enrollment results
debug:
var: enrollment_output.stdout_lines
Advanced Ansible Playbook with Token Management
---
- name: Manage PatchMon Proxmox Integration
hosts: localhost
vars:
patchmon_url: "https://patchmon.example.com"
admin_token: "{{ vault_patchmon_admin_token }}"
tasks:
- name: Create Proxmox enrollment token
uri:
url: "{{ patchmon_url }}/api/v1/auto-enrollment/tokens"
method: POST
headers:
Authorization: "Bearer {{ admin_token }}"
Content-Type: "application/json"
body_format: json
body:
token_name: "{{ inventory_hostname }}-proxmox"
max_hosts_per_day: 200
default_host_group_id: "{{ proxmox_host_group_id }}"
allowed_ip_ranges: ["{{ proxmox_host_ip }}"]
expires_at: "2026-12-31T23:59:59Z"
metadata:
integration_type: "proxmox-lxc"
environment: "{{ environment }}"
created_by_ansible: true
status_code: 201
register: token_response
- name: Store token credentials
set_fact:
enrollment_token_key: "{{ token_response.json.token.token_key }}"
enrollment_token_secret: "{{ token_response.json.token.token_secret }}"
- name: Deploy enrollment script to Proxmox hosts
include_tasks: deploy_enrollment.yml
vars:
enrollment_token_key: "{{ enrollment_token_key }}"
enrollment_token_secret: "{{ enrollment_token_secret }}"
Ansible Task for Bulk Enrollment
---
- name: Bulk enroll Proxmox containers
hosts: proxmox_hosts
become: yes
vars:
patchmon_url: "https://patchmon.example.com"
token_key: "{{ vault_patchmon_token_key }}"
token_secret: "{{ vault_patchmon_token_secret }}"
tasks:
- name: Get LXC container list
shell: |
pct list | tail -n +2 | while read -r line; do
vmid=$(echo "$line" | awk '{print $1}')
name=$(echo "$line" | awk '{print $3}')
status=$(echo "$line" | awk '{print $2}')
if [ "$status" = "running" ]; then
machine_id=$(pct exec "$vmid" -- bash -c "cat /etc/machine-id 2>/dev/null || cat /var/lib/dbus/machine-id 2>/dev/null || echo 'proxmox-lxc-$vmid-'$(cat /proc/sys/kernel/random/uuid)" 2>/dev/null || echo "proxmox-lxc-$vmid-unknown")
echo "{\"friendly_name\":\"$name\",\"machine_id\":\"$machine_id\",\"metadata\":{\"vmid\":\"$vmid\",\"proxmox_node\":\"$(hostname)\"}}"
fi
done | jq -s '.'
register: containers_json
- name: Bulk enroll containers
uri:
url: "{{ patchmon_url }}/api/v1/auto-enrollment/enroll/bulk"
method: POST
headers:
X-Auto-Enrollment-Key: "{{ token_key }}"
X-Auto-Enrollment-Secret: "{{ token_secret }}"
Content-Type: "application/json"
body_format: json
body:
hosts: "{{ containers_json.stdout | from_json }}"
status_code: 201
register: enrollment_result
- name: Display enrollment results
debug:
msg: "{{ enrollment_result.json.message }}"
Ansible Role for PatchMon Integration
# roles/patchmon_proxmox/tasks/main.yml
---
- name: Install PatchMon dependencies
package:
name:
- curl
- jq
state: present
- name: Create PatchMon directory
file:
path: /opt/patchmon
state: directory
mode: '0755'
- name: Download enrollment script
get_url:
url: "{{ patchmon_url }}/api/v1/auto-enrollment/proxmox-lxc?token_key={{ token_key }}&token_secret={{ token_secret }}&force={{ force_install | default('false') }}"
dest: /opt/patchmon/proxmox_auto_enroll.sh
mode: '0700'
- name: Run enrollment script
command: /opt/patchmon/proxmox_auto_enroll.sh
environment:
PATCHMON_URL: "{{ patchmon_url }}"
AUTO_ENROLLMENT_KEY: "{{ token_key }}"
AUTO_ENROLLMENT_SECRET: "{{ token_secret }}"
HOST_PREFIX: "{{ host_prefix | default('') }}"
DRY_RUN: "{{ dry_run | default('false') }}"
DEBUG: "{{ debug | default('false') }}"
FORCE_INSTALL: "{{ force_install | default('false') }}"
register: enrollment_output
- name: Display enrollment results
debug:
var: enrollment_output.stdout_lines
when: enrollment_output.stdout_lines is defined
- name: Fail if enrollment had errors
fail:
msg: "Enrollment failed with errors"
when: enrollment_output.rc != 0
Ansible Vault Integration
# group_vars/all/vault.yml (encrypted with ansible-vault)
---
vault_patchmon_admin_token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
vault_patchmon_token_key: "patchmon_ae_abc123..."
vault_patchmon_token_secret: "def456ghi789..."
Ansible Playbook with Error Handling
---
- name: Robust Proxmox enrollment with error handling
hosts: proxmox_hosts
become: yes
vars:
patchmon_url: "https://patchmon.example.com"
token_key: "{{ vault_patchmon_token_key }}"
token_secret: "{{ vault_patchmon_token_secret }}"
max_retries: 3
retry_delay: 30
tasks:
- name: Test PatchMon connectivity
uri:
url: "{{ patchmon_url }}/api/v1/auto-enrollment/tokens"
method: GET
headers:
Authorization: "Bearer {{ vault_patchmon_admin_token }}"
status_code: 200
retries: "{{ max_retries }}"
delay: "{{ retry_delay }}"
- name: Download enrollment script
get_url:
url: "{{ patchmon_url }}/api/v1/auto-enrollment/proxmox-lxc?token_key={{ token_key }}&token_secret={{ token_secret }}"
dest: /root/proxmox_auto_enroll.sh
mode: '0700'
retries: "{{ max_retries }}"
delay: "{{ retry_delay }}"
- name: Run enrollment with retry logic
shell: |
for i in {1..{{ max_retries }}}; do
echo "Attempt $i of {{ max_retries }}"
if /root/proxmox_auto_enroll.sh; then
echo "Enrollment successful"
exit 0
else
echo "Enrollment failed, retrying in {{ retry_delay }} seconds..."
sleep {{ retry_delay }}
fi
done
echo "All enrollment attempts failed"
exit 1
register: enrollment_result
- name: Handle enrollment failure
fail:
msg: "Proxmox enrollment failed after {{ max_retries }} attempts"
when: enrollment_result.rc != 0
- name: Parse enrollment results
set_fact:
enrolled_count: "{{ enrollment_result.stdout | regex_search('Successfully Enrolled:\\s+(\\d+)', '\\1') | default('0') }}"
failed_count: "{{ enrollment_result.stdout | regex_search('Failed:\\s+(\\d+)', '\\1') | default('0') }}"
- name: Report enrollment statistics
debug:
msg: |
Enrollment completed:
- Successfully enrolled: {{ enrolled_count }} containers
- Failed: {{ failed_count }} containers
Error Handling
Common HTTP Status Codes
Code | Meaning | Description |
---|---|---|
200 | OK | Request successful |
201 | Created | Resource created successfully |
400 | Bad Request | Invalid request data |
401 | Unauthorized | Invalid authentication |
403 | Forbidden | IP not authorized |
404 | Not Found | Resource not found |
409 | Conflict | Host already exists |
429 | Too Many Requests | Rate limit exceeded |
500 | Internal Server Error | Server error |
Error Response Format
{
"error": "Error message",
"message": "Detailed description",
"code": "ERROR_CODE",
"details": {
"field": "additional context"
}
}
Validation Errors
{
"errors": [
{
"msg": "Token name is required",
"param": "token_name",
"location": "body"
}
]
}
Rate Limiting
Token Rate Limits
- Default: 100 hosts per day per token
- Maximum: 1000 hosts per day per token
- Reset: Daily at midnight UTC
- Scope: Per-token (not per-host)
Rate Limit Headers
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85
X-RateLimit-Reset: 1640995200
Rate Limit Exceeded Response
{
"error": "Rate limit exceeded",
"message": "Maximum 100 hosts per day allowed for this token",
"retry_after": 3600
}
Security Considerations
Token Security
- Secret Storage: Token secrets are hashed using bcrypt
- One-Time Display: Secrets are only shown during token creation
- Rotation: Regular token rotation recommended (90 days)
- Scope: Tokens only create hosts, cannot access existing data
IP Restrictions
{
"allowed_ip_ranges": ["192.168.1.10", "10.0.0.0/24"]
}
Network Security
- Use HTTPS in production
- Implement proper firewall rules
- Consider VPN for remote Proxmox hosts
- Monitor for unusual enrollment patterns
Audit Logging
All enrollment activities are logged with:
- Token name and ID
- Enrolled host details
- Timestamp and source IP
- Success/failure status
API Reference
Complete Endpoint List
Admin Endpoints (JWT Authentication)
POST /api/v1/auto-enrollment/tokens
- Create tokenGET /api/v1/auto-enrollment/tokens
- List tokensGET /api/v1/auto-enrollment/tokens/{tokenId}
- Get token detailsPATCH /api/v1/auto-enrollment/tokens/{tokenId}
- Update tokenDELETE /api/v1/auto-enrollment/tokens/{tokenId}
- Delete token
Enrollment Endpoints (Token Authentication)
GET /api/v1/auto-enrollment/proxmox-lxc
- Download scriptPOST /api/v1/auto-enrollment/enroll
- Enroll single hostPOST /api/v1/auto-enrollment/enroll/bulk
- Bulk enroll hosts
Host Endpoints (API Credentials)
GET /api/v1/hosts/install
- Download installation scriptGET /api/v1/hosts/agent/download
- Download agent scriptPOST /api/v1/hosts/update
- Update host data
Request/Response Examples
Create Token Request
curl -X POST \
-H "Authorization: Bearer <jwt_token>" \
-H "Content-Type: application/json" \
-d '{
"token_name": "Production Proxmox",
"max_hosts_per_day": 100,
"default_host_group_id": "uuid",
"allowed_ip_ranges": ["192.168.1.10"],
"expires_at": "2026-12-31T23:59:59Z"
}' \
https://patchmon.example.com/api/v1/auto-enrollment/tokens
Enroll Host Request
curl -X POST \
-H "X-Auto-Enrollment-Key: patchmon_ae_abc123..." \
-H "X-Auto-Enrollment-Secret: def456ghi789..." \
-H "Content-Type: application/json" \
-d '{
"friendly_name": "webserver",
"machine_id": "proxmox-lxc-100-abc123",
"metadata": {
"vmid": "100",
"proxmox_node": "proxmox01"
}
}' \
https://patchmon.example.com/api/v1/auto-enrollment/enroll
Download Installation Script
curl -H "X-API-ID: patchmon_abc123" \
-H "X-API-KEY: def456ghi789" \
https://patchmon.example.com/api/v1/hosts/install
Integration Patterns
Pattern 1: Direct Script Download
# Download and execute in one command
curl -s "https://patchmon.example.com/api/v1/auto-enrollment/proxmox-lxc?token_key=KEY&token_secret=SECRET" | bash
Pattern 2: API-First Approach
# 1. Create token via API
# 2. Use token to enroll hosts via API
# 3. Download agent scripts for each host
# 4. Install agents using host-specific credentials
Pattern 3: Hybrid Approach
# 1. Create token via API
# 2. Download enrollment script with token embedded
# 3. Run script on Proxmox hosts
# 4. Script handles both enrollment and agent installation
This API documentation provides everything needed to integrate PatchMon's Proxmox functionality with automation tools like Ansible. The endpoints are designed to be secure, scalable, and easy to integrate into existing infrastructure automation workflows.
No comments to display
No comments to display