Documentation v0.1.7

Access Control

This page describes go-pve-qemu's three guards: origin-scoped CORS, the ALLOW_IPS whitelist, and per-VM state and lock checks.

Layer 1: CORS

Every request passes the CORS middleware:

Origin Response
A private IP (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16) in the server's own /24 Access-Control-Allow-Origin echoes that origin
Any other origin No Access-Control-Allow-Origin
No Origin (curl, server-side callers) Unaffected

The server subnet comes from the first non-loopback private IPv4 interface, falling back to 192.168.0.*. Allowed methods are GET, POST, OPTIONS; OPTIONS preflights get 204 directly.

CORS only constrains browsers; it is not authentication.

Layer 2: ALLOW_IPS

Every mutating endpoint (install, start, stop, shutdown, reboot, destroy, set/*) first matches the client IP:

ALLOW_IPS Behavior
0.0.0.0 Allow all
192.168.0.10,192.168.0.20 Allow only the listed IPs
unset or empty Deny all

The client IP comes from Gin's c.ClientIP(). The service sets no trusted proxies, so Gin honors X-Forwarded-For / X-Real-IP by default, and a client talking to the API directly can spoof its IP; expose the service only inside a controlled network.

Rejections look like this:

Endpoint type Response
Sync endpoints 403 this IP is not allowed to perform this action
SSE endpoints 200 with a single data: {"message": "...this IP is not allowed to perform this action"} line

Query endpoints (health, list, status) do not check ALLOW_IPS.

Layer 3: VM State and the Disabled List

Mutating endpoints that target a VM check it against pvesh get /cluster/resources and .go_qemu_disabled:

Check Failure response
VM is on the disabled list 400 this IP is not allowed to be controlled
Requires running, VM is stopped 400 VM is not running
Requires stopped, VM is running 400 VM is running
Cluster data or disabled list unreadable 500 failed to get VM list: ...
Requires a running VM Requires a stopped VM
stop, shutdown, reboot start, destroy, set/cpu, set/memory, set/disk, set/node

SSE endpoints report check failures as a single data: line as well.

中文