Security dashboard: per-lab posture audit¶
Murmurent's per-lab security dashboard runs the security_guard agent
periodically against a registered host (a machine you have added to
Murmurent with murmurent host add; typically a shared lab server) and
surfaces permission, hygiene, and policy findings in one screen.
Two tiers, two trust levels:
- Tier 1: unprivileged. Runs as the invoking user over SSH. Walks
POSIX bits on filesystems where they're authoritative (
/home, ext4), reads the user's own~/.ssh/,~/.murmurent/,~/.claude*, dotfiles, crontab, systemd user units, etc. Available without additional setup. - Tier 2: root-owned ACL snapshot. Requires a sysadmin to install a
narrowly-scoped sudoers entry on the target host (see
Tier 2 setup). Reads the storage layer's real ACLs
plus
sshd -Tand lab-wideauthorized_keyssummaries. The dashboard consumes the snapshot if present and reports "ACL details unavailable" rows if absent.
Hard rule (from the global Murmurent data-storage policy): the
security agent never modifies or deletes any file under the lab's
immutable/ or append_only/ data trees, even when its own findings recommend
a fix. All chmod/chown/ACL adjustments in the dashboard are
display-only: the PI runs them by hand after vetting.
Site-specific configuration is kept privately. The concrete server, storage host, mount layout, ACL templates, and authorised operators for a given lab are that lab's own operational record and are not part of this public documentation. Each lab keeps them in its private lab-management repo. This page describes only the general mechanism.
Storage where POSIX bits are not authoritative¶
Many enterprise NAS platforms store native (NTFS-style / NFSv4) ACLs and,
when a directory is exported over NFSv3, can only project those ACLs
as synthesized POSIX bits. Those bits are not authoritative: a
chmod on the v3 mount may not flip the underlying ACE, and the bits you
see don't reflect deny-ACE chains.
The usual remedy is a parallel NFSv4 view restricted to root that
exposes the real ACLs (nfs4_getfacl). Tier 2 reads from that view.
The Tier 1 scanner detects this situation automatically: if
nfs4_getfacl <data_root> reports that the attribute isn't supported,
the scanner skips the POSIX walks of immutable/ and append_only/ (which
would produce nothing but noise) and emits a single info-finding
POSIX-NOT-AUTHORITATIVE-01 pointing the PI at Tier 2.
Local filesystems (a server's own /home on ext4, for example) have
real POSIX ACLs, so the home-dir, ssh-key, and dotfile scanners stay
valid there.
The interpretation of the storage layer's ACL entries and the expected per-directory ACL templates a given lab audits against are lab-specific and are kept in that lab's private lab-management repo, not here.
Rule catalog¶
Every Tier 1 / Tier 2 finding carries a stable rule ID. Use the anchors
below to deep-link from the dashboard rows. <data_root> stands for
the lab's data root.
Which data folders are checked. Both tiers check every governed data
folder that exists. immutable/ must be read-only on disk: a file is saved
there once and not changed afterwards, so the RAW- rules apply to it.
append_only/ and modifiable/ are for the lab group only, so the
REFINED- rules apply to them. During the move to the new names the legacy
raw/ (read-only) and refined/ (lab-shared) are checked too. Each
finding's category is the folder it was found in.
Tier 1: unprivileged scanners¶
Tier 2: root-owned ACL snapshot¶
The Tier 2 audit diffs observed ACLs against the lab's expected templates (kept privately). Rules:
Tier 2: per-core ACL diff (cores)¶
The snapshot script's per-core ACL files are diffed against the same
templates as the lab tree, with CORE--prefixed rule IDs so the
dashboard can group findings per core. Each finding carries the core's
short id in its project field. The category is core_ plus the folder
name, for example core_immutable or core_append_only.
Project-level access checks (lead/PI standing check)¶
A lead/PI-scoped, unprivileged check (issue #95 Phase 4; also the deferred
project-level slice of #63 item 2/3): for every project the viewer leads,
does each project member still have read (and, for the append_only/ tree
and local repo clones, write) access to the project's governed data
directories? Run it with murmurent security project-access; findings persist
to ~/.murmurent/security/local/project-access-<date>.jsonl and surface on this
dashboard alongside the personal-audit rows. Access is evaluated from POSIX
owner/group/other mode bits, refined by the NFSv4 ACL (authoritative) when
nfs4_getfacl output is available. Read-only: stat + ACL parsing only, never
a chmod. On a clinical project a locked-out member escalates from warn to
block.
Member→OS-user mapping: an explicit os_user (or posix_user) key in the
member file's frontmatter takes priority, else the member's official_handle
(institutional netname, which on the shared institutional NFS servers murmurent
targets is the login name). When neither is known the row is unverifiable
(never a false "access ok"), so the PI knows to record the member's server
login.
Tier 2 setup¶
The short way. On the lab server, in an up-to-date murmurent folder, run once:
sudo bash scripts/install_security_snapshot.sh --dry-run # preview; changes nothing
sudo bash scripts/install_security_snapshot.sh # install
It checks the script's fingerprint, installs it at
/opt/murmurent/lab_sec_dump.sh, writes this server's settings to
/etc/default/murmurent, lets you run the script without a password, and
validates the sudo configuration before using it. If the server has an older
install under the project's previous name (/opt/wigamig), it copies the
earlier results across and moves the old pieces into
/var/backups/wigamig_retired_<date>/. Run it again after each update to
the script.
The steps it automates are:
- SSH to the lab server and update the commons clone (
git pull). - Verify the shipped script's SHA256 against the recorded checksum before running anything as root (detects in-flight tampering; a mismatch means STOP, do not install).
- Install the snapshot script root-owned (
install -m 0755 -o root -g root). - Install the sudoers grant (
install -m 0440 -o root -g root), after editing it to list the operators your lab authorises. - Validate the sudoers file with
visudo -c -f ...before trusting it (a bad sudoers file can lock everyone out of sudo). - Smoke-test with
sudo -n <script>: no password should be prompted. - (Recommended) Periodically re-check the installed binary's hash against the source, since anyone with root could later modify it.
After that, the /security dashboard's Run sudo dump button SSHes to
the host, runs the snapshot as root, ships the result back, and merges
Tier 2 findings into the table.
The host, mount paths, ACL templates, snapshot location, and the list of authorised operators are lab-specific and are configured in the script's constants and the sudoers grant on that host. A lab keeps those concrete values in its own private lab-management repo, not here.
What the snapshot writes¶
A per-run directory on the host's local disk (not on a network share,
since root is often not a valid principal on enterprise ACL storage),
readable only by the lab group. It contains a manifest, the immutable/ and
append_only/ ACL dumps, the effective sshd -T config, a per-member SSH
key summary (no key bodies), and an auth summary. The auth summary
records per-user counts of publickey / password / failed auth plus a
distinct-subnet count only (raw IPs are deliberately redacted, since
the file is lab-group readable). The dashboard parses each section
independently: a missing section only suppresses that section's findings.
Retention¶
All snapshots are kept (each is MB-scale). The audit trail lets the PI answer "when did this ACL change?" by diffing two snapshot dates. Prune with a simple cron if storage ever becomes an issue.
When Tier 2 isn't available¶
If the cluster admin can't grant sudo or expose a root-level ACL view,
the dashboard runs in Tier 1 only mode: the Tier 2 rule rows render
with a yellow "?" verdict and an "ACL snapshot unavailable" note.
POSIX-bit scanners on the ACL-backed data mount stay skipped (per
POSIX-NOT-AUTHORITATIVE-01). The dashboard remains useful for /home,
SSH keys, dotfiles, repos, and GitHub visibility.
What the dashboard does not do¶
- It never modifies any file on the target. All suggested fixes are
display-only strings. It specifically never writes under the lab's
immutable/orappend_only/data trees, enforced down to thesecurity_guardagent's own prompt. - It does not audit other labs' trees. Scope is this lab's slice of the host.
- It does not store credentials. No SSH password prompts, no sudo password prompts. Sudo is either NOPASSWD-on-one-script or not available.