Do not raise agent-can-become-root while the first setuid search is still within its bound
After every node-engine restart the account verdict says not judged yet until the engine's first search for setuid programs ends, and DA raised the urgent condition each time. The account stays unconfined and node show still says not judged; the condition is raised once the search fails, runs out its bound, finds a way to root, or the statement goes stale.
This commit is contained in:
@@ -117,6 +117,37 @@ func judgedConfined(agent string, h inventory.NodeHealth, had bool, now time.Tim
|
||||
h.SaidAt.Local().Format("2006-01-02 15:04"))
|
||||
}
|
||||
|
||||
// searchQuietFor is how long a verdict may say its setuid search is still running before that is itself the
|
||||
// urgent condition: the node-engine's bound on one search, and one statement more (a node-engine states its
|
||||
// health at least every five minutes) for the verdict that follows it to be heard.
|
||||
const searchQuietFor = link.RootSearchBound + 5*time.Minute
|
||||
|
||||
// searchStillRunning says the one thing keeping an agent account from being judged is the node-engine's first
|
||||
// search for setuid programs, still within its bound (novox/hq ADR 0266): a fresh statement from an engine that
|
||||
// judges root, holding a verdict on the account, every verdict on it healthy or not judged yet because that
|
||||
// search runs — and none of those for longer than searchQuietFor. A way to root found, a search that failed or
|
||||
// did not finish, any other unknown, a stale statement: false, and DA raises it.
|
||||
func searchStillRunning(agent string, h inventory.NodeHealth, had bool, now time.Time) bool {
|
||||
if !had || now.Sub(h.HeardAt) > verdictFreshFor || h.Contract < link.RootContract {
|
||||
return false
|
||||
}
|
||||
pending := false
|
||||
for _, r := range h.Resources {
|
||||
if r.Kind != link.KindAccount || r.Target != agent || r.Root != link.RootNever {
|
||||
continue
|
||||
}
|
||||
switch {
|
||||
case r.State == link.StateHealthy:
|
||||
case r.State == link.StateUnknown && strings.HasPrefix(r.Reason, link.ReasonRootPending) &&
|
||||
!r.Since.IsZero() && now.Sub(r.Since) <= searchQuietFor:
|
||||
pending = true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return pending
|
||||
}
|
||||
|
||||
// probeAgentAccounts is DA: every machine that names an agent account has it judged, on its node-engine's
|
||||
// newest statement, unable to become root without a person (ADR 0266).
|
||||
func probeAgentAccounts(ctx context.Context, d *doctor) ([]conditions.Observation, error) {
|
||||
@@ -134,10 +165,18 @@ func probeAgentAccounts(ctx context.Context, d *doctor) ([]conditions.Observatio
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
confined, why := judgedConfined(n.AgentAccount, h, had, time.Now())
|
||||
now := time.Now()
|
||||
confined, why := judgedConfined(n.AgentAccount, h, had, now)
|
||||
if confined {
|
||||
continue
|
||||
}
|
||||
// Not judged yet only because the first search since the node-engine started is still running: not the
|
||||
// urgent condition after every restart. The agent is still not confined — ADR 0259's router reads
|
||||
// agentConfined, not this — and `node show` still says not judged. Loud again once the search fails,
|
||||
// runs out its bound, or the statement goes stale.
|
||||
if searchStillRunning(n.AgentAccount, h, had, now) {
|
||||
continue
|
||||
}
|
||||
out = append(out, conditions.Observation{Scope: conditions.ScopeMachine, ID: n.Name, Token: "agent-root",
|
||||
Machine: n.Name, Severity: conditions.Urgent,
|
||||
Summary: fmt.Sprintf("on %s, %s (ADR 0266): an agent there may become root without a person, and "+
|
||||
|
||||
Reference in New Issue
Block a user