Skip to content

v1.8.0 — what your nodes actually run

Choose a tag to compare

@eth-man eth-man released this 18 Aug 12:19
· 24 commits to main since this release
783f455

The console can say what a node does get, not only what it should.

Classification has always described intent thoroughly — every class on a node, which group set it, why that group matched. The catalog is the result, and nothing read it. So "is /etc/ssh/sshd_config the same on all 190 servers?" had no answer here.

That is not a lookup. It is a consistency question, and configuration management exists to make an estate uniform.

Added

Estate-wide resource search

A new Resources page, peer to Nodes. Results group by resource and lead with variance:

⚠  File[/etc/ssh/sshd_config]   production   12 nodes   2 variants
✓  File[/etc/motd]              production   12 nodes   1 variant

Disagreements sort to the top. A flat list of 190 identical rows hides the three that differ, which is the opposite of what an operator opened the screen to find.

Variance without fetching a single parameter

PuppetDB's resource field is a SHA-1 over type, title and parameters, so identical hashes mean byte-identical parameters. The list query uses extract to omit parameters outright — a value never fetched cannot leak through a rendering bug, a log line, an error page or a screenshot.

Counted within an environment, never across it

A development node and a production node legitimately differ. Counting that as drift would flag a two-environment estate as entirely inconsistent on day one, and an alert that cries wolf gets muted — taking the one that mattered with it.

Expand to see who, compare to see what

Expanding a row names which nodes carry which configuration. Comparing parameters fetches one representative per variant and diffs them:

−  app18.nexuspuppet.test     +  cache35.nexuspuppet.test
   # managed by puppet
−  PermitRootLogin no
+  PermitRootLogin yes

Multi-line values get a line diff with unchanged bulk collapsed, so a 200-line config file shows the stanza that changed rather than two columns to compare by eye.

Composes with fact filtering

"File[/etc/resolv.conf] on Ubuntu 22.04 nodes" is one query, reusing the inventory subquery from v1.7.7. Filtering by parameter value is supported too — "every node where sshd_config permits root login" — which needs no parameter to be displayed.

resources:read, a new and privileged permission

Deliberately not inventory:read. Facts describe a machine; resource parameters are its configuration payload — a File's content is the whole file body, and a class parameter may hold a credential.

Read-only audit events

Expanding parameters, and any query filtering on a parameter value, write an AuditLog row. Ordinary browsing does not — burying the events that matter under thousands that do not is how a trail stops being read.

The row is written before the read, so a crash cannot lose the evidence while keeping the disclosure. And it records the question, never the answer: no parameter value is ever written into the audit log, because that would copy the estate's secrets into a table that gets forwarded off-box.

Upgrading

One migration, admin_resources_read. No configuration changes.

Every existing ADMIN gains the ability to read managed file contents. The migration grants resources:read to the built-in ADMIN role. It is granted because otherwise nobody could hold it: creating a custom role answers 501 without the enterprise layer, so leaving it unheld would make the feature unreachable in every core deployment rather than merely restricted. VIEWER and OPERATOR are unaffected.

A deployment that needs "an admin who manages users but must not read file contents" needs the enterprise layer to express it, by granting the permission to a custom role and narrowing ADMIN.

AuditLog consumers must tolerate null before and after. Read events have neither. This is visible on the wire, including to syslog and webhook forwarding.

A note on how this was built

Every slice shipped with a defect that only a real environment found, and CI was green on all of them: a lowercase resource type answering 500 instead of 400; built-in role defaults living in three places rather than two; a screen that could report drift but never name the machine; and a parameter comparison that pushed one node's column off-screen entirely.

The last was found by copying the table and pasting it, revealing a value that had never been on screen. The API, the audit rows, the diff logic and the built bundle had all passed.

Full changelog: v1.7.7...v1.8.0