docs: Self review of doc pages

This commit is contained in:
2026-08-10 16:32:23 +01:00
parent bd7b3256fc
commit 83c38db92e
34 changed files with 860 additions and 991 deletions
+7 -7
View File
@@ -20,15 +20,15 @@ Directory `0700`, file `0600`. The install script sets both.
```yaml
server_url: "vantage.yourdomain.com:9090"
server_id: "<uuid>"
pre_reg_token: "<token>" # removed after the first successful Register()
agent_token: "" # written by the agent after Register()
pre_reg_token: "<token>" # cleared once the agent has registered
agent_token: "" # written by the agent when it registers
poll_interval: 30s
tls: true
```
| Field | Meaning |
| --------------- | --------------------------------------------------------------------- |
| `server_url` | `host:port` of the gRPC endpoint. Comes from the server's `GRPC_HOST` |
| `server_url` | The `host:port` the agent connects to. Comes from your `GRPC_HOST` |
| `server_id` | The identity issued when the enrolment was created |
| `pre_reg_token` | Single-use, one hour. Cleared once registration succeeds |
| `agent_token` | The permanent credential, written by the agent itself |
@@ -36,8 +36,8 @@ tls: true
| `tls` | Whether to use TLS. Leave `true` |
:::danger This file is the credential
`agent_token` is plaintext here and nowhere else the control plane holds only
its SHA-256. Anyone who can read this file can act as this agent.
`agent_token` exists in full only in this file. Anyone who can read it can act
as this agent.
:::
## Service management
@@ -77,5 +77,5 @@ rm -rf /etc/vantage
systemctl daemon-reload
```
Keys already written to `authorized_keys` remain on disk the agent is no
longer running to remove them. Revoke first if that matters.
Keys already written to `authorized_keys` remain on disk, because the agent is
no longer running to remove them. Revoke first if that matters.
+8 -6
View File
@@ -13,16 +13,18 @@ it is absent.
| -------------------------- | --------------- | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GRPC_HOST` | **yes** | | The `host:port` agents dial. Boot fails without it. There is deliberately no fallback to the web host: that would hand every agent a port that does not speak gRPC |
| `MONGO_URI` | no | `mongodb://localhost:27017` | The database name is taken from the URI path, falling back to `vantage`. There is no separate `MONGO_DB` |
| `REDIS_ADDR` | no | `localhost:6379` | Sessions, and the bus that routes agent commands between server replicas. Every replica must point at the **same** Redis |
| `REDIS_ADDR` | no | `localhost:6379` | Where sessions are held. If you run more than one copy of Vantage, they must all point at the same Redis |
| `REDIS_USERNAME` | no | | Redis 6+ ACL user. Leave empty against a legacy `requirepass` instance, which authenticates with the password alone |
| `REDIS_PASSWORD` | no | | Leave empty for an unauthenticated Redis. Both of these exist so an install can use a managed Redis rather than the bundled one |
| `KEY_ENCRYPTION_KEY` | yes in practice | | 64 hex characters (32 bytes) for AES-256-GCM. Required for private keys, vault secrets, OIDC client secrets and console credentials |
| `GITEA_HOST` | yes | `gitea.example.com` | Used to build the install scripts and agent download URLs. The default is a placeholder that will not resolve |
| `GITEA_HOST` | yes in practice | `gitea.example.com` | Host serving agent releases; used to build the install scripts and download URLs. The default is a placeholder that will not resolve, so set it to `gitea.hostxtra.co.uk` |
| `GUACD_ADDR` | no | `guacd:4822` | The [browser console](../vantage/browser-console.md) daemon |
| `PROXY_ADVERTISE_HOST` | no | `server` | The hostname **guacd** uses to reach the control plane's console relay. Wrong here and every console session fails at connect with guacd unable to resolve the relay |
| `PROXY_LISTEN_HOST` | no | `0.0.0.0` | Interface the ephemeral relay listeners bind. Narrow it only if guacd shares a known interface |
| `POD_IP` | no | | Kubernetes only, set by the Helm chart from the downward API. Overrides `PROXY_ADVERTISE_HOST`, because a console relay belongs to one replica and a Service address names all of them |
| `APP_ROOT_LABEL` | no | `vantage` | The app root label for the host and session organisation guard |
| `APP_ROOT_LABEL` | no | `vantage` | The label Vantage expects in its own hostname, used to match a browser session to the right instance |
| `VANTAGE_LICENSE` | no | | A licence supplied at startup, so an automated install does not have to paste one in |
| `VANTAGE_TRIVY_DB_REF` | no | `ghcr.io/aquasecurity/trivy-db:2` | Where the vulnerability database is pulled from. Point it at a mirror for an air-gapped install |
| `VANTAGE_VULNDB_DISABLED` | no | | `true` switches [vulnerability scanning](../vantage/vulnerabilities.md) off entirely. Findings already stored are still served, and still shown as stale |
:::danger `KEY_ENCRYPTION_KEY` has no recovery path
It encrypts SSH private keys, vault secrets, OIDC client secrets and console
@@ -38,8 +40,8 @@ protecting anything.
### Not configurable
The HTTP port (`8080`) and the gRPC port (`9090`) are fixed in the server. The
`HTTP_PORT` and `GRPC_PORT` entries in the shipped Compose file are inert —
remap with Docker's port publishing instead.
`HTTP_PORT` and `GRPC_PORT` entries in the shipped Compose file have no effect.
Remap the ports with Docker instead.
## Agent
+18 -16
View File
@@ -9,9 +9,9 @@ sidebar_label: Ports and networking
| Port | Service | Who connects | Expose publicly |
| ------- | ----------- | -------------------------------- | --------------- |
| `3000` | web | Browsers, via your reverse proxy | Yes, behind TLS |
| `8080` | server REST | The web app | No |
| `8080` | server API | The web app | No, firewall it |
| `9090` | server gRPC | Agents | **Yes** |
| `4822` | guacd | The server | No |
| `4822` | guacd | The server | No, firewall it |
| `27017` | MongoDB | The server | No |
| `6379` | Redis | The server | No |
@@ -35,11 +35,10 @@ NAT is not an obstacle. The only requirement is that the machine can reach
`GRPC_HOST`.
**The console rides the agent's connection too.** guacd never dials the target
directly; the server pushes a command down the agent's existing outbound gRPC
stream on `9090`, and the agent relays the protocol traffic from its own
loopback. No route from the control plane to the target's address is needed,
and no new inbound port opens on the target — the same connection that carries
key sync carries console traffic. This is what makes the console work for a
directly. Vantage sends the request down the connection the agent already holds
on port `9090`, and the agent connects to the service locally on that machine. No route from the control plane to the target's address is needed,
and no new inbound port opens on the target. The same connection that keeps keys
in sync carries console traffic, which is what makes the console work for a
machine behind NAT on a private subnet, as long as its agent is online.
## What to open
@@ -55,8 +54,8 @@ machine behind NAT on a private subnet, as long as its agent is online.
- Anything a server-run [monitor](../vantage/monitors.md) checks.
- SMTP, if you use an SMTP notification channel.
No route to the machines you intend to console is needed — that traffic rides
the agent's existing outbound `9090` connection instead.
No route to the machines you intend to console is needed. That traffic uses the
connection the agent already holds.
### Outbound from a managed machine
@@ -68,14 +67,17 @@ the agent's existing outbound `9090` connection instead.
Terminate TLS for the web UI at your reverse proxy.
gRPC on `9090` is reached directly by agents with `tls: true`, so that port needs
a valid certificate for the name in `GRPC_HOST`. If you proxy it, the proxy must
speak HTTP/2 end to end many do not by default, and the symptom is agents that
register and then fail to hold the command stream.
Vantage does not terminate TLS itself, so port `9090` needs the same treatment:
put it behind your proxy with a certificate valid for the name in `GRPC_HOST`.
The proxy has to pass HTTP/2 through to Vantage. Many do not do that by default,
and the symptom is agents that register once and then stop responding.
On a private network you can skip TLS instead, by setting `tls: false` in each
[agent's config](./agent-config.md).
## Reverse proxy notes
- Point the proxy at `web:3000`. The web app reaches the REST API internally, so
- Point the proxy at `web:3000`. The web app reaches the API internally, so
`8080` does not need publishing.
- The console uses a **WebSocket** at `/api/console/tunnel`. A proxy that does
not forward upgrade headers breaks the console and nothing else.
@@ -85,8 +87,8 @@ register and then fail to hold the command stream.
## Air-gapped and restricted networks
The control plane needs outbound access to fetch agent releases. Managed
machines need it too, unless you distribute the agent binary yourself and write
the config by hand the install script's only job is to do those two things.
machines need it too, unless you distribute the agent yourself and write its
config by hand, which is all the install script does.
Licence verification is entirely local, so a licensed install works with no
outbound access to HQ at all.
+42 -137
View File
@@ -1,154 +1,59 @@
---
id: rest-api
title: REST API
sidebar_label: REST API
title: Automating Vantage
sidebar_label: Automating Vantage
---
The control plane's HTTP API, on port `8080`. The web UI is a client of it and
has no privileges it does not.
Everything the web UI does, it does through Vantage's own API, so anything you
can do on screen you can also do from a script.
## Authentication
The routes mirror the product: `/api/servers`, `/api/keys`, `/api/workflows`,
`/api/monitors`, `/api/secrets`, `/api/audit`, and so on.
Most endpoints take a session: an opaque 32-byte token in the `km_session`
cookie, with the body in Redis for 24 hours.
## Where it is
One endpoint takes a bearer token instead the External Secrets Operator read
path.
On a self-hosted install the API is served on port `8080`, behind the same
reverse proxy as the web UI, under `/api` and `/auth`. On a cloud instance it is
your instance hostname.
## Unauthenticated
## Signing in
```
GET /install /install.ps1 # dynamic agent install scripts
GET /update /update.ps1
GET /auth/bootstrap-status
POST /auth/bootstrap /auth/login /auth/logout
GET /auth/me
GET /auth/providers # {local_enabled, providers:[{id,name,preset}]} — no issuer, client ID or secret
GET /auth/oidc/:providerId/start · /auth/oidc/:providerId/callback
GET /api/secrets/:group/values # bearer token (ESO)
Most calls use a session, exactly as the browser does:
```bash
curl -c cookies.txt -X POST https://vantage.example.com/auth/login \
-H 'Content-Type: application/json' \
-d '{"email":"you@example.com","password":"..."}'
curl -b cookies.txt https://vantage.example.com/api/servers
```
`/install` and `/install.ps1` take `server_id` and `token` as query parameters
and return a shell script with the newest agent version substituted in.
Sessions last 24 hours. Your role applies exactly as it does in the UI: a
`member` calling an owner-only route is refused.
`POST /auth/bootstrap` works only while the database has no users.
## The one exception
## Session-authenticated, under `/api`
Kubernetes reads secret groups with a token instead of a session, so that it
does not need an account. See
[Secrets](../vantage/secrets.md#kubernetes-external-secrets-operator).
### Servers
## Things worth knowing
```
GET,POST /servers
GET,POST /servers/new
GET,DELETE /servers/:id
POST /servers/:id/generate-key
POST /servers/:id/update-agent
POST /servers/:id/apply-updates
```
- **Reads always work. Changes need a valid licence.** Without one, the instance
is read-only and any call that changes something is refused. Deleting things,
applying OS updates and installing a licence are always allowed, so you can
always get back under your allowance or out of read-only mode.
- **Some features are licensed.** The browser console, single sign-on and
vulnerability scanning are refused if your licence does not include them.
- **Some things cannot be changed here.** A cloud instance refuses a pasted
licence, and people managed by Vantage HQ cannot be re-roled or deleted inside
the instance.
- **Errors are JSON**, with an `error` field naming the reason.
- **Everything that changes something is audited**, whether it came from the UI
or from a script. See [Audit log](../vantage/audit-log.md).
### Keys
## Vantage HQ
```
GET,POST /keys
GET,DELETE /keys/:id
GET /keys/:id/private-key
POST /keys/:id/assign
DELETE /keys/:id/assign/:serverId
```
### Workflows and steps
```
GET,POST /steps
PUT,DELETE /steps/:id
GET /steps/:id/export
POST /steps/import · /steps/seed-defaults · /steps/parse
GET /steps/usage
GET,POST /workflows
GET,PUT,DELETE /workflows/:id
POST /workflows/:id/run
GET /workflows/:id/runs
GET /runs/:runId
POST /runs/:runId/cancel
GET /runs/:runId/servers/:serverId/logs
GET /runs/:runId/servers/:serverId/logs/stream
```
`PUT` and `DELETE` on a step whose source is `default` answer `409`. See
[Workflows](../vantage/workflows.md#default-steps).
### Monitors and channels
```
GET,POST /monitors
GET,PUT,DELETE /monitors/:id
GET /monitors/:id/incidents · /monitors/:id/uptime
GET,POST /channels
PUT,DELETE /channels/:id
POST /channels/:id/test
```
### Secrets
```
GET,POST /secrets
GET,PUT,DELETE /secrets/:group
POST /secrets/:group/reveal
DELETE /secrets/:group/:key
```
### Console
```
POST /console/connect
GET /console/tunnel # websocket
```
### Other
```
GET /audit
GET /agent/latest-version
GET,PUT /settings (owner|admin)
POST /settings/secrets-token (owner|admin)
GET /license
POST /license (self-hosted only)
GET,POST /org/users
PUT /org/users/:id/role
DELETE /org/users/:id
GET,POST /auth/providers (owner|admin)
PUT,DELETE /auth/providers/:id (owner|admin)
POST /auth/providers/:id/test · /auth/providers/:id/ack-notice (owner|admin)
GET /auth/presets (owner|admin)
```
## Notable refusals
| Endpoint | Condition | Status |
| -------------------------------------------------- | ------------------------------ | ------------------- |
| `POST /license` | deployment is `cloud` | `409 cloud_managed` |
| `PUT,DELETE /steps/:id` | the step's source is `default` | `409` |
| `PUT /org/users/:id/role`, `DELETE /org/users/:id` | the user's auth source is `hq` | `409` |
`POST /license` is exempt from the licence check, so pasting a valid licence
works while the current one is expired that is the way out of degraded mode.
## Multi-tenancy
Every request is scoped to the instance resolved from the session. On a
multi-tenant deployment, a request arriving at `<slug>.vantage.<tld>` also has
its host checked against the session's instance, and a mismatch is rejected.
## Errors
Errors are JSON with an `error` field. Customer-facing endpoints in the HQ API
answer `404` rather than `403` for another account's resource, because a `403`
confirms the resource exists; the control plane's own API is single-tenant per
session and does not need that distinction.
## Admin API
Vantage HQ is a separate hosted service with its own API and its own session.
Its behaviour is described in the [Vantage HQ](../hq/accounts-and-signup.md)
section rather than here; the two services share no session and no
authentication.
The portal is a separate service with its own sign-in, described in the
[Vantage HQ](../hq/accounts-and-signup.md) section. A Vantage session does not
work there, and an HQ session does not work in your instance.
+24 -25
View File
@@ -8,13 +8,12 @@ Symptoms, in the order people hit them.
## The server will not start
**Exits immediately on boot.** Almost always a missing `GRPC_HOST` the server
**Exits immediately on boot.** Almost always a missing `GRPC_HOST`. The server
refuses to start rather than guess a value that would break every agent later.
**Fails during index creation.** The auth and settings index builders are fatal
on failure by design: those unique indexes are what enforce tenant isolation,
so starting without them is worse than not starting. Check the MongoDB user's
permissions and whether a conflicting index already exists.
**Fails while preparing the database.** Vantage stops rather than run without
the safeguards it sets up at startup. Check the MongoDB user's permissions and
whether an old, conflicting index is already there.
**Starts, but every secret operation errors.** `KEY_ENCRYPTION_KEY` is missing
or is not 64 hex characters.
@@ -22,15 +21,15 @@ or is not 64 hex characters.
## Nobody can sign in
**`/setup` appears when users already exist.** The server is pointed at a
different database than you think. Check the database name in `MONGO_URI`
it comes from the URI path, not a separate variable.
different database than you think. Check the database name in `MONGO_URI`,
which is taken from the end of the URI.
**Sessions do not stick.** Redis is unreachable, or the cookie is being dropped
because the site is served over plain HTTP.
**"Wrong organisation" style rejections.** The host and session guard is
comparing the request host's label against the session's organisation. Check
`APP_ROOT_LABEL`.
**"Wrong organisation" style rejections.** Vantage compares the address you
browsed to against the instance your session belongs to. On a custom domain,
check `APP_ROOT_LABEL`.
**OIDC redirects and then fails.** The callback URL registered with the provider
must match exactly. Keep one local owner account so a broken provider is not a
@@ -44,12 +43,12 @@ Work through it in this order:
2. What does it say? `journalctl -u vantage-agent -f`.
3. Can that machine reach the endpoint? Test `GRPC_HOST` **from the machine**,
not from the control plane host.
4. Was the token already used or expired? It is single-use and lives one hour —
create a fresh enrolment rather than reusing the old command.
4. Was the token already used, or older than an hour? Generate a fresh install
command rather than reusing the old one.
| Symptom | Cause |
| --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| Registers, then goes `offline` within minutes | Something permits the short `Register` call but drops the long-lived stream. Usually a proxy or idle-timeout middlebox |
| Registers, then goes `offline` within minutes | The short registration call gets through but the long-lived connection is dropped, usually by a proxy or an idle timeout |
| Stays `pending` forever | Registration never happened. Token spent, or the endpoint unreachable |
| Flaps between `active` and `offline` | Intermittent path, or a poll interval longer than the offline threshold |
@@ -67,15 +66,15 @@ instantaneous.
## A workflow run fails or hangs
- **Hangs at dispatch.** The target's command stream is not connected the
- **Hangs at dispatch.** The target's command stream is not connected; the
server may be `offline`.
- **Fails immediately with an interpreter error.** A bash step on a Windows
target, or PowerShell on Linux.
- **A value does not reach the next step.** Values pass through the file at
`$WORKFLOW_ENV`, one `KEY=value` per line. Declaring an output does not export
it.
- **A secret is empty.** The group is not in the step's `secret_refs`, or the
key name differs from the environment variable you are reading.
`$WORKFLOW_ENV`, one `KEY=value` per line. Listing an output does not pass it
on by itself.
- **A secret is empty.** The group is not attached to that step, or the key name
differs from the variable you are reading.
- **Logs stop mid-run.** A reverse proxy read timeout cut the stream. The run
itself continues; reload the page.
@@ -85,8 +84,8 @@ instantaneous.
| ----------------------------- | --------------------------------------------------------------------------------------------------------------- |
| Connects, then closes at once | guacd unreachable. Check `GUACD_ADDR` and that the container is running |
| SSH rejects the key | The stored key has no private half, or is not on the target |
| RDP fails on retry | Credentials are single-use and consumed at tunnel open enter them again |
| Hangs, then disconnects | The agent never claimed the relay, nothing is listening on the protocol port on the target's own loopback address, or guacd never dialled in time. Check the audit log for `console.proxy_failed` — its reason (`agent_timeout`, `dial_refused`, `guacd_timeout`, `rejected`) names which |
| RDP fails on retry | Credentials are single-use and consumed at tunnel open. Enter them again |
| Hangs, then disconnects | The agent could not reach the service on that machine, or setting up the session timed out. The audit log records which |
| Fails only in production | The reverse proxy is not forwarding WebSocket upgrade headers |
## Monitors report down when the service is up
@@ -98,7 +97,7 @@ instantaneous.
## Notifications are not arriving
Use the channel **Test** button it goes through the real delivery path, so a
Use the channel **Test** button. It goes through the real delivery path, so a
test that arrives proves credentials, network path and destination.
If the test fails: a webhook returning 300 or above counts as a failure, SMTP
@@ -109,9 +108,9 @@ needs `host`, `port`, `from` and `to`, and Telegram needs both `token` and
| Symptom | Cause |
| ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `409 cloud_managed` when pasting | It is a cloud instance. Licences are written by HQ; there is nothing to paste |
| Licence rejected as not matching | It is bound to a different instance UUID. Relink in HQ |
| Instance degraded despite a valid-looking licence | It has expired past its grace period. Pasting still works that endpoint stays available specifically so it can |
| "Managed by Vantage HQ" when pasting | It is a cloud instance, which is licensed for you. There is nothing to paste |
| Licence rejected as not matching | It was issued to a different instance ID. Relink it in Vantage HQ |
| Instance degraded despite a valid-looking licence | It expired more than a few days ago. Pasting a new one still works, which is how you recover |
| Cannot enrol another server | The server allowance is reached. Raise it in HQ or remove one |
## HQ portal problems
@@ -129,5 +128,5 @@ docker compose logs --tail=200 server
journalctl -u vantage-agent --no-pager -n 200 # on the affected machine
```
Include your instance UUID from **Settings → Licence** it is the reference
Include your instance ID from the **Licence** page, which is the reference
support works from.