Skip to content

Build log

Engineering a VDI platform in the open.

LocumView is an open-source virtual desktop platform on RHEL 10. This page documents how it is being built, what has broken along the way, and why each decision was made.

Status · Version one: complete

Updated

Live: 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.

4 of 11 phase groups complete. Each phase has a single, testable definition of done.
  1. 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
  2. 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
  3. 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
  4. 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
  5. 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
  6. Phase 9 litePlanned

    Clinical AI demo (US)

    Done when: The first slice of the US clinical AI module; not part of the EU product (ADR 0008).

    • Planned for the US only, on synthetic data and local models
  7. 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
  8. 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
  9. 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)
  10. 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
  11. Phase 9Planned

    Clinical AI module on synthetic EHR data (US)

    Done when: Designed for the US; not part of the EU product. EU assistants retrieve, summarize, organize, and draft only.

    • Synthea population and hand-built scenarios with expected answers
    • FHIR R4 server (Medplum preferred, HAPI FHIR alternative) in the lab environment
    • Access only through SMART on FHIR OAuth with scoped, revocable tokens
    • Outputs written back as FHIR Communication or Task resources

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

  1. 1Browser
  2. 2Cloudflare (TLS)
  3. 3Cloudflare Tunnel
  4. 4Guacamole
  5. 5guacd
  6. 6RDP
  7. 7RHEL 10 desktop

Only guacd can reach RDP. Nothing on the path listens publicly.

Launch gate

What stands between the internet and a desktop.

The guest demo account is the riskiest surface: a limited-access mirror of the real workspace. It is treated as hostile by design. Items marked next are in progress.

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

A separate module, designed for the US.

The clinical AI pipeline is a separate, detachable module designed for the US under FDA clinical decision support principles, and it is not part of the EU product (ADR 0008). It is described on the US build log. In the EU, LocumView assistants are limited to retrieving, summarizing, organizing, and drafting.

Field findings

What building it taught us.

Phase 1 was deliberately manual, and every surprise became a requirement for the automation that replaces it. The automation now turns up surprises of its own.
Security

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.

Chrome

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.

Provisioning

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.

Signing

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).

Flatpak

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.

DNS

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.

OpenTofu

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.

vTPM

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.

bootc

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

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.

STIG

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.

Firmware

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.

SELinux

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.

TLS

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.

Tooling

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.

Provisioning

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.

The name nods to VMware View, the original name of Horizon, now owned by Omnissa. Each Horizon component has an open, auditable counterpart.
Horizon componentLocumView counterpart
Unified Access GatewayOutbound-only Cloudflare Tunnel
Connection ServerApache Guacamole
Blast / HTML AccessRDP via guacd, in the browser
Identity / MFAKeycloak with TOTP (WebAuthn next)
Instant-clone poolsbootc 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. 1.Web-based and Linux-native applications
  2. 2.Application publishing from a supported Windows host
  3. 3.Open-source replacements for general productivity
  4. 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.

Windows is demoted from a per-seat desktop to a shared, right-sized application service. The savings scale with how much of the workload is web or Linux-native.
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.