Build log
Engineering a VDI platform in the open.
Status · Version one: complete
UpdatedLive: a RHEL 10 desktop reached at login.locumview.com through Keycloak SSO with enforced MFA, Guacamole on k3s, and an outbound-only Cloudflare Tunnel, plus an isolated guest demo. Built since: organizational login through Red Hat IdM, organization-set layouts and clipboard controls, the DISA STIG profile, encryption on every network hop, and the desktop as a bootc image that OpenTofu installs, encrypts, enrolls, and removes again with no manual steps. Desktops are built, signed, and updated through CI and accept only signed updates. Proven: a desktop destroyed and rebuilt from a clean clone with nothing typed, whose DISA STIG scan passes with 0 failures. Since 2026-10-21 the live demo runs on a desktop built from that image, replacing the hand-built reference desktop. Version one: 5 of 5 items done (the desktop built as a bootc image from code; browser access through SSO with enforced MFA; DISA STIG hardening with a committed OpenSCAP report; encryption in transit everywhere; the README with quick start and HIPAA mapping). Version one is complete.
The test
“Can a reviewer clone the repo and rebuild it with no manual steps?”
"I configured a thing" is IT administration. "It rebuilds from code" is engineering. In healthcare it is also what an audit needs: when someone asks to see that a clinical desktop was built the way you say it was, the answer should be a signed image, a commit, and a committed scan, not a screenshot and a memory. Every phase is judged against that test.
Roadmap
Phased, and judged against a rebuild.
- Phase 0Complete
Foundations
Done when: Repo exists, lints run on commit, secrets handling decided, ADRs written.
- Self-hosted Git with signed commits
- Checks on every commit and in CI on every push: secret scanning (detect-secrets, gitleaks), a guard that every SOPS file is encrypted, ansible-lint, tflint, kubeconform, all pinned by version and digest
- ADR 0001: RHEL 10 as the base distribution
- ADRs 0001 to 0015 written, from the base OS, desktop and access broker to the EU posture, version-one scope, the local AI operator, FIPS mode and OpenTofu
- Done: CI re-runs every check on each push, and the website preview deploys from it
- Phase 1Complete
Hand-built reference desktop
Done when: RDP into a headless session, and the changelog fully reproduces the desktop.
- RHEL 10.2 installed, registered, baselined, and snapshotted
- vTPM and guest agent verified
- GNOME Remote Desktop in system (remote login) mode
- Headless RDP session validated end to end, then straight-to-desktop sessions (user mode) after SSO
- Done: organization-set layout (Mac, Windows or GNOME style), locked centrally; Mac style verified
- Phase 2Complete
Access layer
Done when: A user reaches the desktop in a browser through SSO + MFA, with no RDP exposed.
- Done: Apache Guacamole + guacd on k3s, default-deny network policies
- Done: Keycloak SSO with TOTP enforced; WebAuthn after version one
- Done: public at login.locumview.com via an outbound-only Cloudflare Tunnel
- Done: isolated guest demo account
- Done: pod traffic between cluster nodes encrypted with WireGuard
- After version one: session recording for audit evidence, Nextcloud
- Phase 3Complete
Automation and hardening
Done when: The desktop is destroyed and rebuilt from a clean clone with zero manual steps.
- Done: DISA STIG with GUI applied to the reference desktop, OpenSCAP report committed, every exception documented (164 to 417 passing rules)
- Done: the desktop defined in a Containerfile as a RHEL image mode (bootc) image (ADR 0007), with the tailored STIG applied at build time, the separate file systems the STIG requires, and updates in place; it replaces the planned Ansible desktop roles
- Done: desktops install from an ISO and provision themselves on first boot, with nothing typed on the VM: disk encryption bound to the vTPM, directory enrollment, remote desktop sign-in, break-glass accounts, firewall
- Done: OpenTofu (Terraform-compatible) creates each desktop on libvirt with UEFI + Secure Boot and a vTPM, its directory host entry and its first-boot seed, and destroy removes all of it; state encrypted (ADR 0013)
- Done: HIPAA technical safeguard mapping; encryption at rest is now partly met (desktops installed from the image are encrypted; the cluster nodes and databases are next)
- Decided: no FIPS mode on the desktop for now, because remote desktop sign-in depends on an algorithm FIPS mode disables (ADR 0012); revisited for sectors that require FIPS
- Done: run from the operator machine with every secret from SOPS and nothing typed: each desktop registers itself in directory DNS and gets its Guacamole connection by host name; OpenTofu signs in with a directory account limited to hosts, host groups, and DNS. Verified in a real browser session: sign-in with MFA, then straight into the OpenTofu-built desktop; destroy removed every trace
- Done: image-built desktops register with Red Hat on first boot and get Red Hat’s Firefox ESR; destroy removes the registration, so test desktops never use up the subscription
- Done: Google Chrome in the image as the browser for web EHRs, beside Firefox ESR, both locked down to the DISA STIG settings; with the EHR launcher open for 15 minutes Chrome sent nothing at all, measured and published (ADR 0016)
- Done: CI builds the image on a dedicated runner, signs it with cosign (offline, no public log), attaches a signed SBOM, and the installer is built only from the signed image
- Done: desktops accept only updates signed with the project key; unsigned images and every other registry are refused. Proven on a desktop OpenTofu installed with nothing typed: first boot moved it to the signed CI build, it booted that build after a restart, and bootc upgrade then moved it to the next signed build
- Done: the proof. A desktop built from a clean clone with nothing typed, destroyed with nothing left behind, and rebuilt; the rebuilt desktop passes the DISA STIG image profile with 0 failures (405 rules), report committed
- Phase 4In progress
Packaging and supply chain
Done when: Every LocumView component in the image comes from a signed package or a pinned, verified source, and every image release is signed, has an SBOM, and is verified before it is promoted.
- Already built, ahead of this phase: signed images (cosign) and SBOMs (syft) from CI, pulled into Phase 3 because version one needed signed-only updates
- Built: every image build is scanned against the DISA STIG image profile before it is pushed, and the result is attached to the image as a signed attestation, beside the signature and the SBOM
- Built: verified promotion. A build goes to a testing channel; desktops follow the stable channel, which moves only after the signature, the SBOM and a passing scan are verified. First promotions on 2026-10-22; the second was tested on a desktop first (upgrade, full STIG scan, rollback and forward again)
- Built: LocumView’s own pieces (shell extensions, branding, the tour, the EHR launcher) as signed RPMs, built and published by CI; the image installs them from the project’s package registry and checks every signature. Planned: a public COPR mirror, and package versions pinned to the image build so a rebuild installs the same packages
- Planned: Fedora and EPEL packages for dependencies RHEL does not ship, starting with the Python FHIR libraries
- Phase 9 litePlanned
Clinical AI demo
Done when: A pharmacist signs in at the LocumView desktop, opens the clinical app from its icon, launches it from an OpenEMR chart in patient context, and sees at least one stewardship and one IV to PO finding with the agent’s explanation, all on synthetic data and local models. The phase ends with a frozen, versioned evaluation build.
- Planned, right after Phase 4 (ADR 0017): one web app with a triage dashboard, module queues (Antimicrobial Stewardship, IV to PO, ADE Monitoring), and a patient view, opened in the hardened Chrome in app mode from its own icon, behind Keycloak
- Planned, first: OpenEMR and Synthea as the mock EHR, with a check that a scenario loads reproducibly and that cultures and susceptibility results come back out through its FHIR API faithfully enough for stewardship rules
- Planned: a scenario library of 10 to 20 hand-built synthetic cases, growing to 20 to 30 for evaluation, including cases where no intervention is right and ambiguous ones; each versioned with its expected findings, rationale, guideline citations and a reference answer
- Planned: the clinical app, launched from the EHR chart through SMART on FHIR; then the Epic and Oracle Health sandboxes
- Planned: the rules and explanation pipeline. Deterministic rules decide what is flagged; a local model explains each finding, with its reasoning and source data shown; no orders and no automatic treatment changes
- Planned: internal refinement of every case, ending in a frozen, versioned evaluation build
- Phase 5In progress
Other distributions
Done when: A SUSE or openSUSE desktop built from this repository passes its own hardening profile and the same access-layer tests as the RHEL desktop.
- In progress, not shipped: SUSE Linux Enterprise and openSUSE, from the same desktop definition, with equivalent hardening
- Planned: Debian, validated as customer need appears
- The same GNOME layouts, policies, and remote display on every distribution (ADR 0014)
- Runs largely in parallel with the RHEL work and never delays it
- Phase 6Planned
On-premises hypervisors and Kubernetes
Done when: The same signed desktop image runs on Proxmox and on KubeVirt, and only the OpenTofu module changes between them.
- Proxmox VE as the practical production target (ADR 0009), with its own OpenTofu module
- KubeVirt on k3s as a scoped learning piece, mapping to OpenShift Virtualization; first workload: a demo desktop that resets between sessions
- GitOps: merging a pull request creates or changes a desktop, with no manual kubectl
- Monitoring of desktops and the access layer with Prometheus and Grafana; VM memory limits set first
- Host configuration (bridge, firewall, libvirt, cluster prerequisites) as an Ansible role, replacing today’s host scripts; the desktop itself stays an image
- Phase 7Planned
Public and sovereign cloud
Done when: A desktop built from the same image runs in a private AWS subnet, reached only through the same access layer, created and destroyed by OpenTofu within a budget alarm.
- AWS alongside the SAA-C03 certification: budget alarms first, private subnets, no public IPs, IAM instance roles
- The same image turned into an AMI by bootc-image-builder; RHEL licensing through Red Hat Cloud Access checked before use
- Encrypted remote state for OpenTofu, and every test environment destroyed after the session
- Later: European-owned clouds for sovereignty-focused deployments (see Deploy)
- Phase 8Planned
Documentation and portfolio
Done when: A reviewer understands the platform from the README, a short demo video, and a write-up per phase, and can rebuild it from the repository.
- Done: README with architecture diagram, quick start, and HIPAA mapping (version one)
- A 3 to 5 minute demo video: sign-in with MFA, the desktop, and a rebuild from code
- A write-up per phase, built from the build log and its field findings
- Architecture notes and platform documentation on the Resources page
- Phase 9Planned
Clinical AI on synthetic EHR data
Done when: A scenario patient triggers a review, and a cited, guardrail-checked recommendation lands in the provider queue, Matrix, and dashboard, with a complete audit log and no PHI anywhere.
- Planned, first: the Clinical Review Workspace (ADR 0018), after the demo video and first write-ups. Invited external clinicians, three clinical pharmacists first, assess the frozen build’s findings on synthetic cases through the same access path as every LocumView user: Keycloak with MFA, Guacamole, a short-lived desktop
- Planned: independent evaluation, a structured expert review of a research prototype on synthetic data, never described as clinical validation; then published findings, with reviewers named only with their written permission
- The scenario library kept as a clinical regression suite for every later build
- FHIR R4 server (Medplum preferred, HAPI FHIR alternative) in the lab environment
- Agents authenticate through real SMART on FHIR OAuth with scoped, revocable tokens
- Recommendations written back as FHIR Communication or Task resources
- Watch only: Epic Connectors (announced 2026-10-21) as a possible read-only delivery path for stewardship findings; revisit when Epic publishes developer documentation
Version one is complete when
- Done: One RHEL 10 desktop built as a bootc image from a Containerfile and provisioned on the reference hypervisor (libvirt) from a clean clone, with zero manual steps.
- Done: Reached in a browser through Guacamole, Keycloak SSO with enforced MFA, no exposed RDP.
- Done: DISA STIG profile applied, OpenSCAP report committed, exceptions documented.
- Done: Encryption in transit everywhere.
- Done: README with architecture diagram, quick start, HIPAA technical-safeguard mapping, honest status.
Request path
- 1Browser
- 2Cloudflare (TLS)
- 3Cloudflare Tunnel
- 4Guacamole
- 5guacd
- 6RDP
- 7RHEL 10 desktop
Only guacd can reach RDP. Nothing on the path listens publicly.
Launch gate
What stands between the internet and a desktop.
Identity and access
- Default Guacamole admin removed; no default or test accounts remain
- Keycloak is the single identity provider over OIDC, so MFA is never enforced in two places
- MFA (TOTP) enforced for every organizational account, with enrollment required at first sign-in; the guest demo is password-only by design and contained by the isolation controls below
- Next: WebAuthn and passkeys, preferred over TOTP for phishing resistance
- Brute-force lockout in Keycloak and Guacamole and short token lifetimes; next: rate limiting at the edge
Guest isolation
- Guest egress fenced: internet only, no route to the private network, the cluster API, or other desktops
- Separate non-admin guest account, no stored credentials, tokens, or kubeconfigs, and no access to other users' files
- Next: an ephemeral guest VM that resets to a clean state between sessions
- No patient data on the demo; synthetic Synthea and scenario data only once clinical features exist
Exposure
- RDP and VNC never exposed directly; only the Guacamole gateway, behind TLS
- Published only through an outbound-only Cloudflare Tunnel; no open inbound ports, and the identity provider's admin console is not reachable from the internet
- Every change can be rolled back: image-built desktops return to the previous image with bootc, and the hand-built reference desktop to a known-good snapshot
Clinical AI pipeline
Stewardship logic lives in retrieval and guardrails, not model weights.
- Stage 1
Trigger
Scheduled sweep of active antimicrobial orders, or an event such as a new culture result via CDS Hooks.
- Stage 2
Retrieval
Patient, MedicationRequest, Observation, Condition, and AllergyIntolerance over FHIR R4.
- Stage 3Core build
Normalization
Raw FHIR becomes a pharmacist-style picture: drug, dose, renal function, organism, day of therapy.
- Stage 4Core build
Reasoning
Model plus retrieved guidelines. Every recommendation cites its source and shows its reasoning.
- Stage 5Core build
Guardrails
Safety-bound checks, citation required, low-confidence output suppressed or flagged for human review.
- Stage 6
Delivery and audit
Routed to the provider queue, Matrix, or dashboard, with every step logged.
Tuning what surfaces versus what gets suppressed is where clinical judgment matters most. Every scenario output is checked against a reference answer written by a clinical pharmacist, and later assessed by independent reviewers.
About LocumView’s clinical AI work. The clinical AI module is a research prototype, built and tested only on synthetic patient data. No real patient data, and no data, protocols or confidential information from any employer or healthcare organization, is used in it. It is developed independently, on the author’s own time and resources, and is not affiliated with, sponsored by or endorsed by any institution. It is not used in patient care. Any expert review of it is an independent professional assessment of a prototype, not clinical validation, certification or regulatory approval.
Field findings
What building it taught us.
Checked the day after: php2shell
On 21 October 2026 PHP fixed two critical flaws that let an unauthenticated attacker run code on a web server (CVE-2026-109618 and CVE-2026-109619), already exploited in the wild. The next day every part of LocumView was checked: the desktop image and the running desktops, the cluster nodes, the directory server, every container running on the cluster and the ones that could be started again, and this website. None runs PHP, so no patch was needed, and the method and results are published in the repository. One finding for the plan: OpenEMR, the mock EHR for the first clinical AI demo, is a PHP application, so it will be built on a fixed PHP release and covered by the same check.
A browser that says nothing
Web EHRs are validated on Chromium browsers, so the desktop ships Google Chrome for the EHR, which sits awkwardly with keeping data away from big platforms. The answer had to be measured, not asserted. With its managed policies in place and the EHR open for 15 minutes, Chrome sent no DNS query and no connection at all. The same Chrome without the policies reached about ten Google services within 90 seconds. The capture turned up something else: the desktop had quietly picked up the internet provider’s DNS servers, because a network setting made at first boot did not survive the next one. It is now enforced at every boot.
The fix that never arrived
The STIG scan of a desktop rebuilt from a clean clone found six failures the image build could not catch, because they happen later: directory enrollment rewrites two hardened settings, and the first boot creates SSH host keys and the file-integrity database. First-boot provisioning now puts each one back, and the fix shipped in the next signed image. A new desktop would still not have run it: provisioning runs from the image the installer carries, not from the newer signed image the desktop switches to on first boot, so a provisioning fix reaches new desktops only through a new installer. With the installer rebuilt, the third desktop from a clean clone passed with 0 failures.
Signed, and still refused
Desktops accept only updates signed with the project key, so the first test switched one to a signed CI build. It was refused: "A signature was required, but no signature exists". The signature was there. The signing tool now writes signatures in a newer bundle format by default, and the container tools RHEL uses to verify updates read only the classic one. CI now signs in the classic format. Two more turned up on the way: bootc will not enforce signatures while the system’s default policy accepts anything, so the default is now reject; and the signed SBOM, at 161 MB with every file listed, was too large for the verifier to read back, so it now lists packages only (11.6 MB).
The installer did more than install
The first desktop built from the image had no browser. On a conventional RHEL install, the installer quietly adds Firefox from Red Hat’s Flatpak repository; an image-built desktop never runs that step. First boot now does it, after registering the desktop, which Red Hat’s repository requires. It still failed at first: the repository authenticates through a helper that needs a desktop session bus, which a boot-time service does not have. Giving the command a private one fixed it.
A name that did not exist yet
Each desktop registers its own name in the directory’s DNS when it enrolls, so the gateway connects by name, not by a leased address. The first one stayed unreachable by name for most of an hour. Enrollment had looked the name up a moment before registering it, the LAN resolver cached the "does not exist" answer, and the zone told resolvers to keep such answers for an hour. The zone now says one minute, so a new desktop resolves almost at once.
The hypervisor has opinions about paths
The first OpenTofu-built desktop was defined but would not start: "Permission denied" on its own disk. The script-built desktops had referenced their disks by file path; the provider referenced a storage-pool volume. On hosts that confine guests with AppArmor, libvirt adds only file paths to each guest's profile, so the volume was never allowed. Disks are now attached by path. The same first runs showed that a failed start leaves a VM defined but outside the state, which is now in the module notes.
An unclean shutdown counts as an attack
Desktops unlock their encrypted disk with the virtual TPM, so nobody types a passphrase at boot. During testing, one desktop suddenly asked for its passphrase anyway. The disk and the binding were fine: the TPM was in dictionary-attack lockout. A TPM counts every unclean shutdown as a failed authorization, and the default allows only three, each taking about 17 minutes to expire. Three forced restarts, or a power cut and a host crash, are enough. Installation and first boot now allow 32, each expiring after 5 minutes, and a fresh desktop came back from three forced resets in a row, unlocked, in 17 seconds each.
Image mode leaves /var to you
Directory enrollment failed on the first image-built desktop: the IdM client could not find its own state directory. In image mode, /var belongs to the machine, not the image, so package directories under /var are not created on an installed system unless something declares them. The client and certificate tools now get theirs from tmpfiles.d. Three more first-boot surprises came out of the same test: a startup ordering loop that made systemd silently drop the provisioning job, a text-mode install that set the default boot to no graphical login, and the setup wizard appearing before any account existed.
FIPS mode versus remote desktop sign-in
The first bootc image ran in FIPS mode, as the DISA STIG asks, and RDP sign-in stopped working. GNOME Remote Desktop accepts only Network Level Authentication, which uses NTLM, and NTLM depends on MD4, which FIPS mode disables. The server log says it plainly: "md4: NTLM support not available". Re-enabling MD4 for one process would not be FIPS in any meaningful sense, so the desktop runs without FIPS mode, every other STIG control stays, and the decision is recorded in ADR 0012 for the day a FIPS-only buyer asks. HIPAA does not require FIPS mode. The same test showed that FIPS mode also refuses Ed25519 SSH keys.
Hardening can remove what you depend on
One STIG rule removes gssproxy. dnf also removed nfs-utils, which depends on it, and with it the IdM client tools, which depend on nfs-utils. Sign-in kept working, because the directory enrollment itself stayed, so the hands-on checks passed. It surfaced two days later while mapping the desktop for the image. The rule is now a documented exception, and dependency checks go all the way down.
Manual builds drift from intent
The reference VM came up on SeaBIOS, the virt-manager default, instead of the UEFI + Secure Boot target. It was rebuilt from a recorded virt-install command with UEFI, Secure Boot, and a vTPM, and the provisioning script now sets that firmware for every desktop. It is the argument for building from code, demonstrated.
TPM credential sealing vs SELinux
GNOME Remote Desktop 49 can seal RDP credentials to a TPM, but RHEL 10.2 policy denies the confined daemon access to the TPM device. The change was reverted, not patched with a custom module, because a local policy exception is not defensible under STIG. Evidence is committed, and an upstream selinux-policy report is a candidate contribution.
Certificates need SANs
FreeRDP reported the CN-only self-signed certificate as a name mismatch. The remote access setup, now run by first-boot provisioning, issues each desktop’s certificate with DNS and IP SANs and a private key only its user can read.
Supply-chain-aware tooling without EPEL
pre-commit, ansible-lint, gitleaks, tflint, and OpenTofu are not in RHEL repos. They are installed with pip --user, as Podman containers pinned by digest, or from signed upstream releases checked before use, so the build machine stays clean. Two OpenTofu providers are unsigned in the registry, so their hashes were checked against the maintainers’ published checksums and pinned in the lock file.
Never hardcode system IDs
System UIDs and GIDs are allocated dynamically on RHEL 10, so the build and provisioning scripts refer to accounts by name and never assume a number. Credentials are in the repo only as SOPS-encrypted secrets, with a pre-commit check that blocks plain text.
Architecture decisions
Each choice, and the reason behind it.
- Base OS
- RHEL 10
- Dominant enterprise Linux in regulated healthcare: published STIG and CIS baselines, FIPS-validated crypto, a support contract, and a 10-year lifecycle. SLES and Ubuntu LTS were considered; Rocky and Alma suit labs but lack vendor accountability. The distribution is the most swappable layer, so roles can branch to SLES or Debian later.
- Desktop
- GNOME via headless RDP (ADR 0014)
- RHEL 10 is Wayland-only; GNOME Remote Desktop is the supported native RDP path. Organization-set layouts give staff a Windows, Mac or GNOME style on the same desktop.
- Broker
- Apache Guacamole (ADR 0015)
- Clientless HTML5, native RDP to the existing desktops, OIDC with Keycloak, connection history and session recording for audit evidence, Apache 2.0. Kasm, Teleport, noVNC, and the commercial brokers were considered.
- Identity
- Keycloak SSO + MFA
- Centralized identity, moving to WebAuthn and passkeys for phishing resistance, analogous to clinical badge-tap.
- Exposure
- Outbound-only Cloudflare Tunnel
- Nothing listens at the network edge. The identity provider admin console is not published. RDP is only reachable from guacd.
- Infrastructure as code
- OpenTofu outside, bootc inside (ADR 0013)
- OpenTofu, the open-source fork of Terraform with the same language and providers, creates each desktop VM, its seed, and its directory host entry, and removes them on destroy. Chosen over HashiCorp Terraform for built-in state encryption (the state holds per-desktop secrets) and an open license. The image defines what runs inside the desktop.
- Desktop build
- bootc image from a Containerfile (ADR 0007)
- The OS is built, versioned, and rolled back like a container image; the session runs as a VM booted from it, because a GPU and audio desktop is a VM workload, not a pod. Everything per desktop (name, directory enrollment, credentials, keys) is applied at first boot, never baked in.
- Disk encryption
- LUKS bound to the vTPM
- No passphrase at boot, and a disk copied off the host cannot be read. Each desktop has a recovery passphrase kept in SOPS, and the TPM lockout limits are tuned so that forced restarts do not lock it.
- Browsers
- Firefox ESR, plus hardened Chrome for web EHRs (ADR 0016)
- Web EHRs are validated on Chromium browsers, and hospital IT can reject an unsupported browser even if it works. Firefox ESR stays the system browser, supported by Red Hat. Chrome opens the EHR, locked down with managed policies and egress rules so it talks to Google only where the STIG requires (Safe Browsing); an outbound traffic audit will be published. Chrome on RHEL is supported by neither Red Hat nor Google, so LocumView owns it. The browser is a swappable slot, so a customer’s standard browser can take its place.
- FIPS mode
- Off on the desktop, for now (ADR 0012)
- GNOME Remote Desktop signs in only through NTLM, which FIPS mode disables. HIPAA does not require FIPS mode, every hop stays encrypted with strong TLS or WireGuard, and every other STIG control applies. Revisited when LocumView targets sectors that require FIPS-validated cryptography in FIPS mode.
- Hardening
- scap-security-guide + OpenSCAP
- Compliance as code, with the reports committed to the repo and mapped to HIPAA safeguards.
- Platform ladder
- libvirt, then Proxmox and KubeVirt, then AWS
- The signed image and the OpenTofu pattern stay the same on every rung; only the provider module changes. Proxmox is the practical production target: it runs desktops as native VMs and gives hospital IT the operations it knows from VMware (a console, live migration, high availability, built-in backup and restore), at a fraction of the cost, for organizations moving off VMware. KubeVirt tells the OpenShift Virtualization story.
Horizon mapping
Commercial VDI capabilities, rebuilt with open tooling.
| Horizon component | LocumView counterpart |
|---|---|
| Unified Access Gateway | Outbound-only Cloudflare Tunnel |
| Connection Server | Apache Guacamole |
| Blast / HTML Access | RDP via guacd, in the browser |
| Identity / MFA | Keycloak with TOTP (WebAuthn next) |
| Instant-clone pools | bootc desktop images, created per desktop by OpenTofu (in progress) |
Honest scope
Where it fits, and where it does not.
LocumView targets workloads that are web-based or Linux-native: analysts, data science, pharmacovigilance, developers, and browser-based EHR access. It is not a drop-in replacement for a primary native EHR workstation; native Epic and older Meditech clients remain Windows-first.
There is no clinical-grade Windows compatibility layer. Running patient-care software under Wine or Proton is a compliance and patient-safety risk, so Windows-dependent apps follow a decision hierarchy instead.
EHR presentation layers keep moving into the browser: Meditech Expanse is web-based, and Epic Hyperdrive wraps a Chromium engine. Built on web technology is not the same as runs in any browser, but as the browser becomes the workstation, securing and standardizing it becomes the real infrastructure problem.
Windows-app decision order
- 1.Web-based and Linux-native applications
- 2.Application publishing from a supported Windows host
- 3.Open-source replacements for general productivity
- 4.Compatibility layers only for low-risk internal tools, never clinical systems
As clinical computing moves to the browser, hardened and reproducible Linux endpoints let organizations reduce licensing dependence and shrink their attack surface, adopted workload by workload.
Cost and security model
Savings from consolidation, not elimination.
- Endpoint OS cost goes away
- Desktops run community Linux or Red Hat with a support subscription, replacing stacked Windows plus VDI licensing.
- Concurrent, not one-to-one
- A shared Windows session-host pool is sized to concurrent use of legacy apps, not one idle desktop per person.
- A shrinking footprint
- As clinical software goes web-native, the Windows farm and its cost curve bend downward year over year.
- A smaller attack surface
- Locked-down, immutable Linux endpoints sidestep much of the Windows-targeted ransomware landscape common in healthcare.
Honest caveats: Volunteered up front: Windows Server and delivery licensing still needs careful sizing, the publishing tier is real engineering, and retraining and Windows-first peripherals (badge readers, label printers, dictation) scope the thesis rather than kill it.
Beyond the platform
Follow-on work built on the same foundation.
Secure PV analyst workstation
View-but-not-copy desktop profile with fapolicyd and audited sessions for pharmacovigilance AI work.
OpenShift Virtualization port
KubeVirt desktops on OpenShift with Operators, Routes, and OpenShift GitOps.
Workspaces vs desktops
The same environment as Dev Spaces and as full VDI, with a written tradeoff analysis.
Continuous compliance
OpenSCAP scans running desktops on a schedule; drift is corrected by redeploying the signed image, not by patching in place, and every correction is logged.
Centralized Linux identity (built)
Built 2026-10-05: Red Hat IdM for users, host-based access, and sudo rules, federated with Keycloak.
Backup and disaster recovery
Built: nightly encrypted, off-host identity backups. Next: desktop VM backups, scheduled restore drills, and documented recovery targets.
Local AI operator (ADR 0011)
Planned: a local model for narrow engineering tasks, such as changelog drafts and drift reports, that can only propose changes as pull requests a person reviews. Design accepted; not built yet.
Packaging contributions
Every dependency RHEL 10 does not ship is a candidate Fedora or EPEL contribution, starting with the Python FHIR libraries (fhirclient, fhir.resources). LocumView-specific builds go to COPR; large services stay as containers.