The VPN overview screen answers one question that a tunnel operator portal normally cannot: who is connected right now. It reads the engine’s own live state, not the database rows that describe what should be connected, and pairs that with durable history so you can also see who was connected and who was refused.

What this screen shows

The screen is built from three sources, stacked top to bottom: Four totals sit above the live table:
  • Connected now — number of sessions in the snapshot.
  • Received / Sent — aggregate rxBytes / txBytes.
  • Spoofed packets dropped — see Source-address violations. This is given equal billing with throughput deliberately: it is a security number, and a security number nobody looks at is useless.
Each live row carries the user, the device label on the credential, the leased VPN IP, the peer address the client is connecting from, Rx/Tx byte counters, how long the session has been up, and the gateway shard serving it.

Live sessions vs durable history

These two tables look similar and mean different things. Read them differently. Live sessions comes from the engine’s per-shard session snapshots (telequick:vpn:sessions:<shard> in Redis), which carry a TTL. It reflects reality — what the gateway currently has open. The table polls every 5 seconds, because a stale live table is worse than no live table when you are deciding whether a revoke actually took effect. If the engine restarts, the snapshots expire with it, so this table is not a record of anything; it is a window. Session history and Refused connections come from Postgres. Rows are written by the control plane’s vpn-events-sync consumer, reading the engine’s durable event bus — not from anything Redis carries. These rows survive an engine restart. The history query returns the most recent 25 sessions and refusals. So: if a session is missing from the live table but present in history with still open in the Ended column, you are looking at a durable record whose live counterpart has aged out of the snapshot. Session history rows include the assigned VPN IP, connect and disconnect timestamps, the close reason where one was recorded, Rx/Tx totals, and whether a second factor was used for that session (2FA column).

The credential projection and when to refresh access state

The gateway does not query the database on each handshake. It authenticates against a projection of the active credential set that the control plane writes for it. Every mutation that changes access — creating, editing or revoking a credential — re-projects that set on its own, so in normal operation you never touch this. The Refresh access state button in the page header calls adminVpn.resync. It exists for the one case that leaves no trace anywhere in the console: the engine (or Redis) came up after the projection had already been written, so nothing re-projected and the gateway is holding a credential set that is empty or stale. On success the button reports how many active credentials were refreshed (projected). On failure it surfaces the error inline. Reach for it when:
  • Nobody appears in the live table but you expect someone to be connected.
  • A credential you just revoked still seems to be accepted.
  • The engine or its Redis was restarted or replaced.
It is idempotent — it rebuilds the projection from the current active credential set, so running it when nothing is wrong changes nothing.

Fail-closed behaviour when access state is unavailable

If the gateway cannot read the active credential set, it fails closed: it refuses new connections rather than admitting them unauthenticated. This is why an empty Live sessions table has two very different explanations — genuinely nobody is connected, or the gateway is refusing everyone because it has no access state to check against. The empty state on the live table says as much. When you hit it and expected traffic, check gateway health and then refresh the access state.

Refusal reasons and close reasons

Refused connections records attempts the gateway rejected. Each row has the time, the claimed user (the identity the client asserted — which is why the column is labelled “claimed” and may be the raw claim rather than a resolved user), the device label on the credential if one matched, the refusal reason, and the peer address. Reasons fall into two classes, and the console colours them differently because they are two different conversations:
  • Authentication failures, highlighted in red: bad_auth (an unknown, invalid or revoked token) and any mfa_* reason (a missing, invalid or replayed second-factor code). A cluster of these from one peer address is a security event. A revoked credential trying to reconnect lands here too.
  • Everything else, shown unhighlighted — for example the address pool being exhausted at the time of the attempt. These are capacity and configuration problems, not intrusion signals.
Close reasons are recorded separately, on completed sessions. When a session has a close reason, Session history shows it in parentheses after the disconnect timestamp; sessions still open show still open.

Source-address violations

The Spoofed packets dropped total counts packets a client sent from an address it was not leased. The engine enforces the source address on the tunnel and drops anything that does not match, so the traffic never reaches the network — the counter is the only place you see it happened. When the counter is non-zero the screen raises a banner. Treat a non-zero value as a security signal, not a performance one. It is benign only if a device is genuinely misconfigured; otherwise it means something is attempting to impersonate another client on the VPN. Cross-reference the peer addresses in the live table and in Refused connections to find the device.

Attribute consumption with tags

The Usage by tag panel breaks tunnel consumption down by the values of a single tag key. The key picker is populated by tags.keys, which lists the tag keys in use in your org ordered by how many resources carry them, so the most-used key is preselected. Two things to know about reading it:
  • The panel reports consumption, not spend. VPN is bundled rather than rated per unit, so there is no per-unit price to total up.
  • Users inherit tags from their network. Tagging a network therefore allocates every user on it in one move, which is normally the cheapest way to get a complete breakdown.
The panel counts users as its resource noun.

Enabling session and refusal recording

Durable history is a deployment-level capability. adminVpn.history returns a recording flag alongside the rows, and when it is false the console shows a prominent warning above both history tables:
History is not being recorded. Session and refusal history is unavailable on this deployment.
Read that banner literally. When recording is off, empty history tables mean nothing — they are empty because nothing is being written, not because nothing has happened. The live table and the totals are unaffected; they come from the engine, not from Postgres. If you need refusal history for security review or session history for audit, recording has to be enabled on the deployment before the events occur. It is not backfilled — the vpn-events-sync consumer writes rows as events arrive on the bus.