Technical reference for the central API. The code remains the authority when implementation and documentation differ.
RDP Session API centralizes Remote Desktop Services telemetry from one or more Windows servers. It accepts event streams and WTS snapshots from the companion Agent, persists raw and consolidated state, and exposes read-only JSON endpoints for dashboards and integrations.
The design separates write credentials used by Agents from read credentials used by consumers.
| Repository | Responsibility |
|---|---|
RDP-Session-API |
FastAPI service, authentication, persistence, reconciliation, query endpoints, Linux deployment |
RDP-Session-Agent |
Windows Event Log collection, WTS snapshots, durable spool, Scheduled Task execution |
flowchart LR
subgraph WindowsServers["Windows Servers"]
S1["RDP Session Agent"]
S2["RDP Session Agent"]
SN["RDP Session Agent"]
end
subgraph ApiHost["Linux API Host"]
Proxy["HTTPS Reverse Proxy"]
API["FastAPI / Uvicorn :8091"]
DB[("MariaDB / MySQL")]
end
Consumers["Grafana / API consumers"]
S1 -->|"events + snapshots"| Proxy
S2 -->|"events + snapshots"| Proxy
SN -->|"events + snapshots"| Proxy
Consumers -->|"X-API-Key + JSON"| Proxy
Proxy --> API
API --> DB
- Agents authenticate with a server-specific
X-Server-IDand Bearer secret. - Each monitored server receives an independent Agent credential.
- The API stores only a hash of the Agent secret.
- Read/query clients authenticate separately with
X-API-Key. - Uvicorn is intended to stay on loopback behind a TLS reverse proxy.
- Database credentials and query keys live outside the Git checkout.
- TLS private keys and environment-specific proxy configuration are not repository content.
flowchart TB
Routers["FastAPI routers"] --> Services["Domain services"]
Services --> State["Session state machine"]
Services --> Reconcile["Snapshot reconciliation"]
Services --> Models["SQLAlchemy models"]
Models --> DB[("Database")]
Auth["Agent + query authentication"] --> Routers
Alembic["Alembic migrations"] --> DB
Expose ingestion, health, server summary, active session, and history endpoints.
Apply idempotency, normalize timestamps, update consolidated state, and reconcile WTS observations.
The API uses dedicated SQLAlchemy models and Alembic migrations instead of writing to an unrelated application's database.
erDiagram
SERVER ||--o{ SERVER_CREDENTIAL : owns
SERVER ||--o{ SESSION_EVENT : receives
SERVER ||--o{ RDP_SESSION : consolidates
SERVER {
string id PK
string hostname
string fqdn
string os_version
string agent_version
datetime last_seen_at
datetime last_snapshot_at
datetime last_boot_at
boolean enabled
}
SERVER_CREDENTIAL {
string id PK
string server_id FK
string token_hash
datetime created_at
datetime last_used_at
datetime revoked_at
}
SESSION_EVENT {
string id PK
string server_id FK
string event_type
int event_id
int event_record_id
int windows_session_id
string username
datetime boot_time
datetime occurred_at
string event_fingerprint
}
RDP_SESSION {
string id PK
string server_id FK
int windows_session_id
string username
string state
datetime logon_at
datetime logoff_at
int disconnect_count
int duration_minutes
string end_reason
}
sequenceDiagram
participant Agent as Windows Agent
participant API as RDP Session API
participant DB as Database
Agent->>API: POST /agent/events
API->>API: authenticate server
API->>API: normalize boot/time values
API->>DB: check event fingerprint
alt event is new
API->>DB: persist raw event
API->>DB: update consolidated session
API-->>Agent: accepted=1
else duplicate
API-->>Agent: duplicates=1
end
Event fingerprinting makes replay safe when the Agent resends a locally spooled batch.
sequenceDiagram
participant Agent as Windows Agent / WTS
participant API as RDP Session API
participant DB as Database
Agent->>API: POST /agent/snapshot
API->>API: authenticate server
API->>DB: compare observed sessions with open sessions
API->>DB: create/update observed sessions
API->>DB: close missing open sessions as RECONCILIATION
API-->>Agent: observed / created / updated / closed
The snapshot is a current-state correction mechanism. It complements Event Log ingestion rather than replacing it.
stateDiagram-v2
[*] --> ACTIVE: LOGON
ACTIVE --> DISCONNECTED: DISCONNECT
DISCONNECTED --> ACTIVE: RECONNECT
ACTIVE --> CLOSED: LOGOFF
DISCONNECTED --> CLOSED: LOGOFF
ACTIVE --> CLOSED: RECONCILIATION
DISCONNECTED --> CLOSED: RECONCILIATION
ACTIVE --> CLOSED: REBOOT
DISCONNECTED --> CLOSED: REBOOT
Typical terminal reasons include:
LOGOFF— lifecycle event explicitly closed the session;RECONCILIATION— WTS no longer observed an open session;REBOOT— a different boot instance invalidated sessions from the previous boot.
flowchart LR
Agent["RDP Session Agent"] -->|"X-Server-ID + Bearer secret"| Ingest["Write endpoints"]
Consumer["Grafana / client"] -->|"X-API-Key"| Query["Read endpoints"]
Ingest --> API["RDP Session API"]
Query --> API
Agent credentials intentionally cannot be used to read global session history.
flowchart TB
InternetOrLAN["Trusted network clients"] -->|HTTPS :443| Nginx["Reverse proxy"]
Nginx -->|HTTP loopback| Uvicorn["systemd: rdp-session-api"]
Uvicorn --> DB[("MariaDB / MySQL")]
Env["/etc/rdp-session-api/rdp-session-api.env"] --> Uvicorn
Systemd["systemd"] --> Uvicorn
Systemd -->|ExecStartPre| Alembic["alembic upgrade head"]
The bundled systemd path provides:
- dedicated non-login service account;
- loopback-only Uvicorn bind;
- migration preflight;
- automatic restart;
- journald logging;
- basic service hardening.
For every additional Windows server:
- register the server in the API;
- receive its unique
server_idand one-time secret; - install the companion Agent using those values;
- validate
/servers/{server_id}/summary; - repeat without sharing credentials between servers.
No API deployment change is required when adding another monitored server.
Grafana is a read-only consumer of the API and can run on a separate host.
flowchart LR
Grafana["Grafana Server"] -->|"HTTPS + X-API-Key"| Proxy["API Reverse Proxy"]
Proxy --> API["RDP Session API"]
Useful dashboard sources include:
- server list;
- active users;
- active/disconnected/open session counts;
- active session table;
- session history.
The Grafana host must trust the certificate chain used by the API endpoint.