Self-Service VDI — Admin Invite, Request, Approve, Provision
The Federal Frontier Platform provides a fully self-service Virtual Desktop Infrastructure (VDI) flow. Admins invite users, users request workspaces, admins approve, and the platform provisions persistent or temporary desktops automatically — zero shell access, zero plaintext passwords.
Self-Service VDI — Admin Invite, Request, Approve, Provision
The Federal Frontier Platform provides a fully self-service Virtual Desktop Infrastructure (VDI) flow. The entire lifecycle — from onboarding a new user to provisioning a persistent desktop workspace — runs through the OutpostAI UI with no shell access and no plaintext passwords.
Architecture Overview
The VDI self-service flow spans four platform components:
| Component | Role |
|---|---|
| OutpostAI (Next.js) | Admin and user-facing UI — invite form, request form, approval queue, workspace tiles |
| Trailboss API (FastAPI) | Backend endpoints for invite, request, approve, deny + deploy script orchestration |
| Keycloak (FAS realm) | Identity provider — user creation, password reset, OIDC tokens with role claims |
| OpenStack (Kolla) | Infrastructure — Cinder volumes, Nova VMs, Neutron floating IPs |
| Guacamole | Browser-based RDP gateway — connections auto-registered with per-workspace credentials |
| MailHog | Development email capture — receives invitation and notification emails |
End-to-End Demo Flow
The platform demonstrates the following self-service workflow:
1. Admin Invites a User
The admin navigates to Admin → Invite User in OutpostAI and selects an existing FAS realm user (or enters details for a new user). The platform:
- Creates the Keycloak user with a cryptographically random temporary password
- Marks the account for password reset on first login (
requiredActions: UPDATE_PASSWORD) - Sends an invitation email via Keycloak’s execute-actions-email API through MailHog
- The invitation email subject is “Update Your Account” from “Federal Frontier Platform”
Production note: MailHog is a dev-cluster email capture service. Production deployments wire SMTP to your enterprise mail relay. The flow is identical — only the transport changes.
2. User Requests a Workspace
After the invited user sets their password and signs in to OutpostAI, they navigate to the Workspaces tab and click Request a Workspace. The request dialog offers:
- Persistent Desktop — Cinder-backed 50 GB home directory. Files survive reboots. For long-term analysis work.
- Temporary Desktop — Session-only. No persistent storage. For quick tasks and demos.
The user provides a justification and submits. A notification email is sent to the VDI admin address, and the request appears in the admin’s VDI Requests queue.
3. Admin Approves the Request
The admin navigates to Admin → VDI Requests, which shows a filterable table of all workspace requests with state badges (pending, approved, fulfilled, denied, failed). The admin can:
- Approve — triggers synchronous provisioning (~60 seconds). The approve button shows a spinner with “Provisioning…” text while the deploy script runs.
- Deny — opens a comment dialog requiring a reason. The user sees the denial reason in their “My Requests” section.
4. Platform Provisions the Workspace
When the admin clicks Approve, the Trailboss API invokes the deploy script (deploy-persistent-workspace.sh) inside the Trailboss container. The script:
- Creates a Cinder volume (
vdi-home-{username}, 50 GB) if one doesn’t exist — auto-provisioned, no manual step - Boots a Nova VM from the
ffp-vdi-desktop-v2.2golden image with the volume attached at/dev/vdb - Sets a cryptographically random password for the
vdi-useraccount via cloud-init — users never see this password - Allocates a floating IP from the public network
- Registers a Guacamole RDP connection with the random password — Guacamole injects the credential transparently
- Grants READ permissions to the requesting user and the operator in Guacamole
- Transitions the request state to
fulfilled
Total provisioning time: ~60 seconds.
5. User Accesses Their Workspace
The user refreshes the Workspaces tab in OutpostAI and sees their new workspace tile (ffp-vdi-persistent-{name}). Clicking Connect opens a Guacamole RDP session in a new browser tab — the XFCE desktop loads with the user’s persistent home directory mounted and skel content (.bashrc, .profile, Desktop, Documents, Downloads) already seeded.
Files created in the workspace persist across VM reboots. The persistent volume (/dev/vdb) is formatted on first boot and mounted at /home/vdi-user by a systemd oneshot service.
Authorization Model
VDI admin capabilities are gated by a two-layer check:
| Layer | Mechanism |
|---|---|
| Backend | _require_vdi_admin() checks user_role == "platformadmin" OR "vdi-admin" in roles |
| Frontend | isVdiAdmin checks roles.includes("vdi-admin") \|\| roles.includes("platformadmin") \|\| roles.includes("superadmin") |
- The
vdi-adminKeycloak group exists in the FAS realm with a mapped realm role - Platform admins (
platformadmin,frontieradmin) inherit VDI admin access without explicit group membership - Regular users can submit workspace requests and view their own request status — they cannot see the admin queue or invite form
API Endpoints
All endpoints are on the Trailboss API (/api/v1/):
| Method | Path | Auth | Description |
|---|---|---|---|
POST |
/users/invite |
vdi-admin | Create Keycloak user + send reset email |
POST |
/workspace-requests |
Any authenticated | Submit a workspace request |
GET |
/workspace-requests/me |
Any authenticated | List own requests |
GET |
/workspace-requests |
vdi-admin | List all requests |
POST |
/workspace-requests/{id}/approve |
vdi-admin | Approve + provision (~60s) |
POST |
/workspace-requests/{id}/deny |
vdi-admin | Deny with comment |
Golden Image: ffp-vdi-desktop-v2.2
The VDI desktop image is built via Packer (not manually) and includes:
- Ubuntu 22.04 with XFCE desktop environment
- XRDP for remote desktop access
vdi-persistent-home.service— systemd oneshot that formats, fsck’s, and mounts/dev/vdbat/home/vdi-useron boot/usr/local/sbin/vdi-mount-persistent-home.sh— skel seeding script that populates the home directory from/etc/skelif.bashrcis missing (FF-570 fix)- Cloud-init support for password injection and service enablement
Image lineage: v1 → v2 → v2.1 → v2.2 (current production). Previous versions retained in Glance for rollback.
Database Schema
Workspace requests are stored in PostgreSQL (f3iai database):
CREATE TABLE workspace_requests (
id SERIAL PRIMARY KEY,
requestor_keycloak_id VARCHAR(64) NOT NULL,
requestor_username VARCHAR(100) NOT NULL,
justification TEXT NOT NULL,
estimated_duration VARCHAR(50),
workspace_type VARCHAR(50) NOT NULL DEFAULT 'knowledge_worker',
state VARCHAR(20) NOT NULL DEFAULT 'pending'
CHECK (state IN ('pending','approved','denied','fulfilled','failed')),
requested_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
decision_at TIMESTAMPTZ,
decided_by VARCHAR(100),
decision_comment TEXT,
fulfilled_at TIMESTAMPTZ,
fulfilled_workspace_id VARCHAR(100)
);
The table is auto-created on first use via the asyncpg connection pool (same pattern as the cluster templates system).
Security Properties
- Zero plaintext passwords — VDI user passwords are cryptographically random (24 characters,
secrets.choice), set via cloud-init, and stored only in the Guacamole connection parameters. No human ever sees or types them. - Invitation flow — Keycloak temporary credentials with
UPDATE_PASSWORDrequired action. Users set their own password via the Keycloak reset flow. - OIDC token-based auth — All API calls authenticated via Bearer token from the
federal-frontierOIDC client. Thesubclaim identifies the user;realm_access.rolesgates admin operations. - No shell access required — The entire provisioning flow runs inside the Trailboss container via
subprocess.runwithasyncio.to_thread(non-blocking). No SSH to infrastructure nodes.
Email Notifications
| Event | Recipient | Subject | Transport |
|---|---|---|---|
| User invited | Invited user | “Update Your Account” | Keycloak SMTP → MailHog |
| Workspace requested | VDI admin | “VDI Workspace Request #{id} from {username}” | Python smtplib → MailHog |
Production deployments replace MailHog with an enterprise mail relay or webhook integration.
Deployment
The VDI self-service system is deployed via the standard FFP GitOps pipeline:
- Trailboss API:
harbor.vitro.lan/ffp/trailboss:v5.9.4— includes OpenStack CLI, credentials, deploy script ConfigMap mount - OutpostAI:
harbor.vitro.lan/ffp/outpostai-dev:v1.2.1— includes admin invite/requests UI, workspace request form, role gating - Deploy script: Mounted as ConfigMap
vdi-deploy-scriptat/opt/vdi/deploy-persistent-workspace.sh - OpenStack credentials: Secret
openstack-admin-credentialswith 8OS_*environment variables - Guacamole password: Key
guacamole_admin_passwordinf3iai-secrets
All image builds via GitLab CI → Harbor → Gitea overlay update → ArgoCD auto-sync. No local Docker builds on infrastructure nodes.
Federation Roadmap
The current demo uses admin-invites-user onboarding. The architectural follow-up (FF-572) replaces this with federated identity:
“Jordan signs in once with her CAC and the platform discovers her identity from your IdP. That federation work is documented in our identity architecture ADR. What you’re seeing today is the user-facing flow for federation-shaped self-service VDI. Same flow, different identity source. That’s how it scales from 50 users to 700,000.”
Known Limitations (Current Release)
- No workspace destruction — workspaces can be created but not destroyed through the UI. Manual cleanup requires 4 OpenStack/Guacamole commands. (FF-584)
- Duplicate workspace names — re-provisioning for a username that already has a workspace fails on the Guacamole connection name collision. Cleanup required between runs.
- Single workspace type — “Data Scientist” template (GPU pool) is not yet implemented. Knowledge Worker only.
- No quota management — no limits on requests per user or total workspaces.