agent: read chrony status from tracking.log instead of the command socket
Bench on comet-beacon-54 proved every command-socket route is blocked for the hardened agent: chronyd's unix socket is owner-write-only (0755, so even a chrony-group member can't connect), and STIG closes the UDP command port (cmdport 0). Rather than re-open a port or expose chrony's privileged socket, enable chronyd's tracking log and have the agent READ it — no port, no socket, no group, no SELinux domain transition, full hardening intact. - chrony.conf: enable 'log tracking' (idempotent) so chronyd appends source/stratum/offset to /var/log/chrony/tracking.log. Write volume is a ~130B line per clock update (backing off to ~maxpoll when stable) and capped by the chrony RPM's logrotate — negligible on the RAM overlay. cmdport 0 stays, so no STIG deviation. - agent: chronyTracking() now reads the last data line of tracking.log via parseTrackingLog() (source f[2], stratum f[3], offset f[6], leap/sync f[7]); replaces the chronyc exec + parseChrony. Unit test swapped accordingly. - revert the two abandoned approaches: drop the bindcmdaddress line (394ad10) and the fleet_agent_chronyc SELinux nnp_transition module + provisioner block (e6fd4a2, .te deleted) — no chronyc exec means no transition to allow. Removed stig-deviations #16 and #17 (both waivers no longer needed). Needs a workstation image rebuild + reboot. BENCH-VERIFY: tracking.log is world-readable so the DynamicUser agent can read it; under enforcing unconfined_service_t can read chronyd_var_log_t (add a minimal file-read allow if denied); and the offset sign matches chronyc on a synced host.
This commit is contained in:
@@ -68,16 +68,16 @@ func TestParseUptime(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseChrony(t *testing.T) {
|
||||
out := `Reference ID : C0A8320A (192.168.50.10)
|
||||
Stratum : 3
|
||||
Ref time (UTC) : Fri Jul 10 06:00:00 2026
|
||||
System time : 0.000012345 seconds slow of NTP time
|
||||
Last offset : +0.000001234 seconds
|
||||
Frequency : 12.345 ppm slow
|
||||
Leap status : Normal
|
||||
func TestParseTrackingLog(t *testing.T) {
|
||||
// A realistic tracking.log: banner + header + two data lines. parseTrackingLog
|
||||
// must take the LAST data line, skip banner/header, and read source/stratum/offset.
|
||||
log := `====================================================================
|
||||
Date (UTC) Time IP Address St Freq ppm Skew ppm Offset L Co Offset sd
|
||||
====================================================================
|
||||
2026-07-10 05:59:00 192.168.50.10 3 -1.234 0.100 +0.000002000 N 4 1.0e-07
|
||||
2026-07-10 06:00:00 192.168.50.10 3 -1.250 0.090 -0.000012345 N 4 1.0e-07
|
||||
`
|
||||
c := parseChrony(out)
|
||||
c := parseTrackingLog([]byte(log))
|
||||
if c.state != "synced" {
|
||||
t.Errorf("state = %q, want synced", c.state)
|
||||
}
|
||||
@@ -87,17 +87,18 @@ Leap status : Normal
|
||||
if c.stratum != 3 {
|
||||
t.Errorf("stratum = %d, want 3", c.stratum)
|
||||
}
|
||||
// "slow of NTP time" -> negative offset (sign-sensitive check).
|
||||
// last line's Offset is -0.000012345 (sign-sensitive: must not read the +2e-6 above).
|
||||
if c.offset >= 0 || math.Abs(c.offset+0.000012345) > 1e-9 {
|
||||
t.Errorf("offset = %v, want -0.000012345", c.offset)
|
||||
}
|
||||
// unsynced when Leap status isn't Normal.
|
||||
if c := parseChrony("Leap status : Not synchronised\n"); c.state != "unsynced" {
|
||||
t.Errorf("state = %q, want unsynced", c.state)
|
||||
// unsynchronised reference: L='?' and 0.0.0.0 source.
|
||||
uns := "2026-07-10 06:01:00 0.0.0.0 0 0.000 0.000 +0.000000000 ? 0 0.0e+00\n"
|
||||
if c := parseTrackingLog([]byte(uns)); c.state != "unsynced" || c.source != "" {
|
||||
t.Errorf("unsynced parse = %+v, want state=unsynced source=''", c)
|
||||
}
|
||||
// empty / unavailable.
|
||||
if c := parseChrony(""); c.state != "unsynced" || c.source != "" {
|
||||
t.Errorf("empty parse = %+v", c)
|
||||
// empty / header-only -> zero chrony{}.
|
||||
if c := parseTrackingLog([]byte(" Date (UTC) Time IP Address\n")); c.state != "" {
|
||||
t.Errorf("header-only parse = %+v, want zero", c)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user