feat: machine binding and version enforcement
migration 017 adds machine_id to agents table middleware validates X-Machine-ID header on authed routes agent client sends machine ID with requests MIN_AGENT_VERSION config defaults 0.1.22 version utils added for comparison blocks config copying attacks via hardware fingerprint old agents get 426 upgrade required breaking: <0.1.22 agents rejected
This commit is contained in:
@@ -17,6 +17,7 @@ import (
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/circuitbreaker"
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/client"
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/config"
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/crypto"
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/display"
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/installer"
|
||||
"github.com/Fimeg/RedFlag/aggregator-agent/internal/orchestrator"
|
||||
@@ -348,13 +349,28 @@ func registerAgent(cfg *config.Config, serverURL string) error {
|
||||
}
|
||||
}
|
||||
|
||||
// Get machine ID for binding
|
||||
machineID, err := system.GetMachineID()
|
||||
if err != nil {
|
||||
log.Printf("Warning: Failed to get machine ID: %v", err)
|
||||
machineID = "unknown-" + sysInfo.Hostname
|
||||
}
|
||||
|
||||
// Get embedded public key fingerprint
|
||||
publicKeyFingerprint := system.GetPublicKeyFingerprint()
|
||||
if publicKeyFingerprint == "" {
|
||||
log.Printf("Warning: No embedded public key fingerprint found")
|
||||
}
|
||||
|
||||
req := client.RegisterRequest{
|
||||
Hostname: sysInfo.Hostname,
|
||||
OSType: sysInfo.OSType,
|
||||
OSVersion: sysInfo.OSVersion,
|
||||
OSArchitecture: sysInfo.OSArchitecture,
|
||||
AgentVersion: sysInfo.AgentVersion,
|
||||
Metadata: metadata,
|
||||
Hostname: sysInfo.Hostname,
|
||||
OSType: sysInfo.OSType,
|
||||
OSVersion: sysInfo.OSVersion,
|
||||
OSArchitecture: sysInfo.OSArchitecture,
|
||||
AgentVersion: sysInfo.AgentVersion,
|
||||
MachineID: machineID,
|
||||
PublicKeyFingerprint: publicKeyFingerprint,
|
||||
Metadata: metadata,
|
||||
}
|
||||
|
||||
resp, err := apiClient.Register(req)
|
||||
@@ -376,7 +392,27 @@ func registerAgent(cfg *config.Config, serverURL string) error {
|
||||
}
|
||||
|
||||
// Save configuration
|
||||
return cfg.Save(getConfigPath())
|
||||
if err := cfg.Save(getConfigPath()); err != nil {
|
||||
return fmt.Errorf("failed to save config: %w", err)
|
||||
}
|
||||
|
||||
// Fetch and cache server public key for signature verification
|
||||
log.Println("Fetching server public key for update signature verification...")
|
||||
if err := fetchAndCachePublicKey(cfg.ServerURL); err != nil {
|
||||
log.Printf("Warning: Failed to fetch server public key: %v", err)
|
||||
log.Printf("Agent will not be able to verify update signatures")
|
||||
// Don't fail registration - key can be fetched later
|
||||
} else {
|
||||
log.Println("✓ Server public key cached successfully")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// fetchAndCachePublicKey fetches the server's Ed25519 public key and caches it locally
|
||||
func fetchAndCachePublicKey(serverURL string) error {
|
||||
_, err := crypto.FetchAndCacheServerPublicKey(serverURL)
|
||||
return err
|
||||
}
|
||||
|
||||
// renewTokenIfNeeded handles 401 errors by renewing the agent token using refresh token
|
||||
@@ -694,6 +730,12 @@ func runAgent(cfg *config.Config) error {
|
||||
if err := handleReboot(apiClient, cfg, ackTracker, cmd.ID, cmd.Params); err != nil {
|
||||
log.Printf("[Reboot] Error processing reboot command: %v\n", err)
|
||||
}
|
||||
|
||||
case "update_agent":
|
||||
if err := handleUpdateAgent(apiClient, cfg, ackTracker, cmd.Params, cmd.ID); err != nil {
|
||||
log.Printf("[Update] Error processing agent update command: %v\n", err)
|
||||
}
|
||||
|
||||
default:
|
||||
log.Printf("Unknown command type: %s - reporting as invalid command\n", cmd.Type)
|
||||
// Report invalid command back to server
|
||||
|
||||
Reference in New Issue
Block a user