Files
Jungfraujoch/docs/SECURITY.md
T
leonarski_fandClaude Opus 5 d2f57975e8 Record whether the image is mirrored in Y, and label the .poni orientation
Which way the detector's rows run was decided once, in the module assembly, and
never stated again: not on the wire, not in the file, nowhere a consumer could
read it. mirror_y was consumed inside the DetectorGeometryModular constructor and
discarded. It is now a declared property of the detector setup, carried into the
start message, written to HDF5 under detectorSpecific, and read back. Absence
means true, which is the MX convention and the only thing Jungfraujoch has ever
produced.

Deliberately a boolean and not a corner enum: the assembled image can only be
flipped in Y, so a four-corner value would encode states that cannot occur.

DECTRIS stream2 has no field for this - checked against the specification - so
the key is new rather than an extension of theirs, and a consumer that does not
know it skips it and behaves exactly as before.

The .poni file gains pyFAI's orientation. Without it pyFAI applies its own
default, 3 (bottom left), and believes increasing row means physically upwards.
The numbers still agreed - a mirror preserves 2theta, so radial integration was
never affected - but the azimuth came out with the opposite sense, which matters
for cake and sector integration.

Declaring orientation 2 is not a one-line addition: it re-anchors Poni1 to the
top edge and reverses rot2 and rot3, a row flip being improper. Measured against
pyFAI 2026.5.0 by searching all four orientations, both Poni1 anchorings and all
eight sign combinations: exactly two combinations reproduce the lab position
DiffractionGeometry computes to 1.4e-17 m - the unlabelled form written before,
and (orientation 2, Poni1 = height-1-beam_y, +rot1/+rot2/-rot3), which is now
written. Calibration_PoniFileAxisConvention pins it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-22 22:54:50 +02:00

7.5 KiB

Security

Jungfraujoch is a data-acquisition and analysis system for X-ray detectors, designed to run inside a controlled facility network. This document describes what the software does and does not protect against, the current known limitations, and the authentication work in progress.

Threat model and scope

The security model targets a semi-trusted internal facility network. The concern is a peer on that network reaching a Jungfraujoch service with little or no effort — a mistyped host/port, a curious colleague, a mis-pointed script, a stray browser tab — not a determined attacker and not passive wire capture (which is the responsibility of the network layer: 802.1x, VLANs, facility infrastructure).

The asset that matters most is the confidentiality of live analysis data: the diffraction images and derived metadata (unit cell, resolution, spot counts, sample name) that reveal which sample is being measured. This matters for industrial and proprietary experiments. By contrast, acquisition control (start / stop / configure) is treated as low risk — scientists operate their own experiments and there is little to gain from restricting it.

Security is best-effort: measures that materially impede normal operation get turned off, so the design favours a few high-value, low-friction controls over comprehensive lockdown.

Out of scope. Jungfraujoch is not designed to be exposed to an untrusted network or the public internet. Do not do this.

1. Good practice — what is and is not protected

What you can secure (and should)

These controls work and a deployment should apply them (see also DEPLOYMENT.md):

  • Network isolation. Keep the broker and its data streams on a controlled segment. The broker ↔ writer ↔ receiver traffic should run on a dedicated back-end network, with the data-socket addresses pinned to that interface and the ports firewalled.
  • Reverse proxy for TLS. The broker speaks plain HTTP. To get HTTPS, put a reverse proxy (Apache / nginx) in front that terminates TLS and pin the broker to localhost behind it. The desktop viewer supports https:// endpoints — choose the scheme in the Open HTTP Connection dialog.
  • Filesystem confinement of written data. The writer creates NXmx HDF5 files on shared storage. Confidentiality of that data at rest is enforced by the filesystem: run the writer under a dedicated identity and use directory ownership / ACLs (and setgid) so that only the owning experiment can read its files.
  • Firewall the ZeroMQ ports. The image / preview / metadata / republish streams have no access control of their own (see below), so restrict who can reach those ports at the network layer.

What the software does NOT provide

