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
+17 -20
View File
@@ -4,7 +4,8 @@ title: Audit log
sidebar_label: Audit log
---
Every mutating API path writes an audit event. The log is at **Audit**.
Anything that changes something is recorded, whether it was done in the UI or by
a script. The log is at **Audit Log**.
## What an event carries
@@ -23,21 +24,24 @@ keys and assignments, workflow and step changes, runs triggered, monitors and
channels, secret groups and reveals, console sessions opened, settings and
member changes, licence installs.
Reads are not recorded, with one deliberate exception: **revealing a secret**
writes an event, because reading that particular thing is an act rather than a
lookup.
Simply looking at something is not recorded, with one exception: **revealing a
secret** is.
## What is not recorded
- Sign-ins and sign-out.
- Sign-ins and sign-outs.
- Anything inside a console session.
- Step output. That lives in the run log, kept under the workflow retention
setting rather than with the audit log.
## Retention
Audit events are not swept by the workflow log retention setting that setting
governs run logs only. Audit history stays until the instance does.
How long audit events are kept comes from your licence: 30 days on Free, a year
on Professional, and unlimited on Enterprise. See
[Licensing and entitlements](../hq/licensing-and-entitlements.md).
This is separate from the workflow log retention setting, which covers run logs
only.
:::warning It is a log, not a control
The audit log tells you what happened. It does not restrict what can happen, and
@@ -45,18 +49,11 @@ an admin can do anything an admin can do. Use roles for restriction and the log
for accountability.
:::
## Getting events out
## Searching and exporting
`GET /api/audit` returns one page of events as JSON:
The page searches by actor, detail and event type, and filters by category, such
as `workflow`, `key` or `server`. The count shown is the number of matching
events, not the number on screen.
```json
{ "events": [ ... ], "total": 3214 }
```
It accepts `limit` (default 50, maximum 200), `skip`, `q` to search actor,
details and event type, and `category` to match the part of an event type
before the dot — `workflow`, `key`, `server`. `total` counts everything
matching the filter, not the page, so a short page is not the end of the log.
There is no streaming or push export; if you need events in a SIEM, poll that
endpoint, walking `skip` until you have `total`.
The same events are available from the API if you want them in a log system of
your own. See [Automating Vantage](../reference/rest-api.md).
+36 -47
View File
@@ -4,70 +4,59 @@ title: Browser console
sidebar_label: Browser console
---
An SSH, RDP or VNC session in a browser tab, with no client software and no
inbound port on the target beyond the one the protocol already uses.
An SSH, RDP or VNC session in a browser tab, with no client software to install
and no new port to open on the target machine.
Protocol handling is Apache Guacamole's the control plane proxies a WebSocket
to a **guacd** daemon and manages credentials around it.
:::info Requires the console feature on your licence
The console is a per-instance feature you enable on a paid plan. Without it, the
Console button is unavailable. See
[Licensing and entitlements](../hq/licensing-and-entitlements.md).
:::
## Requirements
## What you need
- `guacd` running and reachable from the server. The bundled Compose stack
includes it; `GUACD_ADDR` defaults to `guacd:4822`.
- `KEY_ENCRYPTION_KEY` set, since every credential involved is stored encrypted.
- The target's **agent must be online**. Console traffic is relayed over the
agent's existing outbound connection, so the control plane never needs a route
to the server's address — but it does need the agent.
- No inbound port on the target, beyond what the protocol already listens on
locally. A service bound only to `127.0.0.1` works, because the agent dials
loopback on the target itself.
- The target server's **agent must be online**. Console traffic travels over the
connection the agent already holds, so an offline agent means no session.
- `KEY_ENCRYPTION_KEY` set on a self-hosted install, since every credential
involved is stored encrypted.
- The service you are connecting to listening on the machine itself. It does not
have to be reachable from anywhere else, because the agent connects to it
locally.
## Opening a session
From a server's page, choose **Console**. Then:
1. The UI calls `POST /api/console/connect`, which mints a **one-time** session
token. If the target's agent is not connected, this fails immediately with
`409 agent_offline` rather than hanging.
2. The browser opens a WebSocket to `GET /api/console/tunnel` with that token.
3. The server marks the token consumed atomically, so a second use cannot
race and proxies the connection to guacd.
From a server's page, choose **Console**, pick the protocol and connect. Vantage
issues a one-time ticket for that session, and the connection is refused rather
than left hanging if the agent is not online.
## Credentials
### SSH
Authenticates with a private key stored in the [key library](./ssh-keys.md). The
key must have its private half uploaded; a public-only key cannot open a
session.
Uses a private key from your [key library](./ssh-keys.md). The key must have had
its private half uploaded; a public key alone cannot open a session.
### RDP and VNC
You supply credentials when connecting. They are encrypted, **single-use**, and
consumed when the tunnel opens. They are not retained for the next session.
You type the credentials when you connect. They are encrypted, used once and
discarded, so the next session asks again.
:::info Why single-use
A stored console credential is a standing grant to that machine for anyone who
can reach the endpoint. Consuming it at tunnel-open means a leaked session token
is worth one connection at most, and only until it is used.
:::
## During and after a session
## Session behaviour
Closing the tab ends the session. There is no reconnect: opening it again starts
a fresh session.
Closing the tab ends the session. There is no reconnect and no session
persistence reopening mints a new token and a new connection.
## Auditing
Opening a console is an audited action, with actor, server and time. What
happens _inside_ the session is not recorded: there is no session capture or
keystroke log. If you need that, it has to come from the target machine.
Opening a console is recorded in the [audit log](./audit-log.md), with who did
it, which server and when. What happens inside the session is not recorded.
There is no session replay or keystroke capture, so if you need that, it has to
come from the target machine itself.
## When it does not work
| Symptom | Cause |
| -------------------------------- | ------------------------------------------------------------------------------- |
| Connects then closes immediately | guacd unreachable check `GUACD_ADDR` and that the container is up |
| SSH refuses the key | The stored key has no private half, or is not in the target's `authorized_keys` |
| RDP fails on a fresh credential | Credentials are consumed on open; a retry needs them entered 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 |
| Symptom | What to check |
| -------------------------------- | ------------------------------------------------------------------------------------------ |
| Connects, then closes at once | The console daemon is unreachable. On a self-hosted install, check that `guacd` is running |
| SSH refuses the key | The stored key has no private half, or is not assigned to that server |
| RDP fails when you retry | Credentials are used once. Enter them again |
| Hangs, then disconnects | The agent could not reach the service on the machine, or the session timed out setting up. The audit log records the reason |
| Works locally, fails in production | Your reverse proxy is not forwarding WebSocket connections |
+15 -16
View File
@@ -28,22 +28,22 @@ Every monitor has a **runner**:
| `server` | The control plane's scheduler performs the check |
| a server ID | That server's agent performs it locally and reports the result |
Use `server` for anything reachable from the control plane public endpoints,
your own front door. Use an agent for anything only reachable from inside the
Use `server` for anything Vantage itself can reach, such as your public website
or API. Use an agent for anything only reachable from inside the
target network: a database on a private subnet, a service bound to localhost, a
device on a management VLAN.
:::tip Agent-run monitors measure what your users can't
A check run from the control plane tells you the service is reachable from
there. A check run on the machine tells you the process is alive. Those are
different questions, and outages usually live in the gap.
:::tip The two answer different questions
A check from Vantage tells you the service is reachable over the network. A
check on the machine tells you the process is running. Watch both where it
matters.
:::
## Interval, retries and state
- **Interval** how often to check.
- **Retries** how many consecutive failures are tolerated before the state
flips.
- **Interval** is how often to check.
- **Retries** is how many failures in a row are tolerated before the state
changes.
A monitor sits in `pending` until its first result. Failures accumulate; once
they exceed `retries`, the monitor goes `down`, an **incident** opens and the
@@ -58,21 +58,20 @@ Attach one or more [notification channels](./notification-channels.md) to a
monitor. Channels are shared, so one Slack destination can serve every monitor
you have.
Notification state is tracked per monitor, so a service that is down for six
hours does not send a message per interval.
You get a message when a monitor goes down and another when it recovers, not one
per check while it stays down.
## Uptime and incidents
The monitor detail page shows:
- **Uptime**, from hourly rollup records checks performed, how many were up,
and mean latency per hour. Rollups are what make the graph cheap to draw over
long windows.
- **Uptime**, summarised per hour: how many checks ran, how many passed and the
average response time.
- **Incidents**, each with a start, a resolution and the cause recorded at the
moment it opened.
## Disabling versus deleting
Disabling stops the checks and keeps the history. Deleting removes the monitor.
Prefer disabling for anything seasonal the uptime record is usually the part
you wanted.
Disable anything seasonal rather than deleting it, since the uptime record is
usually the part worth keeping.
+6 -8
View File
@@ -4,8 +4,8 @@ title: Notification channels
sidebar_label: Notification channels
---
A channel is a destination for alerts. [Monitors](./monitors.md) reference
channels by ID, so one destination serves as many monitors as you like.
A channel is a destination for alerts. One channel serves as many
[monitors](./monitors.md) as you like.
Manage them at **Settings → Notifications**.
@@ -64,9 +64,7 @@ Posts the alert as message content.
Port `465` uses implicit TLS; anything else uses STARTTLS.
Alert emails are rendered by the same email system that sends licence and
account mail, so a monitor alert and an account email look like the same
product.
Alert emails look like the rest of the mail Vantage sends you.
## The message
@@ -83,9 +81,9 @@ something that needs to branch on status.
## Testing
Every channel has a **Test** button. It dispatches a fabricated down event for a
monitor called "Test monitor", through the real delivery path so a test that
arrives proves the credentials, the network path and the destination, not just
the configuration form.
monitor called "Test monitor" and sends it the same way a real alert goes out, so
a test that arrives proves the credentials, the network path and the destination
as well as the form.
:::tip Test after every change
Channel settings are only exercised when something breaks, which is the worst
+22 -23
View File
@@ -10,54 +10,53 @@ External Secrets Operator.
## Groups and values
A **group** is a named bundle `prod-db`, `registry`, `acme-api`. Inside it are
key/value pairs.
A **group** is a named bundle, such as `prod-db`, `registry` or `acme-api`.
Inside it are key/value pairs.
Group by consumer, not by type. A group is the unit a workflow step references
and the unit ESO reads, so a group that matches one consumer is one reference;
a group holding everything is over-sharing to every step that needs any of it.
Group by who uses them rather than by what they are. A workflow step references
a whole group, so a group that matches one job stays tidy, while a group holding
everything hands all of it to every step that needs any of it.
## Managing them
**Secrets → New group**, then add keys.
Values are write-then-hidden. The list shows keys, never values. **Reveal** is a
separate action on a separate endpoint, and it writes an audit event so
looking at a secret is a recorded act.
Once saved, a value is hidden. The list shows key names only. **Reveal** is a
separate action, and it is written to the audit log.
Deleting a single key and deleting the whole group are separate operations.
## Using secrets in workflows
Add the group name to a step's `secret_refs`. At execution the group's pairs are
injected into the step's environment:
Add the group to a step's secret references. When the step runs, the group's
pairs are available to it as environment variables:
```bash
# secret_refs: ["registry"]
# with the "registry" group attached to this step
echo "$REGISTRY_PASSWORD" | docker login registry.example.com -u "$REGISTRY_USER" --password-stdin
```
A workflow can also override `secret_refs` per step, without changing the
library entry.
A workflow can change which groups a step uses without changing the step in the
library.
:::warning A step can print its own secrets
Injection puts values in the environment. If your script echoes them, or runs
with `set -x`, they land in the run log which is stored on disk and readable
in the UI. Vantage does not scrub step output.
Values arrive as environment variables. If your script prints them, or runs with
`set -x`, they end up in the run log, which anyone who can see the run can read.
Vantage does not filter step output.
:::
## Kubernetes External Secrets Operator
`GET /api/secrets/:group/values` returns a group's pairs for ESO, authenticated
with a **bearer token** rather than a session.
Kubernetes can read a secret group directly, using a token rather than a
sign-in.
1. Generate the token at **Settings → Integrations**. It is shown once; only its
SHA-256 is stored.
1. Generate the token at **Settings → Integrations**. It is shown once, and
Vantage stores only a fingerprint of it.
2. Put it in a Kubernetes secret.
3. Point an ESO `SecretStore` at the endpoint with that bearer token.
3. Point an External Secrets Operator `SecretStore` at your Vantage address with
that token.
The token is rotatable: generating a new one replaces the stored hash and
invalidates the old one immediately.
Generating a new token replaces the old one immediately.
:::danger This token reads every group
It is instance-wide, not scoped to one group. Treat it as a credential to the
+24 -34
View File
@@ -5,8 +5,8 @@ sidebar_label: Servers
---
The fleet. Every managed machine runs an agent that connects outbound to the
control plane, and everything else in Vantage keys, workflows, monitors,
consoles targets these records.
control plane. Keys, workflows, monitors and consoles all point at these
records.
## Enrolling a server
@@ -23,18 +23,17 @@ a one-liner to run as root on the target machine.
| `offline` | Last-seen passed the threshold |
The offline sweep runs every two minutes, so a machine that has just gone away
takes a little while to be marked as such. That delay is intentional a single
missed poll is not an outage.
takes a little while to be marked as such.
## Tags
A tag is a `key:value` label you put on a server. Tags are how you say what a
machine **is** `env:prod`, `role:web`, `team:core-infra` so that you can find
it later, and so that a [workflow](./workflows.md) can target it without you
machine is, such as `env:prod`, `role:web` or `team:core-infra`, so that you can
find it later and so a [workflow](./workflows.md) can target it without you
naming it by hand.
There is no tag library to manage first. A tag exists because a server carries
it, and it stops existing when the last server carrying it drops it.
There is no tag library to set up first. A tag exists as soon as a server
carries it, and disappears when the last server carrying it drops it.
### The rules
@@ -45,25 +44,22 @@ it, and it stops existing when the last server carrying it drops it.
| Value length | up to 64 characters |
| Per server | up to 20 tags |
Neither half may be empty, and keys beginning `sys:` are reserved for tags
Vantage may derive from inventory later, so a tag you write today can never
collide with one invented for you tomorrow.
Neither half may be empty, and keys beginning `sys:` are reserved for Vantage's
own use.
Anything outside those rules is refused with a message naming the rule, rather
than quietly saved in a shape you did not intend. Uppercase is not folded to
lowercase for you `Env` is a mistake, not a synonym for `env`.
Anything outside those rules is refused, with a message naming the rule.
Uppercase is not corrected for you, so `Env` and `env` are different tags.
### Editing a server's tags
On the server detail page, **Edit** beside the tag chips. Saving replaces the
whole set: what you see in the editor is exactly what the server will have.
There is no per-tag merge, so if two people edit the same server at once, the
last save wins outright rather than producing a blend of the two.
On the server's page, click **Edit** beside the tags. Saving replaces the whole
set, so what you see in the editor is exactly what the server ends up with. If
two people edit the same server at once, the last save wins.
### Filtering the fleet
The **Servers** list has a picker per tag key in use. Choosing values from more
than one key narrows the list a server must match **all** of them, not any.
than one key narrows the list, because a server must match **all** of them.
Untagged servers appear only when no filter is set.
:::tip A filtered fleet view is a link
@@ -96,16 +92,13 @@ metrics is normal rather than a fault.
Agents check for pending package updates hourly and report the count. From the
server page you can:
- **Apply updates** pushes `ApplyUpdatesCmd` down the command stream. The
agent runs the platform's package manager and reports back.
- **Update agent** pushes `UpdateAgentCmd` with a target version; the agent
downloads the release, verifies it and replaces itself. See
- **Apply updates** runs the machine's own package manager and reports back.
- **Update agent** upgrades the Vantage agent on that machine. See
[Agent updates](../operations/agent-updates.md).
:::warning Applying updates is not scheduled or staged
It runs now, on that machine. If you need ordering, health gates or a canary,
build it as a [workflow](./workflows.md) instead that is what workflows exist
for.
It runs immediately, on that machine. If you need ordering, health checks or a
test machine first, build it as a [workflow](./workflows.md) instead.
:::
### Console
@@ -114,10 +107,8 @@ Opens a browser SSH, RDP or VNC session. See [Browser console](./browser-console
## Windows servers
Windows agents register, heartbeat, run workflow steps and report inventory.
They do not manage `authorized_keys` the poll loop stops after the heartbeat
on any non-Linux host. This is a deliberate scope decision, not a gap being
worked on.
Windows agents register, run workflow steps and report inventory. They do not
manage `authorized_keys`.
## Removing a server
@@ -138,7 +129,6 @@ no longer running to remove them. Revoke and let the agent apply the change
## Agent tokens
Each server has its own token. The control plane stores only its SHA-256; the
plaintext exists in the agent's `0600` config and nowhere else. There is no way
to read a token back out of the control plane if one is lost, re-enrol the
machine.
Each server has its own token, which exists in full only in the agent's config
file on that machine. Vantage stores a fingerprint of it and cannot show it to
you again. If a token is lost, enrol the machine again.
+65 -91
View File
@@ -4,31 +4,14 @@ title: Settings
sidebar_label: Settings
---
One page, three groups: **Access**, **Monitoring** and **Integrations**. Plus
the licence, which has its own page.
One page, three groups: **Access**, **Monitoring** and **Integrations**. Your
licence has its own page.
Settings require the `owner` or `admin` role.
:::info Where instance settings went
Members and single sign-on used to live at `/settings/instance`. They are now
the Access group at the top of this page splitting "who can sign in" from "how
this instance behaves" produced two half-pages and a nav entry nobody could
distinguish from Settings. The old path still redirects.
:::
:::danger Upgrading breaks existing single sign-on until you re-register the callback URL
Callback URLs are now per provider instead of one shared URL for the whole
instance. If you already had single sign-on configured, it was carried
forward automatically, but its callback URL changed and **sign-in through it
will fail until you copy the new callback URL from its settings card and
register it with your identity provider**. The migrated provider's card shows
a dismissable warning as a reminder. Password sign-in is not affected by this
change, so an administrator can always sign in locally to make the update.
:::
Settings need the `owner` or `admin` role.
## Access
### Members
### People
Add, remove and re-role the people who can sign in.
@@ -38,112 +21,103 @@ Add, remove and re-role the people who can sign in.
| `admin` | Everything except owner-only settings |
| `member` | Servers, keys, workflows, monitors, secrets, console |
Local members authenticate with email and a bcrypt-hashed password.
Local members sign in with an email address and a password.
#### Members managed by Vantage HQ
#### People managed by Vantage HQ
On a cloud instance, people granted access from the HQ portal appear here as
read-only rows with a link to the portal.
On a cloud instance, anyone granted access from the Vantage HQ portal appears
here as a read-only row with a link back to the portal.
:::warning HQ-managed users cannot be edited locally
Changing the role of, or deleting, an `hq`-sourced user is refused with `409`.
HQ owns their role, their password and whether they exist at all a local
change would be overwritten by the next sync and would leave two writers for one
password hash. Manage them from [People and roles](../hq/people-and-roles.md).
:::warning You cannot edit those people here
Their role, password and access are owned by Vantage HQ, so changing or removing
them has to be done there. See
[People and roles](../hq/people-and-roles.md).
:::
### Single sign-on
Add as many identity providers as you need: one instance can have several at
once, each with its own name, its own button on the login page and its own
callback URL.
:::info Requires the single sign-on feature on your licence
It is a per-instance feature you enable on a paid plan.
:::
Pick a provider from the list of presets:
Add as many identity providers as you need. Each has its own name, its own
button on the login page and its own callback URL.
| Preset | You provide |
| ---------------------- | ------------------------------------------- |
| Microsoft Entra ID | Directory (tenant) ID |
| Google Workspace | nothing further, the issuer is fixed |
| Okta | Your Okta org domain |
| GitHub | Client ID and client secret only |
| Other (OpenID Connect) | The issuer URL of your identity provider |
If you configured single sign-on on an older version, see
[Upgrading](../operations/upgrading.md#single-sign-on-after-an-upgrade).
Every provider also needs a **Client ID** and **Client secret**; the secret is
stored AES-256-GCM encrypted and never shown again after you save it.
Start from a preset:
:::info GitHub requires a verified primary email
Vantage signs a person in by their email address. GitHub is asked for the
account's addresses and only accepts one that is **both** the account's
primary address **and** marked verified: an address GitHub has not confirmed
is not proof anyone controls it.
| Preset | You provide |
| ---------------------- | ---------------------------------------- |
| Microsoft Entra ID | Directory (tenant) ID |
| Google Workspace | Nothing further |
| Okta | Your Okta org domain |
| GitHub | Client ID and client secret only |
| Other (OpenID Connect) | The issuer URL of your provider |
Every provider also needs a **Client ID** and **Client secret**. The secret is
stored encrypted and is never shown again after you save it.
:::info GitHub needs a verified primary email
Vantage identifies people by email address, and it only accepts a GitHub address
that is both the account's primary address and confirmed by GitHub.
:::
#### Callback URL
Each provider gets its own callback URL, shown on its settings card with a
copy button. This is the address you register with the identity provider when
you set up the application on their side: each provider is registered
separately, even if you have several with the same identity provider.
Each provider's card shows its callback URL with a copy button. That is the
address you register with the identity provider when you set up the application
on their side. Register each provider separately, even where several use the
same identity provider.
#### Turning off password sign-in
You can disable local (email and password) sign-in once at least one provider
is enabled. Vantage refuses to save a change that would leave nobody able to
sign in, whether that change comes from the local login toggle or from
disabling the last enabled provider. Keep at least one option open until every
person who needs access can reach the new one.
Once at least one provider is enabled you can turn off email and password
sign-in. Vantage refuses any change that would leave nobody able to sign in,
whether that is switching off passwords or disabling your last provider. Keep
one route open until everyone who needs access can use the new one.
## Monitoring
- **Alert defaults** for monitors.
- **Notification channels** their own page. See
[Notification channels](./notification-channels.md).
## Integrations
### Workflow log retention
How long run logs are kept.
- **Offline threshold**, how long a server may go unheard from before it is
marked offline. The default is 5 minutes.
- **Offline alerts**, the [notification channels](./notification-channels.md) to
tell when that happens.
- **Notification channels** have [their own page](./notification-channels.md).
- **Workflow log retention**, how long run logs are kept.
| Value | Meaning |
| -------- | -------------- |
| unset | 30 days |
| a number | that many days |
| `0` | forever |
| `0` | keep forever |
### ESO read token
## Integrations
The bearer token External Secrets Operator uses to read secret groups. Shown
once, stored as a SHA-256 hash, rotatable. See
### External Secrets Operator token
The token Kubernetes uses to read your secret groups. It is shown once, stored
only as a fingerprint, and can be replaced at any time. See
[Secrets](./secrets.md#kubernetes-external-secrets-operator).
## Licence
`/settings/license` shows the deployment, tier, server allowance, enabled
features and expiry.
The **Licence** page, in the sidebar, shows your instance ID, whether you are
cloud or self-hosted, your tier, server allowance, enabled features and expiry
date.
On **self-hosted**, paste a licence here. This works even while the current
licence is expired that is the way out of degraded mode.
On a **self-hosted** install you paste your licence here. This works even while
your current licence has expired, which is how you get an instance out of
read-only mode.
On **cloud**, there is no paste form. The endpoint answers `409 cloud_managed`,
because a cloud licence is written by HQ directly. The page links to the portal
instead.
On a **cloud** instance there is nothing to paste. Licences are installed for
you, and the page links to the portal instead.
See [Licensing and entitlements](../hq/licensing-and-entitlements.md).
## Sessions
Sessions are an opaque token in the `km_session` cookie, held in Redis with a
24-hour TTL. There is no per-session management UI; restarting Redis signs
everyone out and affects nothing else.
## Host and organisation guard
On a multi-tenant deployment, a request to `<slug>.vantage.<tld>` resolves the
organisation from the slug and rejects a session belonging to a different one.
The label it looks for comes from `APP_ROOT_LABEL`.
:::warning A wrong `APP_ROOT_LABEL` disables the guard
It does not fail loudly it simply stops matching, and the host check stops
protecting anything. If you serve the UI on a custom domain, set it to match.
:::
Signing in gives you a session that lasts 24 hours. There is no session list to
manage. On a self-hosted install, restarting Redis signs everyone out and affects
nothing else.
+15 -18
View File
@@ -22,14 +22,12 @@ fingerprint, and never needs the private half for this path.
### Generate one on a server
Vantage can have an agent generate a keypair on a managed machine
(`GenerateKeyCmd` over the command stream). The public half comes back to the
library. You may optionally upload the private half too, in which case it is
Vantage can have a managed machine generate a keypair for you. The public half
comes back to the library. You may optionally upload the private half too, in which case it is
stored **AES-256-GCM encrypted** under `KEY_ENCRYPTION_KEY`.
The JSON representation of a key exposes only `has_private_key` and
`has_passphrase` never the material. Retrieving a stored private key is its
own endpoint and its own audit event.
Vantage never displays stored private key material in a list. Retrieving one is
a separate, deliberate action, and it is written to the audit log.
:::tip Why store a private key at all
The [browser console](./browser-console.md) needs one to open an SSH session. If
@@ -38,13 +36,13 @@ you are not using the console, do not upload private halves.
## Assigning
Assign a key to one or more servers. Within one poll interval 30 seconds the
agent picks up the change.
Assign a key to one or more servers. The agent picks up the change within about
30 seconds.
## Revoking
Revocation is **soft**: the assignment gets a `revoked_at` timestamp rather than
being deleted, so the history of who had access to what, and when, survives.
Revoking marks the assignment revoked, with a timestamp, rather than erasing it,
so the record of who had access to what, and when, survives.
The agent treats a revoked assignment as "not desired" and removes the line from
`authorized_keys` on its next sync.
@@ -60,13 +58,12 @@ Each poll:
1. The control plane returns the desired set of public keys for that server.
2. The agent reads `/root/.ssh/authorized_keys` and computes fingerprints.
3. **If the sets match, it writes nothing.** No disk churn on unchanged state,
which is most polls.
4. If they differ, it writes a temporary file, then `os.Rename()`s it over the
real one and sets mode `0600`.
3. **If they match, it writes nothing.** That is true of almost every check.
4. If they differ, it writes the new file alongside the old one and swaps it in
one step.
The rename is atomic, so a machine that dies mid-write keeps the old file
intact. There is no window in which `authorized_keys` is truncated or partial.
The swap cannot be interrupted halfway, so a machine that loses power mid-change
keeps its old, working file.
:::danger Vantage owns the whole file
The agent rewrites `authorized_keys` to match the desired set. Keys added by
@@ -77,5 +74,5 @@ it in Vantage.
## Recovering from a lockout
If you have removed every key from a machine and cannot get in, you still have
the console provided a private key is stored or out-of-band access from your
hosting provider. Vantage has no backdoor and does not keep a break-glass key.
the console, provided a private key is stored, or whatever out-of-band access
your hosting provider offers. Vantage has no backdoor and does not keep a break-glass key.
+19 -22
View File
@@ -9,8 +9,8 @@ against the security advisories published by that server's own distribution and
raises a finding for anything not yet patched.
Requires the **vulnerability scanning** feature on your licence. Without it,
agents collect nothing at all — there is no inventory stored and no findings
page to read.
nothing is collected and there is no findings page. See
[Licensing and entitlements](../hq/licensing-and-entitlements.md).
## What gets scanned
@@ -20,10 +20,9 @@ report.
Windows servers are not scanned.
Some distributions publish no machine-readable advisory feed. Those servers
show **unsupported** on their own page rather than appearing as having no
vulnerabilities — the two are very different answers, and only one of them is
good news.
Some distributions publish no security advisories Vantage can read. Those
servers are shown as **unsupported**, rather than as having no vulnerabilities.
Those are very different answers, and only one of them is good news.
## Why versions look "wrong"
@@ -43,9 +42,9 @@ the accurate one for the package you are actually running.
## The board
`/vulnerabilities` groups findings by CVE. One row per CVE with the number of
affected servers, expandable to the individual servers — the same CVE across
forty machines is one decision, not forty.
The **Vulnerabilities** page groups findings by CVE, one row each, with the
number of servers affected. Expand a row to see them. The same CVE across forty
machines is usually one decision, not forty.
Severity counts at the top filter the list when clicked. The state tabs switch
between **open**, **accepted** and **fixed**.
@@ -60,8 +59,8 @@ A finding with a known fixed version gets an **Apply updates** button, which
runs the same OS update the server page offers. There is no separate patching
mechanism.
Vantage never patches automatically. An unattended upgrade triggered by a third
party's data feed is a fleet-wide change nobody chose.
Vantage never patches automatically. Applying updates is always something you
ask for.
## Accepting a finding
@@ -72,23 +71,21 @@ or one with no vendor fix published at all.
a reason that is recorded in the audit log along with your name. On that date it
reopens by itself.
The expiry is required. A dismissal with no end date is how a finding gets
forgotten, and it is exactly what an auditor will ask to see.
An expiry date is required, so nothing is dismissed permanently by accident.
## Alerts
Alert rules live with your notification channels, under
**Settings → Notification Channels**. A rule has a minimum severity, an optional
server tag filter, and one or more channels.
Alert rules live with your
[notification channels](./notification-channels.md). A rule has a minimum
severity, an optional server tag filter, and the channels to notify.
A rule sends **one digest per scan** summarising what newly opened — never one
message per finding. A database refresh can open several hundred findings at
once, and a message each would flood the channel.
A rule sends **one summary per scan** covering everything newly found, rather
than one message per finding. A single update to the security data can raise
hundreds at once.
Findings that were already open do not re-alert.
## Fleet-wide package search
`GET /api/packages/search?name=openssl` answers which servers run a given
package and at what version, across the whole fleet. Useful during an incident
before a finding exists for it.
Search your whole fleet for a package by name to see which servers have it and
at what version. Useful during an incident, before there is a finding for it.
+65 -82
View File
@@ -4,10 +4,9 @@ title: Workflows and steps
sidebar_label: Workflows
---
A **step** is a reusable script with declared inputs, outputs and secret
references. A **workflow** composes steps in order and targets a set of servers.
Running one dispatches the steps to each target's agent and streams the output
back live.
A **step** is a reusable script with its own inputs, outputs and secrets. A
**workflow** puts steps in order and aims them at a set of servers. Running one
sends the steps to each server and streams the output back as it happens.
## Steps
@@ -15,12 +14,12 @@ A step has:
| Field | Meaning |
| --------------------- | ----------------------------------------------- |
| `name`, `description` | Library identity |
| `interpreter` | `bash` or `powershell` |
| `script` | The body |
| `declared_inputs` | Named parameters with defaults and descriptions |
| `declared_outputs` | Names this step promises to export |
| `secret_refs` | Vault entries injected as environment variables |
| Name and description | How you recognise it in the library |
| Interpreter | `bash` or `powershell` |
| Script | What it runs |
| Inputs | Named parameters, with defaults |
| Outputs | Values this step passes on |
| Secrets | Vault groups made available to it |
### Passing values between steps
@@ -34,42 +33,36 @@ echo "$HOSTNAME"
echo "HOSTNAME=$HOSTNAME" >> $WORKFLOW_ENV
```
That is the whole mechanism. `declared_outputs` documents what a step exports so
the designer can show it; the file is what actually carries the value.
That is the whole mechanism. Listing a step's outputs documents them for the
designer, but writing to that file is what actually passes a value on.
### Secrets
List a vault group in `secret_refs` and its key/value pairs are injected as
environment variables when the step runs. They are not written to the run log
unless your own script echoes them. See [Secrets](./secrets.md).
Add a vault group to a step and its pairs are available as environment variables
while it runs. They do not appear in the run log unless your own script prints
them. See [Secrets](./secrets.md).
### The workspace
Every run gets a per-run working directory on each target. Steps share it, so
one step can leave a file for the next. The agent removes it at the end of the
run (`CleanupWorkspaceCmd`).
Every run gets its own working directory on each server. Steps share it, so one
step can leave a file for the next. It is deleted when the run finishes.
Do not use it for anything that must outlive the run.
## Default steps
A small library is seeded into every organisation at boot from the image, so a
new install is not staring at an empty page.
Vantage ships a small library of ready-made steps, so a new install is not
staring at an empty page.
:::warning Default steps are read-only
Editing or deleting one is refused with `409`. Seeding rewrites them on every
boot, so an edit would silently revert and a delete would come back at the next
restart refusing is the honest answer.
They are reinstalled every time Vantage restarts, so any edit or deletion would
come back anyway. Vantage refuses the change rather than letting it quietly
revert.
To customise one, use the per-step **script override** in the workflow designer,
which belongs to that workflow and is not touched by seeding. To add to the
shared library permanently, a file has to be committed to the repository and the
server image rebuilt.
To adapt one, override its script inside the workflow that uses it. That change
belongs to the workflow and is left alone.
:::
The UI mirrors this the step modal opens read-only and Delete is hidden but
the API is the boundary; the UI is the courtesy.
## Building a workflow
1. **Workflows → New**.
@@ -81,11 +74,11 @@ the API is the boundary; the UI is the courtesy.
### Failure behaviour
| `on_failure` | Effect |
| ------------ | --------------------------------------------------------------- |
| `stop` | Abort this server's run. Other servers continue |
| `continue` | Record the failure, run the next step anyway |
| `retry` | Re-run the step up to `max_retries`, then treat it as a failure |
| On failure | Effect |
| ---------- | ------------------------------------------------------------- |
| Stop | Stop this server's run. Other servers carry on |
| Continue | Record the failure and run the next step anyway |
| Retry | Try again up to the limit you set, then count it as a failure |
### Per-step overrides
@@ -97,27 +90,21 @@ scoped to that workflow.
A workflow names servers two ways, and it can use both at once:
- **Target servers** an explicit list you pick from the fleet.
- **Target tags** a `key:value` selector matched against
[server tags](./servers.md#tags). More than one key ANDs: a server must carry
every pair to match.
- **Target servers**, a list you pick by hand.
- **Target tags**, matched against [server tags](./servers.md#tags). Give more
than one tag and a server must carry all of them to match.
A run goes to the **union** of the two, with duplicates removed. A server that is
both named explicitly and matched by the selector runs once, not twice. This is
what lets a workflow say "every production web server, plus this one box I am
watching" without maintaining a list.
A run goes to both sets combined. A server that is named by hand and also matched
by a tag runs once. That is how a workflow can say "every production web server,
plus this one machine I am watching" without you keeping a list up to date.
The designer shows the resolved count as you edit, so you can see how many
machines a change to the selector just added or removed before you save.
:::warning An empty selector matches nothing
Clearing the tag selector does not mean "all servers". A workflow with no named
servers and no tags matches nothing and is refused at run time rather than
reported as a success over zero machines.
The alternative reading, where an empty field means the whole fleet, turns a
cleared box into a fleet-wide run. That is not a mistake anyone should be able to
make by deleting text.
Clearing the tags does not mean "all servers". A workflow with no servers and no
tags matches nothing, and running it is refused rather than reported as a
success over zero machines.
:::
Tags are read **at run time**, not when you save. Tag a new machine `env:prod`
@@ -127,31 +114,29 @@ machine from every workflow that selected on it.
### Offline servers are still targeted
A server matched by tag is dispatched to even if its agent is offline, and that
step fails visibly on that machine. Vantage does not quietly shrink your target
list to the machines that happened to be reachable a patch run that skipped
three servers and reported success is worse than one that failed on three and
said so.
A server is still targeted when its agent is offline, and the run fails visibly
on that machine. Vantage does not quietly drop unreachable servers from a run,
because a patch run that skipped three servers and called itself a success is
harder to spot than one that failed.
Re-run the workflow once they are back, or fix the agent first.
## Running
**Run** snapshots the resolved steps into the run record and dispatches each step
to the target's agent over the command stream no waiting for the next poll.
**Run** records the exact steps being run, then sends them to each server
straight away.
:::info Runs freeze their steps
The snapshot is why editing a step tomorrow never rewrites what happened today.
A run shows the script that actually executed, not the current library version.
Editing a step tomorrow never changes what a past run shows. A run always
displays the script that actually ran.
:::
Targets run **in parallel**; steps within one server run **in order**.
## Schedules
A workflow can carry a schedule, and Vantage will start it the same way a person
would — the same dispatch, the same snapshot, the same run page. A scheduled run
is an ordinary run with `schedule` recorded as who triggered it.
A workflow can run on a schedule. A scheduled run is an ordinary run, on the
same run page, with the schedule recorded as what started it.
Open a workflow, choose **Edit**, and tick **Run on a schedule**. The expression
is standard five-field cron:
@@ -175,10 +160,10 @@ than the browser, so what you see is exactly what will fire.
### Timezones
A schedule stores an IANA timezone by name `Europe/London`, not an offset.
That is what makes a 02:00 job stay at 02:00 across a daylight-saving change
instead of drifting an hour for half the year. An unknown zone is refused when
you save it, not at 2am.
A schedule stores a timezone by name, such as `Europe/London`, rather than an
offset. That keeps a 02:00 job at 02:00 across daylight-saving changes instead
of drifting by an hour for half the year. A timezone Vantage does not recognise
is refused when you save it.
### Overlaps are skipped, not queued
@@ -189,28 +174,27 @@ should fall behind visibly rather than pile up.
### Missed occurrences
If the control plane was not running when an occurrence was due, it still fires
when the control plane comes back — but only within **one hour** of the due
time. Anything older is recorded as missed and dropped. A job missed by ten
minutes during an upgrade should still run; one missed by two days should not
suddenly fire at lunchtime.
If Vantage was not running when a scheduled run was due, it still runs when
Vantage comes back, as long as that is within **one hour** of the due time.
Anything older is recorded as missed and skipped, so a job missed during a short
upgrade catches up, while one missed for two days does not suddenly start at
lunchtime.
Either kind of skip is shown on the workflow's schedule panel, with the time it
was due and why it did not run.
## Watching a run
Step stdout and stderr stream back as chunks, are appended to a log file on the
server, and the UI follows them live. Each step records status, attempts, exit
code and its exported environment.
Output streams back as it happens and the page follows it live. Each step
records its status, how many attempts it took, its exit code and any values it
passed on.
**Cancel** stops a run in progress. Steps already running on an agent finish;
nothing further is dispatched.
## Log retention
Run logs are swept on a schedule set by `workflow_log_retention_days` in
Settings:
How long run logs are kept is set under **Settings → Monitoring**:
| Value | Meaning |
| -------- | -------------- |
@@ -220,16 +204,15 @@ Settings:
## Import and export
Steps export to a JSON file (`vantage.step/v1`) and import back, which is how
you move a step between instances or keep one in version control. There is also
a parse endpoint that turns a pasted script into a draft step by reading its
declared inputs and outputs.
A step exports to a file and imports back, which is how you move one between
instances or keep it in version control. You can also paste a script and have
Vantage turn it into a draft step for you.
## Practical notes
- A step is a script. It runs as root, on the target, with no sandbox. Review
what you import.
- Keep steps small and single-purpose; compose them in the workflow. That is
what makes the library reusable rather than a folder of near-duplicates.
- Keep steps small and single-purpose, and combine them in the workflow. A
library of small steps stays reusable.
- PowerShell steps only make sense on Windows targets and bash steps on Linux
ones. Nothing stops you targeting the wrong one; the step simply fails.
+33 -43
View File
@@ -4,30 +4,27 @@ title: Workloads
sidebar_label: Workloads
---
A **workload** is one Docker container or one systemd service. Each Linux
server reports what it runs, and you can start, stop and restart those
workloads — and read a snapshot of their logs without opening a console.
A **workload** is one Docker container or one systemd service. Each Linux server
reports what it is running, and you can start, stop and restart those workloads,
and read their recent logs, without opening a console.
Available on every instance. No licence feature is required.
## What gets reported
Linux servers only. Agents report every 60 seconds, and an unchanged list costs
a single small message rather than the whole thing again.
Linux servers only, reported every 60 seconds.
- **Containers** every container, running or not, with its image, published
- **Containers**: every container, running or not, with its image, published
ports, health, restart count and the compose stack it belongs to.
- **Services** systemd units that are running or failed, plus units that are
enabled but currently stopped. The platform's own units (`systemd-*`,
`user@*`, `session-*`) are filtered out; a typical host has 300 of them and
they bury the ten you care about.
- **Services**: systemd units that are running, failed, or enabled but stopped.
The operating system's own units are hidden, since a typical host has hundreds
of them and they bury the ones you care about.
Windows servers report no workloads at all.
## Docker not in use is not an error
Three different things look identical if you are careless, and only one of them
is a problem:
Three states look similar, and only one of them is a problem:
| What you see | What it means |
| ------------ | ------------- |
@@ -37,54 +34,47 @@ is a problem:
## Stacks are grouped
Compose stacks appear first, grouped under the stack name, then loose
containers, then services. A stack is one thing even when it is six containers,
and a flat list turns one decision into six rows.
Compose stacks appear first, grouped under the stack name, then individual
containers, then services.
The stack name comes from Docker's own `com.docker.compose.project` label. No
compose file is read from disk — a file on disk may not be what is running.
The stack name comes from Docker itself, so it reflects what is actually
running.
## Controlling a workload
Start, stop and restart are **owner or admin only**, and every action is
written to the audit log naming you, the server and the target.
The agent refuses to act on itself. `vantage-agent.service` is shown with its
buttons disabled: a server that stops its own agent goes offline, and the only
way back is SSH or physical access — which is exactly what this page exists to
avoid needing.
The Vantage agent will not act on itself, and its buttons are disabled. A server
that stopped its own agent would go offline, and getting it back would need SSH
or physical access.
A stop that never finishes is not reported as success. Both `docker stop` and
`systemctl stop` run under a 90-second limit, and a timeout comes back as a
real error.
A stop that never finishes is not reported as a success. Vantage waits up to 90
seconds and then reports the failure.
## Reading logs
Logs are **owner or admin only** and every read is audited. Unlike workflow
logs, a container's output cannot be masked: it is arbitrary, and a startup
banner or a stack trace may contain credentials nobody declared.
Reading logs is **owner or admin only**, and every read is audited. A
container's output cannot be filtered the way a workflow's can, and a startup
banner or stack trace may contain credentials nobody expected.
A log read returns a snapshot of at most **500 lines or 256KB**, whichever
limit is reached first, with the most recent output kept. When either limit
binds, the dialog says so — a truncated log must never be read as a complete
one.
You get the most recent output, up to **500 lines or 256KB**, whichever comes
first. If it was cut short, the dialog says so.
There is no live following. The [browser console](./browser-console.md) already
gives you a real terminal on the same server, where `docker logs -f` works
properly with its own scrollback.
There is no live tail here. For that, use the
[browser console](./browser-console.md), which gives you a real terminal on the
same server.
## Refreshing
Opening a server's Workloads panel asks its agent to report immediately, so
what is on screen is current rather than up to a minute old. That matters
because the panel has a Restart button on it: a stale row is not just a wrong
impression, it is a wrong action aimed at something that already died.
Opening a server's Workloads panel asks its agent to report straight away, so
what you see is current rather than up to a minute old. That matters when the
next thing you click is Restart.
If the agent is offline the refresh fails visibly rather than queueing. A
command whose target cannot be reached must say so.
If the agent is offline, the refresh reports a failure rather than waiting.
## Fleet view
**Workloads** in the sidebar searches the whole fleet by image, stack or state
— "which of these servers is still on the old image" — and links each result
back to its server.
**Workloads** in the sidebar searches your whole fleet by image, stack or state,
which is how you answer questions like "which servers are still on the old
image". Each result links back to its server.