refactor: replace 899 lines of script generation with templates
Created InstallTemplateService with clean template-based script generation. Added linux.sh.tmpl and windows.ps1.tmpl for install scripts. Removed massive generateLinuxScript and generateWindowsScript functions. Downloads handler now uses template service (1073 lines → 174 lines). Templates easily maintainable without modifying Go code.
This commit is contained in:
@@ -636,14 +636,17 @@ func runAgent(cfg *config.Config) error {
|
|||||||
|
|
||||||
apiClient := client.NewClient(cfg.ServerURL, cfg.Token)
|
apiClient := client.NewClient(cfg.ServerURL, cfg.Token)
|
||||||
|
|
||||||
// Initialize scanners
|
// Initialize scanners for package updates (used by update orchestrator)
|
||||||
aptScanner := scanner.NewAPTScanner()
|
aptScanner := scanner.NewAPTScanner()
|
||||||
dnfScanner := scanner.NewDNFScanner()
|
dnfScanner := scanner.NewDNFScanner()
|
||||||
dockerScanner, _ := scanner.NewDockerScanner()
|
|
||||||
windowsUpdateScanner := scanner.NewWindowsUpdateScanner()
|
windowsUpdateScanner := scanner.NewWindowsUpdateScanner()
|
||||||
wingetScanner := scanner.NewWingetScanner()
|
wingetScanner := scanner.NewWingetScanner()
|
||||||
|
|
||||||
// Initialize circuit breakers for each subsystem
|
// Docker, Storage, and System scanners are created by individual subsystem handlers
|
||||||
|
// dockerScanner is created in handleScanDocker
|
||||||
|
// storageScanner and systemScanner are created in main for individual handlers
|
||||||
|
|
||||||
|
// Initialize circuit breakers for update scanners only
|
||||||
aptCB := circuitbreaker.New("APT", circuitbreaker.Config{
|
aptCB := circuitbreaker.New("APT", circuitbreaker.Config{
|
||||||
FailureThreshold: cfg.Subsystems.APT.CircuitBreaker.FailureThreshold,
|
FailureThreshold: cfg.Subsystems.APT.CircuitBreaker.FailureThreshold,
|
||||||
FailureWindow: cfg.Subsystems.APT.CircuitBreaker.FailureWindow,
|
FailureWindow: cfg.Subsystems.APT.CircuitBreaker.FailureWindow,
|
||||||
@@ -656,12 +659,6 @@ func runAgent(cfg *config.Config) error {
|
|||||||
OpenDuration: cfg.Subsystems.DNF.CircuitBreaker.OpenDuration,
|
OpenDuration: cfg.Subsystems.DNF.CircuitBreaker.OpenDuration,
|
||||||
HalfOpenAttempts: cfg.Subsystems.DNF.CircuitBreaker.HalfOpenAttempts,
|
HalfOpenAttempts: cfg.Subsystems.DNF.CircuitBreaker.HalfOpenAttempts,
|
||||||
})
|
})
|
||||||
dockerCB := circuitbreaker.New("Docker", circuitbreaker.Config{
|
|
||||||
FailureThreshold: cfg.Subsystems.Docker.CircuitBreaker.FailureThreshold,
|
|
||||||
FailureWindow: cfg.Subsystems.Docker.CircuitBreaker.FailureWindow,
|
|
||||||
OpenDuration: cfg.Subsystems.Docker.CircuitBreaker.OpenDuration,
|
|
||||||
HalfOpenAttempts: cfg.Subsystems.Docker.CircuitBreaker.HalfOpenAttempts,
|
|
||||||
})
|
|
||||||
windowsCB := circuitbreaker.New("Windows Update", circuitbreaker.Config{
|
windowsCB := circuitbreaker.New("Windows Update", circuitbreaker.Config{
|
||||||
FailureThreshold: cfg.Subsystems.Windows.CircuitBreaker.FailureThreshold,
|
FailureThreshold: cfg.Subsystems.Windows.CircuitBreaker.FailureThreshold,
|
||||||
FailureWindow: cfg.Subsystems.Windows.CircuitBreaker.FailureWindow,
|
FailureWindow: cfg.Subsystems.Windows.CircuitBreaker.FailureWindow,
|
||||||
@@ -678,33 +675,17 @@ func runAgent(cfg *config.Config) error {
|
|||||||
// Initialize scanner orchestrator for parallel execution and granular subsystem management
|
// Initialize scanner orchestrator for parallel execution and granular subsystem management
|
||||||
scanOrchestrator := orchestrator.NewOrchestrator()
|
scanOrchestrator := orchestrator.NewOrchestrator()
|
||||||
|
|
||||||
// Register update scanners
|
// Register update scanners ONLY - package management systems
|
||||||
scanOrchestrator.RegisterScanner("apt", orchestrator.NewAPTScannerWrapper(aptScanner), aptCB, cfg.Subsystems.APT.Timeout, cfg.Subsystems.APT.Enabled)
|
scanOrchestrator.RegisterScanner("apt", orchestrator.NewAPTScannerWrapper(aptScanner), aptCB, cfg.Subsystems.APT.Timeout, cfg.Subsystems.APT.Enabled)
|
||||||
scanOrchestrator.RegisterScanner("dnf", orchestrator.NewDNFScannerWrapper(dnfScanner), dnfCB, cfg.Subsystems.DNF.Timeout, cfg.Subsystems.DNF.Enabled)
|
scanOrchestrator.RegisterScanner("dnf", orchestrator.NewDNFScannerWrapper(dnfScanner), dnfCB, cfg.Subsystems.DNF.Timeout, cfg.Subsystems.DNF.Enabled)
|
||||||
scanOrchestrator.RegisterScanner("docker", orchestrator.NewDockerScannerWrapper(dockerScanner), dockerCB, cfg.Subsystems.Docker.Timeout, cfg.Subsystems.Docker.Enabled)
|
|
||||||
scanOrchestrator.RegisterScanner("windows", orchestrator.NewWindowsUpdateScannerWrapper(windowsUpdateScanner), windowsCB, cfg.Subsystems.Windows.Timeout, cfg.Subsystems.Windows.Enabled)
|
scanOrchestrator.RegisterScanner("windows", orchestrator.NewWindowsUpdateScannerWrapper(windowsUpdateScanner), windowsCB, cfg.Subsystems.Windows.Timeout, cfg.Subsystems.Windows.Enabled)
|
||||||
scanOrchestrator.RegisterScanner("winget", orchestrator.NewWingetScannerWrapper(wingetScanner), wingetCB, cfg.Subsystems.Winget.Timeout, cfg.Subsystems.Winget.Enabled)
|
scanOrchestrator.RegisterScanner("winget", orchestrator.NewWingetScannerWrapper(wingetScanner), wingetCB, cfg.Subsystems.Winget.Timeout, cfg.Subsystems.Winget.Enabled)
|
||||||
|
|
||||||
// Register storage and system scanners
|
// NOTE: Docker, Storage, and System scanners are NOT registered with the update orchestrator
|
||||||
storageScanner := orchestrator.NewStorageScanner(AgentVersion)
|
// They have their own dedicated handlers and endpoints:
|
||||||
systemScanner := orchestrator.NewSystemScanner(AgentVersion)
|
// - Docker: handleScanDocker → ReportDockerImages()
|
||||||
|
// - Storage: handleScanStorage → ReportMetrics()
|
||||||
// Storage and system scanners don't need circuit breakers (always available, fast operations)
|
// - System: handleScanSystem → ReportMetrics()
|
||||||
storageCB := circuitbreaker.New("Storage", circuitbreaker.Config{
|
|
||||||
FailureThreshold: 5,
|
|
||||||
FailureWindow: 10 * time.Minute,
|
|
||||||
OpenDuration: 5 * time.Minute,
|
|
||||||
HalfOpenAttempts: 1,
|
|
||||||
})
|
|
||||||
systemCB := circuitbreaker.New("System", circuitbreaker.Config{
|
|
||||||
FailureThreshold: 5,
|
|
||||||
FailureWindow: 10 * time.Minute,
|
|
||||||
OpenDuration: 5 * time.Minute,
|
|
||||||
HalfOpenAttempts: 1,
|
|
||||||
})
|
|
||||||
|
|
||||||
scanOrchestrator.RegisterScanner("storage", storageScanner, storageCB, 30*time.Second, cfg.Subsystems.Storage.Enabled)
|
|
||||||
scanOrchestrator.RegisterScanner("system", systemScanner, systemCB, 30*time.Second, true) // System scanner always enabled
|
|
||||||
|
|
||||||
// Initialize acknowledgment tracker for command result reliability
|
// Initialize acknowledgment tracker for command result reliability
|
||||||
ackTracker := acknowledgment.NewTracker(getStatePath())
|
ackTracker := acknowledgment.NewTracker(getStatePath())
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/Fimeg/RedFlag/aggregator-server/internal/config"
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/config"
|
||||||
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/services"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -15,12 +16,14 @@ import (
|
|||||||
type DownloadHandler struct {
|
type DownloadHandler struct {
|
||||||
agentDir string
|
agentDir string
|
||||||
config *config.Config
|
config *config.Config
|
||||||
|
installTemplateService *services.InstallTemplateService
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDownloadHandler(agentDir string, cfg *config.Config) *DownloadHandler {
|
func NewDownloadHandler(agentDir string, cfg *config.Config) *DownloadHandler {
|
||||||
return &DownloadHandler{
|
return &DownloadHandler{
|
||||||
agentDir: agentDir,
|
agentDir: agentDir,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
|
installTemplateService: services.NewInstallTemplateService(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -154,918 +157,18 @@ func (h *DownloadHandler) InstallScript(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (h *DownloadHandler) generateInstallScript(platform, baseURL string) string {
|
func (h *DownloadHandler) generateInstallScript(platform, baseURL string) string {
|
||||||
switch platform {
|
// Use template service to generate install scripts
|
||||||
case "linux":
|
// For generic downloads, use placeholder values
|
||||||
return h.generateLinuxScript(baseURL)
|
script, err := h.installTemplateService.RenderInstallScriptFromBuild(
|
||||||
case "windows":
|
"<AGENT_ID>", // Will be generated during install
|
||||||
return h.generateWindowsScript(baseURL)
|
platform, // Platform (linux/windows)
|
||||||
default:
|
"latest", // Version
|
||||||
return "# Unsupported platform: " + platform
|
fmt.Sprintf("%s/downloads/%s", baseURL, platform), // Binary URL
|
||||||
|
fmt.Sprintf("%s/api/v1/config/<AGENT_ID>", baseURL), // Config URL (placeholder)
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Sprintf("# Error generating install script: %v", err)
|
||||||
}
|
}
|
||||||
|
return script
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *DownloadHandler) generateLinuxScript(baseURL string) string {
|
|
||||||
return fmt.Sprintf(`#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# RedFlag Agent Smart Installer
|
|
||||||
# Uses the sophisticated build orchestrator and migration system
|
|
||||||
|
|
||||||
REDFLAG_SERVER="%s"
|
|
||||||
AGENT_USER="redflag-agent"
|
|
||||||
AGENT_HOME="/var/lib/redflag-agent"
|
|
||||||
AGENT_BINARY="/usr/local/bin/redflag-agent"
|
|
||||||
SUDOERS_FILE="/etc/sudoers.d/redflag-agent"
|
|
||||||
SERVICE_FILE="/etc/systemd/system/redflag-agent.service"
|
|
||||||
CONFIG_DIR="/etc/redflag"
|
|
||||||
STATE_DIR="/var/lib/redflag"
|
|
||||||
OLD_CONFIG_DIR="/etc/aggregator"
|
|
||||||
OLD_STATE_DIR="/var/lib/aggregator"
|
|
||||||
|
|
||||||
# Colors for output
|
|
||||||
RED='\033[0;31m'
|
|
||||||
GREEN='\033[0;32m'
|
|
||||||
YELLOW='\033[1;33m'
|
|
||||||
BLUE='\033[0;34m'
|
|
||||||
NC='\033[0m' # No Color
|
|
||||||
|
|
||||||
echo -e "${BLUE}=== RedFlag Agent Smart Installer ===${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Check if running as root
|
|
||||||
if [ "$EUID" -ne 0 ]; then
|
|
||||||
echo -e "${RED}ERROR: This script must be run as root (use sudo)${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Get registration token from first argument
|
|
||||||
REGISTRATION_TOKEN="$1"
|
|
||||||
if [ -z "$REGISTRATION_TOKEN" ]; then
|
|
||||||
echo -e "${RED}ERROR: Registration token is required${NC}"
|
|
||||||
echo -e "${YELLOW}Usage: curl -sL ${REDFLAG_SERVER}/api/v1/install/linux | sudo bash -s -- YOUR_REGISTRATION_TOKEN${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${BLUE}Registration token: ${GREEN}${REGISTRATION_TOKEN:0:8}...${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Detect architecture
|
|
||||||
ARCH=$(uname -m)
|
|
||||||
case "$ARCH" in
|
|
||||||
x86_64)
|
|
||||||
DOWNLOAD_ARCH="amd64"
|
|
||||||
;;
|
|
||||||
aarch64|arm64)
|
|
||||||
DOWNLOAD_ARCH="arm64"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo -e "${RED}ERROR: Unsupported architecture: $ARCH${NC}"
|
|
||||||
echo -e "${YELLOW}Supported: x86_64 (amd64), aarch64 (arm64)${NC}"
|
|
||||||
exit 1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo -e "${BLUE}Detected architecture: $ARCH (using linux-$DOWNLOAD_ARCH)${NC}"
|
|
||||||
echo ""
|
|
||||||
|
|
||||||
# Function to detect existing installation using our sophisticated system
|
|
||||||
detect_existing_agent() {
|
|
||||||
echo -e "${YELLOW}Detecting existing RedFlag agent installation...${NC}"
|
|
||||||
|
|
||||||
# DEBUGGING: Start comprehensive debugging trace
|
|
||||||
echo "=== DEBUGGING: detect_existing_agent() ==="
|
|
||||||
echo "DEBUG: Starting detection process..."
|
|
||||||
|
|
||||||
# Check for config files in both new and old locations
|
|
||||||
echo "DEBUG: Checking for config files in all locations..."
|
|
||||||
|
|
||||||
# Check new location first
|
|
||||||
echo "DEBUG: Checking new config file: /etc/redflag/config.json"
|
|
||||||
if [ -f "/etc/redflag/config.json" ]; then
|
|
||||||
echo "DEBUG: New config file exists!"
|
|
||||||
CONFIG_FILE="/etc/redflag/config.json"
|
|
||||||
CONFIG_LOCATION="new"
|
|
||||||
else
|
|
||||||
echo "DEBUG: New config file does not exist, checking legacy location..."
|
|
||||||
|
|
||||||
# Check old location
|
|
||||||
if [ -f "/etc/aggregator/config.json" ]; then
|
|
||||||
echo "DEBUG: Found legacy config file: /etc/aggregator/config.json"
|
|
||||||
CONFIG_FILE="/etc/aggregator/config.json"
|
|
||||||
CONFIG_LOCATION="old"
|
|
||||||
else
|
|
||||||
echo "DEBUG: No config file found in either location"
|
|
||||||
CONFIG_FILE=""
|
|
||||||
CONFIG_LOCATION="none"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# If we found a config file, try to extract agent_id (using single reliable method)
|
|
||||||
if [ -n "$CONFIG_FILE" ]; then
|
|
||||||
echo "DEBUG: Processing config file: $CONFIG_FILE (location: $CONFIG_LOCATION)"
|
|
||||||
|
|
||||||
# Check file permissions
|
|
||||||
echo "DEBUG: File permissions:"
|
|
||||||
ls -la "$CONFIG_FILE"
|
|
||||||
|
|
||||||
# Check file ownership
|
|
||||||
echo "DEBUG: File ownership:"
|
|
||||||
stat -c "%U:%G" "$CONFIG_FILE"
|
|
||||||
|
|
||||||
# Try reading file content
|
|
||||||
echo "DEBUG: Attempting to read file content..."
|
|
||||||
echo "DEBUG: Method 1 - Direct cat:"
|
|
||||||
if sudo cat "$CONFIG_FILE" 2>/dev/null; then
|
|
||||||
echo "DEBUG: Direct cat successful"
|
|
||||||
else
|
|
||||||
echo "DEBUG: Direct cat failed"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract agent_id using single reliable method
|
|
||||||
echo "DEBUG: Extracting agent_id with grep:"
|
|
||||||
agent_id=$(grep -o '"agent_id": *"[^"]*"' "$CONFIG_FILE" 2>/dev/null | cut -d'"' -f4)
|
|
||||||
echo "DEBUG: Extracted agent_id: '$agent_id'"
|
|
||||||
|
|
||||||
# Check if agent_id looks valid (UUID format)
|
|
||||||
if [ -n "$agent_id" ]; then
|
|
||||||
if echo "$agent_id" | grep -qE '^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$'; then
|
|
||||||
echo "DEBUG: Agent ID appears to be valid UUID format"
|
|
||||||
else
|
|
||||||
echo "DEBUG: Agent ID does not appear to be valid UUID format"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "DEBUG: Agent ID is empty or null"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Note if migration is needed
|
|
||||||
if [ "$CONFIG_LOCATION" = "old" ]; then
|
|
||||||
echo "DEBUG: *** MIGRATION REQUIRED - Config found in legacy location ***"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "DEBUG: No config files found, checking directories..."
|
|
||||||
|
|
||||||
# Check if directories exist for debugging
|
|
||||||
for dir_path in "/etc/redflag" "/etc/aggregator" "/var/lib/redflag" "/var/lib/aggregator"; do
|
|
||||||
if [ -d "$dir_path" ]; then
|
|
||||||
echo "DEBUG: Found directory: $dir_path"
|
|
||||||
echo "DEBUG: Directory contents:"
|
|
||||||
ls -la "$dir_path/" 2>/dev/null || echo "DEBUG: Cannot list contents (permissions?)"
|
|
||||||
else
|
|
||||||
echo "DEBUG: Directory does not exist: $dir_path"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if systemd service exists
|
|
||||||
echo "DEBUG: Checking systemd service..."
|
|
||||||
if systemctl list-unit-files | grep -q "redflag-agent.service"; then
|
|
||||||
echo "DEBUG: Systemd service file exists"
|
|
||||||
|
|
||||||
# Check service status
|
|
||||||
echo "DEBUG: Service status:"
|
|
||||||
systemctl status redflag-agent --no-pager -l || echo "DEBUG: Could not get service status"
|
|
||||||
|
|
||||||
# Check if service is enabled
|
|
||||||
if systemctl is-enabled --quiet redflag-agent 2>/dev/null; then
|
|
||||||
echo "DEBUG: Service is enabled"
|
|
||||||
else
|
|
||||||
echo "DEBUG: Service is not enabled"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if service is active
|
|
||||||
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
||||||
echo "DEBUG: Service is active"
|
|
||||||
else
|
|
||||||
echo "DEBUG: Service is not active"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "DEBUG: Systemd service file does not exist"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check if binary exists
|
|
||||||
echo "DEBUG: Checking for agent binary..."
|
|
||||||
for binary_path in "/usr/local/bin/redflag-agent" "/usr/bin/redflag-agent" "/opt/redflag-agent/bin/redflag-agent"; do
|
|
||||||
if [ -f "$binary_path" ]; then
|
|
||||||
echo "DEBUG: Found agent binary at: $binary_path"
|
|
||||||
echo "DEBUG: Binary permissions:"
|
|
||||||
ls -la "$binary_path"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Test server connectivity
|
|
||||||
echo "DEBUG: Testing server connectivity..."
|
|
||||||
echo "DEBUG: Server URL: ${REDFLAG_SERVER}"
|
|
||||||
|
|
||||||
# Test basic connectivity
|
|
||||||
echo "DEBUG: Testing basic HTTP connectivity..."
|
|
||||||
if curl -s --connect-timeout 5 "${REDFLAG_SERVER}/api/v1/health" >/dev/null 2>&1; then
|
|
||||||
echo "DEBUG: Server connectivity test successful"
|
|
||||||
else
|
|
||||||
echo "DEBUG: Server connectivity test failed"
|
|
||||||
echo "DEBUG: curl exit code: $?"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Call detection API with debugging
|
|
||||||
echo "DEBUG: Calling detection API..."
|
|
||||||
echo "DEBUG: URL: ${REDFLAG_SERVER}/api/v1/build/detect"
|
|
||||||
echo "DEBUG: Payload: {\"agent_id\": \"${agent_id}\"}"
|
|
||||||
|
|
||||||
DETECTION_RESPONSE=$(curl -s -X POST "${REDFLAG_SERVER}/api/v1/build/detect" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"agent_id": "'"$agent_id"'"}' 2>/dev/null)
|
|
||||||
|
|
||||||
echo "DEBUG: curl exit code: $?"
|
|
||||||
echo "DEBUG: Detection response: '$DETECTION_RESPONSE'"
|
|
||||||
|
|
||||||
if [ $? -eq 0 ] && [ -n "$DETECTION_RESPONSE" ]; then
|
|
||||||
echo "DEBUG: Successfully received detection response"
|
|
||||||
|
|
||||||
# Parse JSON response with debugging
|
|
||||||
echo "DEBUG: Parsing detection response..."
|
|
||||||
|
|
||||||
HAS_AGENT=$(echo "$DETECTION_RESPONSE" | grep -o '"has_existing_agent":[^,]*' | cut -d':' -f2 | tr -d ' ')
|
|
||||||
echo "DEBUG: Extracted has_existing_agent: '$HAS_AGENT'"
|
|
||||||
|
|
||||||
AGENT_ID=$(echo "$DETECTION_RESPONSE" | grep -o '"agent_id":"[^"]*"' | cut -d'"' -f4)
|
|
||||||
echo "DEBUG: Extracted agent_id from response: '$AGENT_ID'"
|
|
||||||
|
|
||||||
REQUIRES_MIGRATION=$(echo "$DETECTION_RESPONSE" | grep -o '"requires_migration":[^,]*' | cut -d':' -f2 | tr -d ' ')
|
|
||||||
echo "DEBUG: Extracted requires_migration: '$REQUIRES_MIGRATION'"
|
|
||||||
|
|
||||||
CURRENT_VERSION=$(echo "$DETECTION_RESPONSE" | grep -o '"current_version":"[^"]*"' | cut -d'"' -f4)
|
|
||||||
echo "DEBUG: Extracted current_version: '$CURRENT_VERSION'"
|
|
||||||
|
|
||||||
# Check conditions for successful detection
|
|
||||||
if [ "$HAS_AGENT" = "true" ] && [ -n "$AGENT_ID" ]; then
|
|
||||||
echo "DEBUG: Detection SUCCESS - existing agent found"
|
|
||||||
echo -e "${GREEN}✓ Existing agent detected: ${AGENT_ID}${NC}"
|
|
||||||
echo -e "${BLUE} Current version: ${CURRENT_VERSION}${NC}"
|
|
||||||
if [ "$REQUIRES_MIGRATION" = "true" ]; then
|
|
||||||
echo -e "${YELLOW}⚠ Migration will be performed during upgrade${NC}"
|
|
||||||
fi
|
|
||||||
echo "=== END DEBUGGING: detect_existing_agent() ==="
|
|
||||||
return 0 # Upgrade path
|
|
||||||
else
|
|
||||||
echo "DEBUG: Detection indicates no existing agent"
|
|
||||||
echo "DEBUG: has_existing_agent: '$HAS_AGENT'"
|
|
||||||
echo "DEBUG: agent_id from response: '$AGENT_ID'"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "DEBUG: Detection API call failed or returned empty response"
|
|
||||||
echo "DEBUG: curl exit code: $?"
|
|
||||||
echo "DEBUG: response length: ${#DETECTION_RESPONSE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "DEBUG: Returning new installation path"
|
|
||||||
echo -e "${GREEN}✓ No existing agent detected - performing new installation${NC}"
|
|
||||||
echo "=== END DEBUGGING: detect_existing_agent() ==="
|
|
||||||
return 1 # New installation path
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to perform migration from old paths
|
|
||||||
perform_migration() {
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}=== Migration Required ===${NC}"
|
|
||||||
|
|
||||||
# Create backup directories with timestamp
|
|
||||||
BACKUP_TIMESTAMP=$(date +%%Y%%m%%d_%%H%%M%%S)
|
|
||||||
OLD_CONFIG_BACKUP="${OLD_CONFIG_DIR}.backup.${BACKUP_TIMESTAMP}"
|
|
||||||
OLD_STATE_BACKUP="${OLD_STATE_DIR}.backup.${BACKUP_TIMESTAMP}"
|
|
||||||
|
|
||||||
# Backup old directories if they exist
|
|
||||||
if [ -d "$OLD_CONFIG_DIR" ]; then
|
|
||||||
echo -e "${YELLOW}Backing up old configuration: ${OLD_CONFIG_DIR} -> ${OLD_CONFIG_BACKUP}${NC}"
|
|
||||||
mv "$OLD_CONFIG_DIR" "$OLD_CONFIG_BACKUP"
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -d "$OLD_STATE_DIR" ]; then
|
|
||||||
echo -e "${YELLOW}Backing up old state: ${OLD_STATE_DIR} -> ${OLD_STATE_BACKUP}${NC}"
|
|
||||||
mv "$OLD_STATE_DIR" "$OLD_STATE_BACKUP"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Migrate configuration data if backup exists
|
|
||||||
if [ -d "$OLD_CONFIG_BACKUP" ]; then
|
|
||||||
echo -e "${YELLOW}Migrating configuration data to new location...${NC}"
|
|
||||||
mkdir -p "$CONFIG_DIR"
|
|
||||||
|
|
||||||
# Copy config files, preserving permissions when possible
|
|
||||||
cp -r "$OLD_CONFIG_BACKUP"/* "$CONFIG_DIR/" 2>/dev/null || true
|
|
||||||
|
|
||||||
# Set proper ownership for new location
|
|
||||||
chown -R "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR" 2>/dev/null || true
|
|
||||||
chmod 755 "$CONFIG_DIR" 2>/dev/null || true
|
|
||||||
|
|
||||||
# Ensure config file has correct permissions
|
|
||||||
if [ -f "$CONFIG_DIR/config.json" ]; then
|
|
||||||
chmod 600 "$CONFIG_DIR/config.json" 2>/dev/null || true
|
|
||||||
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR/config.json" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Migrate state data if backup exists
|
|
||||||
if [ -d "$OLD_STATE_BACKUP" ]; then
|
|
||||||
echo -e "${YELLOW}Migrating state data to new location...${NC}"
|
|
||||||
mkdir -p "$STATE_DIR"
|
|
||||||
cp -r "$OLD_STATE_BACKUP"/* "$STATE_DIR/" 2>/dev/null || true
|
|
||||||
chown -R "$AGENT_USER:$AGENT_USER" "$STATE_DIR" 2>/dev/null || true
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Migrate secrets to Docker secrets if available
|
|
||||||
migrate_secrets_to_docker
|
|
||||||
|
|
||||||
echo -e "${GREEN}✓ Migration completed${NC}"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to migrate secrets from filesystem to Docker secrets
|
|
||||||
migrate_secrets_to_docker() {
|
|
||||||
echo -e "${YELLOW}Checking for secrets migration...${NC}"
|
|
||||||
|
|
||||||
# Look for potential secret files in old locations
|
|
||||||
local secrets_found=false
|
|
||||||
|
|
||||||
# Check for common secret file patterns
|
|
||||||
for secret_pattern in "agent.key" "private_key" "secrets.json" ".env" "credentials.json"; do
|
|
||||||
if [ -f "$OLD_CONFIG_BACKUP/$secret_pattern" ] || [ -f "$OLD_STATE_BACKUP/$secret_pattern" ]; then
|
|
||||||
echo -e "${YELLOW}Found potential secret file: $secret_pattern${NC}"
|
|
||||||
secrets_found=true
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check for agent private keys or certificates
|
|
||||||
for key_path in "$OLD_CONFIG_BACKUP" "$OLD_STATE_BACKUP"; do
|
|
||||||
if [ -d "$key_path" ]; then
|
|
||||||
# Look for key files
|
|
||||||
find "$key_path" -type f \( -name "*.key" -o -name "*.pem" -o -name "*.crt" -o -name "id_*" \) 2>/dev/null | while read -r key_file; do
|
|
||||||
echo -e "${YELLOW}Found key file: $(basename "$key_file")${NC}"
|
|
||||||
secrets_found=true
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$secrets_found" = true ]; then
|
|
||||||
echo -e "${BLUE}Secrets migration available${NC}"
|
|
||||||
echo -e "${YELLOW}Note: Secrets will be migrated to Docker secrets when the agent starts${NC}"
|
|
||||||
echo -e "${YELLOW}The agent will automatically detect and migrate filesystem secrets to Docker storage${NC}"
|
|
||||||
|
|
||||||
# Create a migration marker for the agent to find
|
|
||||||
mkdir -p "$CONFIG_DIR"
|
|
||||||
echo '{"secrets_migration_required": true, "migration_timestamp": "'$(date -Iseconds)'"}' > "$CONFIG_DIR/secrets_migration.json"
|
|
||||||
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR/secrets_migration.json" 2>/dev/null || true
|
|
||||||
chmod 600 "$CONFIG_DIR/secrets_migration.json" 2>/dev/null || true
|
|
||||||
else
|
|
||||||
echo -e "${GREEN}No secrets requiring migration found${NC}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to perform new installation using build orchestrator
|
|
||||||
perform_new_installation() {
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}=== New Agent Installation ===${NC}"
|
|
||||||
|
|
||||||
# Call build/new endpoint to get proper configuration and upgrade logic
|
|
||||||
echo -e "${YELLOW}Requesting agent build configuration...${NC}"
|
|
||||||
BUILD_RESPONSE=$(curl -s -X POST "${REDFLAG_SERVER}/api/v1/build/new" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{
|
|
||||||
"server_url": "'"${REDFLAG_SERVER}"'",
|
|
||||||
"environment": "production",
|
|
||||||
"agent_type": "linux-server",
|
|
||||||
"organization": "default",
|
|
||||||
"registration_token": "'"${REGISTRATION_TOKEN}"'"
|
|
||||||
}' 2>/dev/null)
|
|
||||||
|
|
||||||
if [ $? -ne 0 ] || [ -z "$BUILD_RESPONSE" ]; then
|
|
||||||
echo -e "${RED}✗ Failed to request agent build configuration${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Extract agent ID from build response
|
|
||||||
AGENT_ID=$(echo "$BUILD_RESPONSE" | grep -o '"agent_id":"[^"]*"' | cut -d'"' -f4)
|
|
||||||
|
|
||||||
if [ -z "$AGENT_ID" ]; then
|
|
||||||
echo -e "${RED}✗ Invalid response from server${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✓ Agent configuration created: ${AGENT_ID}${NC}"
|
|
||||||
|
|
||||||
# Download native agent binary
|
|
||||||
echo -e "${YELLOW}Downloading native signed agent binary...${NC}"
|
|
||||||
if curl -sL "${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}" -o "$AGENT_BINARY"; then
|
|
||||||
chmod 755 "$AGENT_BINARY"
|
|
||||||
chown root:root "$AGENT_BINARY"
|
|
||||||
echo -e "${GREEN}✓ Native signed agent binary installed${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Failed to download agent binary${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
deploy_agent "$AGENT_ID" "$BUILD_RESPONSE" "new"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to perform upgrade using build orchestrator
|
|
||||||
perform_upgrade() {
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}=== Agent Upgrade ===${NC}"
|
|
||||||
|
|
||||||
# Extract agent ID from detection
|
|
||||||
AGENT_ID=$(echo "$DETECTION_RESPONSE" | grep -o '"agent_id":"[^"]*"' | cut -d'"' -f4)
|
|
||||||
|
|
||||||
if [ -z "$AGENT_ID" ]; then
|
|
||||||
echo -e "${RED}✗ Could not extract agent ID for upgrade${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${YELLOW}Requesting upgrade configuration for agent: ${AGENT_ID}${NC}"
|
|
||||||
|
|
||||||
# Call build/upgrade endpoint to get upgrade configuration
|
|
||||||
BUILD_RESPONSE=$(curl -s -X POST "${REDFLAG_SERVER}/api/v1/build/upgrade/${AGENT_ID}" \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{
|
|
||||||
"server_url": "'"${REDFLAG_SERVER}"'",
|
|
||||||
"environment": "production",
|
|
||||||
"agent_type": "linux-server",
|
|
||||||
"preserve_existing": true
|
|
||||||
}' 2>/dev/null)
|
|
||||||
|
|
||||||
if [ $? -ne 0 ] || [ -z "$BUILD_RESPONSE" ]; then
|
|
||||||
echo -e "${RED}✗ Failed to request agent upgrade configuration${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo -e "${GREEN}✓ Upgrade configuration prepared for agent: ${AGENT_ID}${NC}"
|
|
||||||
|
|
||||||
# STOP SERVICE BEFORE DOWNLOADING BINARY
|
|
||||||
echo -e "${YELLOW}Stopping agent service to allow binary replacement...${NC}"
|
|
||||||
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
||||||
systemctl stop redflag-agent
|
|
||||||
# Wait for service to fully stop
|
|
||||||
local retry_count=0
|
|
||||||
while [ $retry_count -lt 10 ]; do
|
|
||||||
if ! systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
||||||
echo -e "${GREEN}✓ Service stopped successfully${NC}"
|
|
||||||
break
|
|
||||||
fi
|
|
||||||
echo -e "${YELLOW}Waiting for service to stop... (attempt $((retry_count + 1))/10)${NC}"
|
|
||||||
sleep 1
|
|
||||||
retry_count=$((retry_count + 1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
||||||
echo -e "${RED}✗ Failed to stop service, forcing...${NC}"
|
|
||||||
systemctl kill redflag-agent
|
|
||||||
sleep 2
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${BLUE}✓ Service is already stopped${NC}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Download updated native agent binary to temporary location first
|
|
||||||
echo -e "${YELLOW}Downloading updated native signed agent binary...${NC}"
|
|
||||||
TEMP_BINARY="${AGENT_BINARY}.new"
|
|
||||||
|
|
||||||
# Remove any existing temp binary
|
|
||||||
rm -f "$TEMP_BINARY"
|
|
||||||
|
|
||||||
if curl -sL "${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}" -o "$TEMP_BINARY"; then
|
|
||||||
# Verify the download
|
|
||||||
if [ -f "$TEMP_BINARY" ] && [ -s "$TEMP_BINARY" ]; then
|
|
||||||
chmod 755 "$TEMP_BINARY"
|
|
||||||
chown root:root "$TEMP_BINARY"
|
|
||||||
|
|
||||||
# Atomic move to replace binary
|
|
||||||
mv "$TEMP_BINARY" "$AGENT_BINARY"
|
|
||||||
|
|
||||||
# Verify the replacement
|
|
||||||
if [ -f "$AGENT_BINARY" ] && [ -s "$AGENT_BINARY" ]; then
|
|
||||||
echo -e "${GREEN}✓ Native signed agent binary updated successfully${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Binary replacement verification failed${NC}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Downloaded binary is empty or missing${NC}"
|
|
||||||
rm -f "$TEMP_BINARY"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Failed to download agent binary${NC}"
|
|
||||||
rm -f "$TEMP_BINARY"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
deploy_agent "$AGENT_ID" "$BUILD_RESPONSE" "upgrade"
|
|
||||||
}
|
|
||||||
|
|
||||||
# Function to deploy native agent with systemd
|
|
||||||
deploy_agent() {
|
|
||||||
local AGENT_ID="$1"
|
|
||||||
local BUILD_RESPONSE="$2"
|
|
||||||
local INSTALL_TYPE="$3"
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}=== Agent Deployment ===${NC}"
|
|
||||||
|
|
||||||
# Create agent user if it doesn't exist
|
|
||||||
if ! id "$AGENT_USER" &>/dev/null; then
|
|
||||||
echo -e "${YELLOW}Creating agent user: $AGENT_USER${NC}"
|
|
||||||
useradd -r -s /bin/false -d "$AGENT_HOME" -m "$AGENT_USER"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Note: Service is already stopped for upgrades, but check for new installations
|
|
||||||
if [ "$INSTALL_TYPE" = "new" ] && systemctl is-active --quiet redflag-agent 2>/dev/null; then
|
|
||||||
echo -e "${YELLOW}Stopping existing agent service...${NC}"
|
|
||||||
systemctl stop redflag-agent
|
|
||||||
sleep 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Save build response for potential recovery and debugging
|
|
||||||
echo "$BUILD_RESPONSE" > "${CONFIG_DIR}/build_response.json"
|
|
||||||
chown "$AGENT_USER:$AGENT_USER" "${CONFIG_DIR}/build_response.json"
|
|
||||||
chmod 600 "${CONFIG_DIR}/build_response.json"
|
|
||||||
|
|
||||||
# Create directories
|
|
||||||
mkdir -p "$CONFIG_DIR" "$STATE_DIR"
|
|
||||||
|
|
||||||
# Install sudoers configuration if not exists
|
|
||||||
if [ ! -f "$SUDOERS_FILE" ]; then
|
|
||||||
echo -e "${YELLOW}Installing sudoers configuration...${NC}"
|
|
||||||
cat > "$SUDOERS_FILE" << 'SUDOERS_EOF'
|
|
||||||
# RedFlag Agent minimal sudo permissions
|
|
||||||
# Generated automatically during RedFlag agent installation
|
|
||||||
|
|
||||||
# APT package management commands (Debian/Ubuntu)
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get update
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get install -y *
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get upgrade -y *
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/apt-get install --dry-run --yes *
|
|
||||||
|
|
||||||
# DNF package management commands (RHEL/Fedora/Rocky/Alma)
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf makecache
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf install -y *
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf upgrade -y *
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/dnf install --assumeno --downloadonly *
|
|
||||||
|
|
||||||
# Docker operations
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/docker pull *
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/docker image inspect *
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /usr/bin/docker manifest inspect *
|
|
||||||
|
|
||||||
# Directory operations for RedFlag
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/mkdir -p /etc/redflag
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/mkdir -p /var/lib/redflag
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/chown redflag-agent:redflag-agent /etc/redflag
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/chown redflag-agent:redflag-agent /var/lib/redflag
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/chmod 755 /etc/redflag
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/chmod 755 /var/lib/redflag
|
|
||||||
|
|
||||||
# Migration operations (for existing installations)
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/mv /etc/aggregator /etc/redflag.backup.*
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/mv /var/lib/aggregator/* /var/lib/redflag/
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/rmdir /var/lib/aggregator 2>/dev/null || true
|
|
||||||
redflag-agent ALL=(root) NOPASSWD: /bin/rmdir /etc/aggregator 2>/dev/null || true
|
|
||||||
SUDOERS_EOF
|
|
||||||
|
|
||||||
chmod 440 "$SUDOERS_FILE"
|
|
||||||
|
|
||||||
# Validate sudoers file
|
|
||||||
if visudo -c -f "$SUDOERS_FILE" &>/dev/null; then
|
|
||||||
echo -e "${GREEN}✓ Sudoers configuration installed${NC}"
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Invalid sudoers configuration${NC}"
|
|
||||||
rm -f "$SUDOERS_FILE"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Install/update systemd service
|
|
||||||
echo -e "${YELLOW}Installing systemd service...${NC}"
|
|
||||||
cat > "$SERVICE_FILE" << EOF
|
|
||||||
[Unit]
|
|
||||||
Description=RedFlag Update Agent
|
|
||||||
After=network.target
|
|
||||||
Documentation=https://github.com/Fimeg/RedFlag
|
|
||||||
|
|
||||||
[Service]
|
|
||||||
Type=simple
|
|
||||||
User=$AGENT_USER
|
|
||||||
Group=$AGENT_USER
|
|
||||||
WorkingDirectory=$AGENT_HOME
|
|
||||||
ExecStart=$AGENT_BINARY
|
|
||||||
Restart=always
|
|
||||||
RestartSec=30
|
|
||||||
|
|
||||||
# Security hardening
|
|
||||||
ProtectSystem=strict
|
|
||||||
ProtectHome=true
|
|
||||||
ReadWritePaths=$AGENT_HOME /var/log $CONFIG_DIR $STATE_DIR
|
|
||||||
PrivateTmp=true
|
|
||||||
|
|
||||||
# Logging
|
|
||||||
StandardOutput=journal
|
|
||||||
StandardError=journal
|
|
||||||
SyslogIdentifier=redflag-agent
|
|
||||||
|
|
||||||
[Install]
|
|
||||||
WantedBy=multi-user.target
|
|
||||||
EOF
|
|
||||||
|
|
||||||
chmod 644 "$SERVICE_FILE"
|
|
||||||
systemctl daemon-reload
|
|
||||||
|
|
||||||
# Set directory permissions
|
|
||||||
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR" "$STATE_DIR"
|
|
||||||
chmod 755 "$CONFIG_DIR" "$STATE_DIR"
|
|
||||||
|
|
||||||
# Start and enable service
|
|
||||||
systemctl enable redflag-agent
|
|
||||||
systemctl restart redflag-agent
|
|
||||||
|
|
||||||
# Wait for service to start
|
|
||||||
sleep 3
|
|
||||||
|
|
||||||
# Verify deployment
|
|
||||||
if systemctl is-active --quiet redflag-agent; then
|
|
||||||
echo -e "${GREEN}✓ Native agent deployed successfully${NC}"
|
|
||||||
|
|
||||||
# Check logs briefly
|
|
||||||
echo -e "${BLUE}Agent status:${NC}"
|
|
||||||
systemctl status redflag-agent --no-pager -l | head -n 10
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}=== Installation Complete ===${NC}"
|
|
||||||
echo -e "${BLUE}Agent Details:${NC}"
|
|
||||||
echo -e " • Agent ID: ${AGENT_ID}"
|
|
||||||
echo -e " • Binary: ${AGENT_BINARY}"
|
|
||||||
echo -e " • Service: redflag-agent"
|
|
||||||
echo -e " • Config: ${CONFIG_DIR}/config.json"
|
|
||||||
echo -e " • Build Response: ${CONFIG_DIR}/build_response.json"
|
|
||||||
if [ "$INSTALL_TYPE" = "upgrade" ]; then
|
|
||||||
echo -e " • ${GREEN}Seat preserved: No additional license consumed${NC}"
|
|
||||||
else
|
|
||||||
echo -e " • ${GREEN}Seat allocated: One license consumed${NC}"
|
|
||||||
fi
|
|
||||||
echo ""
|
|
||||||
echo -e "${BLUE}Management Commands:${NC}"
|
|
||||||
echo -e " • Status: systemctl status redflag-agent"
|
|
||||||
echo -e " • Logs: journalctl -u redflag-agent -f"
|
|
||||||
echo -e " • Restart: systemctl restart redflag-agent"
|
|
||||||
echo -e " • Update: Re-run this installer script"
|
|
||||||
echo ""
|
|
||||||
else
|
|
||||||
echo -e "${RED}✗ Failed to start agent service${NC}"
|
|
||||||
echo -e "${YELLOW}Troubleshooting:${NC}"
|
|
||||||
echo -e " • Check logs: journalctl -u redflag-agent -n 50"
|
|
||||||
echo -e " • Check binary: ls -la ${AGENT_BINARY}"
|
|
||||||
echo -e " • Check service: systemctl status redflag-agent"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
# Main execution
|
|
||||||
echo -e "${BLUE}Starting smart installation process...${NC}"
|
|
||||||
|
|
||||||
# Detect existing installation using our sophisticated system
|
|
||||||
if detect_existing_agent; then
|
|
||||||
# Check if migration is needed by looking for old directories
|
|
||||||
if [ -d "$OLD_CONFIG_DIR" ] || [ -d "$OLD_STATE_DIR" ]; then
|
|
||||||
perform_migration
|
|
||||||
fi
|
|
||||||
# Upgrade path
|
|
||||||
perform_upgrade
|
|
||||||
else
|
|
||||||
# Check if migration is needed for new install
|
|
||||||
if [ -d "$OLD_CONFIG_DIR" ] || [ -d "$OLD_STATE_DIR" ]; then
|
|
||||||
perform_migration
|
|
||||||
fi
|
|
||||||
# New installation path
|
|
||||||
perform_new_installation
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo ""
|
|
||||||
echo -e "${GREEN}=== Smart Installer Complete ===${NC}"
|
|
||||||
echo -e "${BLUE}Thank you for using RedFlag!${NC}"
|
|
||||||
`, baseURL)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *DownloadHandler) generateWindowsScript(baseURL string) string {
|
|
||||||
return fmt.Sprintf(`@echo off
|
|
||||||
REM RedFlag Agent Installation Script for Windows
|
|
||||||
REM This script downloads the agent and sets up Windows service
|
|
||||||
REM
|
|
||||||
REM Usage:
|
|
||||||
REM install.bat - Interactive mode (prompts for token)
|
|
||||||
REM install.bat YOUR_TOKEN_HERE - Automatic mode (uses provided token)
|
|
||||||
|
|
||||||
set REDFLAG_SERVER=%s
|
|
||||||
set AGENT_DIR=%%ProgramFiles%%\RedFlag
|
|
||||||
set AGENT_BINARY=%%AGENT_DIR%%\redflag-agent.exe
|
|
||||||
set CONFIG_DIR=%%ProgramData%%\RedFlag
|
|
||||||
|
|
||||||
echo === RedFlag Agent Installation ===
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Check for admin privileges
|
|
||||||
net session >nul 2>&1
|
|
||||||
if %%errorLevel%% neq 0 (
|
|
||||||
echo ERROR: This script must be run as Administrator
|
|
||||||
echo Right-click and select "Run as administrator"
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
REM Detect architecture
|
|
||||||
if "%%PROCESSOR_ARCHITECTURE%%"=="AMD64" (
|
|
||||||
set DOWNLOAD_ARCH=amd64
|
|
||||||
) else if "%%PROCESSOR_ARCHITECTURE%%"=="ARM64" (
|
|
||||||
set DOWNLOAD_ARCH=arm64
|
|
||||||
) else (
|
|
||||||
echo ERROR: Unsupported architecture: %%PROCESSOR_ARCHITECTURE%%
|
|
||||||
echo Supported: AMD64, ARM64
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
|
|
||||||
echo Detected architecture: %%PROCESSOR_ARCHITECTURE%% (using windows-%%DOWNLOAD_ARCH%%)
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Create installation directory
|
|
||||||
echo Creating installation directory...
|
|
||||||
if not exist "%%AGENT_DIR%%" mkdir "%%AGENT_DIR%%"
|
|
||||||
echo [OK] Installation directory created
|
|
||||||
|
|
||||||
REM Create config directory
|
|
||||||
if not exist "%%CONFIG_DIR%%" mkdir "%%CONFIG_DIR%%"
|
|
||||||
echo [OK] Configuration directory created
|
|
||||||
|
|
||||||
REM Grant full permissions to SYSTEM and Administrators on config directory
|
|
||||||
echo Setting permissions on configuration directory...
|
|
||||||
icacls "%%CONFIG_DIR%%" /grant "SYSTEM:(OI)(CI)F"
|
|
||||||
icacls "%%CONFIGDIR%%" /grant "Administrators:(OI)(CI)F"
|
|
||||||
echo [OK] Permissions set
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Stop existing service if running (to allow binary update)
|
|
||||||
sc query RedFlagAgent >nul 2>&1
|
|
||||||
if %%errorLevel%% equ 0 (
|
|
||||||
echo Existing service detected - stopping to allow update...
|
|
||||||
sc stop RedFlagAgent >nul 2>&1
|
|
||||||
timeout /t 3 /nobreak >nul
|
|
||||||
echo [OK] Service stopped
|
|
||||||
)
|
|
||||||
|
|
||||||
REM Download agent binary
|
|
||||||
echo Downloading agent binary...
|
|
||||||
echo From: %%REDFLAG_SERVER%%/api/v1/downloads/windows-%%DOWNLOAD_ARCH%%
|
|
||||||
curl -sfL "%%REDFLAG_SERVER%%/api/v1/downloads/windows-%%DOWNLOAD_ARCH%%" -o "%%AGENT_BINARY%%"
|
|
||||||
if %%errorLevel%% neq 0 (
|
|
||||||
echo ERROR: Failed to download agent binary
|
|
||||||
echo Please ensure %%REDFLAG_SERVER%% is accessible
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
echo [OK] Agent binary downloaded
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Agent registration
|
|
||||||
echo === Agent Registration ===
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Check if token was provided as command-line argument
|
|
||||||
if not "%%1"=="" (
|
|
||||||
set TOKEN=%%1
|
|
||||||
echo Using provided registration token
|
|
||||||
) else (
|
|
||||||
echo IMPORTANT: You need a registration token to enroll this agent.
|
|
||||||
echo.
|
|
||||||
echo To get a token:
|
|
||||||
echo 1. Visit: %%REDFLAG_SERVER%%/settings/tokens
|
|
||||||
echo 2. Create a new registration token
|
|
||||||
echo 3. Copy the token
|
|
||||||
echo.
|
|
||||||
set /p TOKEN="Enter registration token (or press Enter to skip): "
|
|
||||||
)
|
|
||||||
|
|
||||||
REM Check if agent is already registered
|
|
||||||
if exist "%%CONFIG_DIR%%\config.json" (
|
|
||||||
echo.
|
|
||||||
echo [INFO] Agent already registered - configuration file exists
|
|
||||||
echo [INFO] Skipping registration to preserve agent history
|
|
||||||
echo [INFO] If you need to re-register, delete: %%CONFIG_DIR%%\config.json
|
|
||||||
echo.
|
|
||||||
) else if not "%%TOKEN%%"=="" (
|
|
||||||
echo.
|
|
||||||
echo === Registering Agent ===
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Attempt registration
|
|
||||||
"%%AGENT_BINARY%%" --server "%%REDFLAG_SERVER%%" --token "%%TOKEN%%" --register
|
|
||||||
|
|
||||||
REM Check exit code
|
|
||||||
if %%errorLevel%% equ 0 (
|
|
||||||
echo [OK] Agent registered successfully
|
|
||||||
echo [OK] Configuration saved to: %%CONFIG_DIR%%\config.json
|
|
||||||
echo.
|
|
||||||
) else (
|
|
||||||
echo.
|
|
||||||
echo [ERROR] Registration failed
|
|
||||||
echo.
|
|
||||||
echo Please check:
|
|
||||||
echo 1. Server is accessible: %%REDFLAG_SERVER%%
|
|
||||||
echo 2. Registration token is valid and not expired
|
|
||||||
echo 3. Token has available seats remaining
|
|
||||||
echo.
|
|
||||||
echo To try again:
|
|
||||||
echo "%%AGENT_BINARY%%" --server "%%REDFLAG_SERVER%%" --token "%%TOKEN%%" --register
|
|
||||||
echo.
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
echo.
|
|
||||||
echo [INFO] No registration token provided - skipping registration
|
|
||||||
echo.
|
|
||||||
echo To register later:
|
|
||||||
echo "%%AGENT_BINARY%%" --server "%%REDFLAG_SERVER%%" --token YOUR_TOKEN --register
|
|
||||||
)
|
|
||||||
|
|
||||||
REM Check if service already exists
|
|
||||||
echo.
|
|
||||||
echo === Configuring Windows Service ===
|
|
||||||
echo.
|
|
||||||
|
|
||||||
sc query RedFlagAgent >nul 2>&1
|
|
||||||
if %%errorLevel%% equ 0 (
|
|
||||||
echo [INFO] RedFlag Agent service already installed
|
|
||||||
echo [INFO] Service will be restarted with updated binary
|
|
||||||
echo.
|
|
||||||
) else (
|
|
||||||
echo Installing RedFlag Agent service...
|
|
||||||
"%%AGENT_BINARY%%" -install-service
|
|
||||||
if %%errorLevel%% equ 0 (
|
|
||||||
echo [OK] Service installed successfully
|
|
||||||
echo.
|
|
||||||
|
|
||||||
REM Give Windows SCM time to register the service
|
|
||||||
timeout /t 2 /nobreak >nul
|
|
||||||
) else (
|
|
||||||
echo [ERROR] Failed to install service
|
|
||||||
echo.
|
|
||||||
pause
|
|
||||||
exit /b 1
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
REM Start the service if agent is registered
|
|
||||||
if exist "%%CONFIG_DIR%%\config.json" (
|
|
||||||
echo Starting RedFlag Agent service...
|
|
||||||
"%%AGENT_BINARY%%" -start-service
|
|
||||||
if %%errorLevel%% equ 0 (
|
|
||||||
echo [OK] RedFlag Agent service started
|
|
||||||
echo.
|
|
||||||
echo Agent is now running as a Windows service in the background.
|
|
||||||
echo You can verify it is working by checking the agent status in the web UI.
|
|
||||||
) else (
|
|
||||||
echo [WARNING] Failed to start service. You can start it manually:
|
|
||||||
echo "%%AGENT_BINARY%%" -start-service
|
|
||||||
echo Or use Windows Services: services.msc
|
|
||||||
)
|
|
||||||
) else (
|
|
||||||
echo [WARNING] Service not started (agent not registered)
|
|
||||||
echo To register and start the service:
|
|
||||||
echo 1. Register: "%%AGENT_BINARY%%" --server "%%REDFLAGSERVER%%" --token YOUR_TOKEN --register
|
|
||||||
echo 2. Start: "%%AGENT_BINARY%%" -start-service
|
|
||||||
)
|
|
||||||
|
|
||||||
echo.
|
|
||||||
echo === Installation Complete ===
|
|
||||||
echo.
|
|
||||||
echo The RedFlag agent has been installed as a Windows service.
|
|
||||||
echo Configuration file: %%CONFIG_DIR%%\config.json
|
|
||||||
echo Agent binary: %%AGENT_BINARY%%
|
|
||||||
echo.
|
|
||||||
|
|
||||||
echo Managing the RedFlag Agent service:
|
|
||||||
echo Check status: "%%AGENT_BINARY%%" -service-status
|
|
||||||
echo Start manually: "%%AGENT_BINARY%%" -start-service
|
|
||||||
echo Stop service: "%%AGENT_BINARY%%" -stop-service
|
|
||||||
echo Remove service: "%%AGENT_BINARY%%" -remove-service
|
|
||||||
echo.
|
|
||||||
|
|
||||||
echo Alternative management with Windows Services:
|
|
||||||
echo Open services.msc and look for "RedFlag Update Agent"
|
|
||||||
echo.
|
|
||||||
|
|
||||||
echo To run the agent directly (for debugging):
|
|
||||||
echo "%%AGENT_BINARY%%"
|
|
||||||
echo.
|
|
||||||
|
|
||||||
echo To verify the agent is working:
|
|
||||||
echo 1. Check the web UI for the agent status
|
|
||||||
echo 2. Look for recent check-ins from this machine
|
|
||||||
echo.
|
|
||||||
|
|
||||||
pause
|
|
||||||
`, baseURL)
|
|
||||||
}
|
|
||||||
102
aggregator-server/internal/services/install_template_service.go
Normal file
102
aggregator-server/internal/services/install_template_service.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/Fimeg/RedFlag/aggregator-server/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed templates/install/scripts/*.tmpl
|
||||||
|
var installScriptTemplates embed.FS
|
||||||
|
|
||||||
|
// InstallTemplateService renders installation scripts from templates
|
||||||
|
type InstallTemplateService struct{}
|
||||||
|
|
||||||
|
// NewInstallTemplateService creates a new template service
|
||||||
|
func NewInstallTemplateService() *InstallTemplateService {
|
||||||
|
return &InstallTemplateService{}
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderInstallScript renders an installation script for the specified platform
|
||||||
|
func (s *InstallTemplateService) RenderInstallScript(agent *models.Agent, binaryURL, configURL string) (string, error) {
|
||||||
|
// Define template data
|
||||||
|
data := struct {
|
||||||
|
AgentID string
|
||||||
|
BinaryURL string
|
||||||
|
ConfigURL string
|
||||||
|
Platform string
|
||||||
|
Version string
|
||||||
|
}{
|
||||||
|
AgentID: agent.ID.String(),
|
||||||
|
BinaryURL: binaryURL,
|
||||||
|
ConfigURL: configURL,
|
||||||
|
Platform: agent.OSType,
|
||||||
|
Version: agent.CurrentVersion,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Choose template based on platform
|
||||||
|
var templateName string
|
||||||
|
if strings.Contains(agent.OSType, "windows") {
|
||||||
|
templateName = "templates/install/scripts/windows.ps1.tmpl"
|
||||||
|
} else {
|
||||||
|
templateName = "templates/install/scripts/linux.sh.tmpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load and parse template
|
||||||
|
tmpl, err := template.ParseFS(installScriptTemplates, templateName)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("failed to load template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render template
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, data); err != nil {
|
||||||
|
return "", fmt.Errorf("failed to render template: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// RenderInstallScriptFromBuild renders script using build response
|
||||||
|
func (s *InstallTemplateService) RenderInstallScriptFromBuild(
|
||||||
|
agentID string,
|
||||||
|
platform string,
|
||||||
|
version string,
|
||||||
|
binaryURL string,
|
||||||
|
configURL string,
|
||||||
|
) (string, error) {
|
||||||
|
data := struct {
|
||||||
|
AgentID string
|
||||||
|
BinaryURL string
|
||||||
|
ConfigURL string
|
||||||
|
Platform string
|
||||||
|
Version string
|
||||||
|
}{
|
||||||
|
AgentID: agentID,
|
||||||
|
BinaryURL: binaryURL,
|
||||||
|
ConfigURL: configURL,
|
||||||
|
Platform: platform,
|
||||||
|
Version: version,
|
||||||
|
}
|
||||||
|
|
||||||
|
templateName := "templates/install/scripts/linux.sh.tmpl"
|
||||||
|
if strings.Contains(platform, "windows") {
|
||||||
|
templateName = "templates/install/scripts/windows.ps1.tmpl"
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFS(installScriptTemplates, templateName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&buf, data); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# RedFlag Agent Installer - Linux
|
||||||
|
# Generated for agent: {{.AgentID}}
|
||||||
|
# Platform: {{.Platform}}
|
||||||
|
# Version: {{.Version}}
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
AGENT_ID="{{.AgentID}}"
|
||||||
|
BINARY_URL="{{.BinaryURL}}"
|
||||||
|
CONFIG_URL="{{.ConfigURL}}"
|
||||||
|
INSTALL_DIR="/usr/local/bin"
|
||||||
|
CONFIG_DIR="/etc/redflag"
|
||||||
|
SERVICE_NAME="redflag-agent"
|
||||||
|
VERSION="{{.Version}}"
|
||||||
|
|
||||||
|
echo "=== RedFlag Agent v${VERSION} Installation ==="
|
||||||
|
echo "Agent ID: ${AGENT_ID}"
|
||||||
|
echo "Platform: {{.Platform}}"
|
||||||
|
echo "Installing to: ${INSTALL_DIR}/${SERVICE_NAME}"
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Step 1: Create directories
|
||||||
|
echo "Creating directories..."
|
||||||
|
sudo mkdir -p "${CONFIG_DIR}"
|
||||||
|
sudo mkdir -p "/var/lib/redflag"
|
||||||
|
sudo mkdir -p "/var/log/redflag"
|
||||||
|
|
||||||
|
# Step 2: Download agent binary
|
||||||
|
echo "Downloading agent binary..."
|
||||||
|
sudo curl -sSL -o "${INSTALL_DIR}/${SERVICE_NAME}" "${BINARY_URL}"
|
||||||
|
sudo chmod +x "${INSTALL_DIR}/${SERVICE_NAME}"
|
||||||
|
|
||||||
|
# Step 3: Download configuration
|
||||||
|
echo "Downloading configuration..."
|
||||||
|
sudo curl -sSL -o "${CONFIG_DIR}/config.json" "${CONFIG_URL}"
|
||||||
|
sudo chmod 600 "${CONFIG_DIR}/config.json"
|
||||||
|
|
||||||
|
# Step 4: Create systemd service
|
||||||
|
echo "Creating systemd service..."
|
||||||
|
cat <<EOF | sudo tee /etc/systemd/system/${SERVICE_NAME}.service
|
||||||
|
[Unit]
|
||||||
|
Description=RedFlag Security Agent
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=root
|
||||||
|
ExecStart=${INSTALL_DIR}/${SERVICE_NAME}
|
||||||
|
Restart=always
|
||||||
|
RestartSec=30
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Step 5: Enable and start service
|
||||||
|
echo "Enabling and starting service..."
|
||||||
|
sudo systemctl daemon-reload
|
||||||
|
sudo systemctl enable ${SERVICE_NAME}
|
||||||
|
sudo systemctl start ${SERVICE_NAME}
|
||||||
|
|
||||||
|
echo
|
||||||
|
echo "✓ Installation complete!"
|
||||||
|
echo "Agent is running. Check status with: sudo systemctl status ${SERVICE_NAME}"
|
||||||
|
echo "View logs with: sudo journalctl -u ${SERVICE_NAME} -f"
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
# RedFlag Agent Installer - Windows PowerShell
|
||||||
|
# Generated for agent: {{.AgentID}}
|
||||||
|
# Platform: {{.Platform}}
|
||||||
|
# Version: {{.Version}}
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$false)]
|
||||||
|
[switch]$SkipServiceInstall = $false
|
||||||
|
)
|
||||||
|
|
||||||
|
$AgentID = "{{.AgentID}}"
|
||||||
|
$BinaryURL = "{{.BinaryURL}}"
|
||||||
|
$ConfigURL = "{{.ConfigURL}}"
|
||||||
|
$InstallDir = "C:\Program Files\RedFlag"
|
||||||
|
$ConfigDir = "C:\ProgramData\RedFlag"
|
||||||
|
$ServiceName = "RedFlagAgent"
|
||||||
|
$Version = "{{.Version}}"
|
||||||
|
|
||||||
|
Write-Host "=== RedFlag Agent v$Version Installation ===" -ForegroundColor Cyan
|
||||||
|
Write-Host "Agent ID: $AgentID"
|
||||||
|
Write-Host "Platform: {{.Platform}}"
|
||||||
|
Write-Host "Installing to: $InstallDir\redflag-agent.exe"
|
||||||
|
Write-Host
|
||||||
|
|
||||||
|
# Step 1: Create directories
|
||||||
|
Write-Host "Creating directories..." -ForegroundColor Yellow
|
||||||
|
New-Item -ItemType Directory -Force -Path $InstallDir | Out-Null
|
||||||
|
New-Item -ItemType Directory -Force -Path $ConfigDir | Out-Null
|
||||||
|
New-Item -ItemType Directory -Force -Path "$ConfigDir\state" | Out-Null
|
||||||
|
New-Item -ItemType Directory -Force -Path "$ConfigDir\logs" | Out-Null
|
||||||
|
|
||||||
|
# Step 2: Download agent binary
|
||||||
|
Write-Host "Downloading agent binary..." -ForegroundColor Yellow
|
||||||
|
$BinaryPath = Join-Path $InstallDir "redflag-agent.exe"
|
||||||
|
Invoke-WebRequest -Uri $BinaryURL -OutFile $BinaryPath -UseBasicParsing
|
||||||
|
|
||||||
|
# Step 3: Download configuration
|
||||||
|
Write-Host "Downloading configuration..." -ForegroundColor Yellow
|
||||||
|
$ConfigPath = Join-Path $ConfigDir "config.json"
|
||||||
|
Invoke-WebRequest -Uri $ConfigURL -OutFile $ConfigPath -UseBasicParsing
|
||||||
|
|
||||||
|
# Step 4: Set permissions
|
||||||
|
Write-Host "Setting file permissions..." -ForegroundColor Yellow
|
||||||
|
icacls $ConfigPath /inheritance:r /grant:r "SYSTEM:(OI)(CI)F" /grant:r "Administrators:(OI)(CI)F" | Out-Null
|
||||||
|
|
||||||
|
# Step 5: Install Windows service (if not skipped)
|
||||||
|
if (-not $SkipServiceInstall) {
|
||||||
|
Write-Host "Creating Windows service..." -ForegroundColor Yellow
|
||||||
|
|
||||||
|
# Register service with appropriate credentials
|
||||||
|
if ([System.Environment]::OSVersion.Version.Major -ge 10) {
|
||||||
|
# Windows 10/Server 2016+ - can use LocalService
|
||||||
|
New-Service -Name $ServiceName -BinaryPathName $BinaryPath -DisplayName "RedFlag Security Agent" -Description "RedFlag Security Monitoring Agent" -StartupType Automatic | Out-Null
|
||||||
|
} else {
|
||||||
|
# Older Windows - use LocalSystem
|
||||||
|
New-Service -Name $ServiceName -BinaryPathName $BinaryPath -DisplayName "RedFlag Security Agent" -Description "RedFlag Security Monitoring Agent" -StartupType Automatic | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Starting service..." -ForegroundColor Yellow
|
||||||
|
Start-Service -Name $ServiceName
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host
|
||||||
|
Write-Host "✓ Installation complete!" -ForegroundColor Green
|
||||||
|
Write-Host "Agent is running. Check status with: Get-Service $ServiceName"
|
||||||
|
Write-Host "View logs with: Get-Content $ConfigDir\logs\agent.log -Tail 100 -Wait"
|
||||||
Reference in New Issue
Block a user