Be explicit about the gaps so a deployment does not assume protection that is not there:

  • No authentication or authorization in the broker. The HTTP/REST API currently has no login, token, or access control. Anyone who can reach the broker's host and port has full read access (live images, unit cell, resolution, sample metadata) and full write access (start, cancel, reconfigure). Confidentiality currently depends entirely on network/firewall isolation. This is being addressed — see §3.
  • No transport encryption in the broker. The broker serves plain HTTP; there is no built-in TLS. Encryption must be provided by a reverse proxy.
  • No access control or encryption on the ZeroMQ streams. The preview, metadata, image, and republish streams are unauthenticated sockets. Any peer that can connect can subscribe to live data. For the image PUSH stream specifically, an accidental extra consumer does not merely eavesdrop — a PULL peer is load-balanced into the stream and will divert images away from the real writer.
  • No per-user isolation. The broker has no concept of users; it cannot separate one operator's access from another's.
  • No application-level audit trail of who accessed or changed what.
  • Broker and back-end streams on an isolated network; never exposed to a general/untrusted network.
  • ZeroMQ data-socket addresses pinned to the back-end interface; ports firewalled to known peers.
  • TLS terminated by a reverse proxy; broker bound to localhost behind it.
  • Writer run under a dedicated identity; data directories owned / ACL'd per experiment (setgid) so users read only their own data.
  • ZeroMQ compatibility streams (preview / metadata / republish) enabled only if actually consumed, and only on the trusted back-end.

2. Known issues

# Issue Impact Mitigation today
1 Broker HTTP API has no authentication Anyone who can reach it has full read (confidential live data) + write (control) Network / firewall isolation; §3 in progress
2 Broker binds all interfaces, plain HTTP Reachable from anywhere routable; no encryption Expose only on the trusted segment; TLS via reverse proxy
3 ZeroMQ preview / metadata / image / republish streams are unauthenticated and unencrypted Live-data exfiltration; a rogue PULL on the image stream diverts/steals images Firewall the ports; run only on the back-end network
4 Web frontend assumes an open API The bundled UI has no auth and expects to reach an open broker Serve and reach it only on the trusted network

Input robustness. Services parse framed data from peers on the (trusted) data path. Hardening of untrusted-frame handling (size caps, overflow guards) is ongoing; these paths are not intended to face an untrusted network.

3. Work in progress — authenticated read access

The main gap (issue #1) is being closed with a best-effort, low-friction scheme that protects the confidential read endpoints while leaving acquisition control open.

Enabling step (done): viewer HTTP client on libcurl. The desktop viewer's broker client was migrated from a plain-HTTP library to libcurl, which gives it HTTPS plus the ability to authenticate. The build stays self-contained per platform: on Windows, TLS and Kerberos come from the operating system (Schannel + SSPI, no external dependencies); on Linux, from system OpenSSL + Kerberos (GSSAPI / krb5). This is why the Linux build now needs the Kerberos development headers (libkrb5-dev on Debian/Ubuntu, krb5-devel on RHEL/Rocky).

Planned enforcement (not yet implemented). Two complementary options, both gating only the sensitive read endpoints (live images, scan result, preview plots, statistics) and leaving writes open:

  • Per-experiment Bearer token. An optional token supplied at acquisition start (/start); when set, the broker requires it (Authorization: Bearer …) on the read endpoints. No token set → no enforcement (backward compatible). The token is minted externally and handed to the authorised viewer(s); the broker only compares strings. A rotated per-experiment token segments one experiment's data from the next.
  • Kerberos / GSSAPI single sign-on. A pass-through reverse proxy performs Kerberos/SPNEGO authentication (service keytab) and forwards the authenticated user name to a localhost-pinned broker as a trusted header. This gives Active Directory single sign-on with no token to carry, at the cost of a proxy deployment. The viewer's libcurl client can negotiate Kerberos directly against such a proxy.

Neither enforcement path is in the broker yet. Until then, confidentiality relies on the network and filesystem controls in §1.