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:
@@ -8,19 +8,22 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/Fimeg/RedFlag/aggregator-server/internal/config"
|
||||
"github.com/Fimeg/RedFlag/aggregator-server/internal/services"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// DownloadHandler handles agent binary downloads
|
||||
type DownloadHandler struct {
|
||||
agentDir string
|
||||
config *config.Config
|
||||
agentDir string
|
||||
config *config.Config
|
||||
installTemplateService *services.InstallTemplateService
|
||||
}
|
||||
|
||||
func NewDownloadHandler(agentDir string, cfg *config.Config) *DownloadHandler {
|
||||
return &DownloadHandler{
|
||||
agentDir: agentDir,
|
||||
config: cfg,
|
||||
agentDir: agentDir,
|
||||
config: cfg,
|
||||
installTemplateService: services.NewInstallTemplateService(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,918 +157,18 @@ func (h *DownloadHandler) InstallScript(c *gin.Context) {
|
||||
}
|
||||
|
||||
func (h *DownloadHandler) generateInstallScript(platform, baseURL string) string {
|
||||
switch platform {
|
||||
case "linux":
|
||||
return h.generateLinuxScript(baseURL)
|
||||
case "windows":
|
||||
return h.generateWindowsScript(baseURL)
|
||||
default:
|
||||
return "# Unsupported platform: " + platform
|
||||
// Use template service to generate install scripts
|
||||
// For generic downloads, use placeholder values
|
||||
script, err := h.installTemplateService.RenderInstallScriptFromBuild(
|
||||
"<AGENT_ID>", // Will be generated during install
|
||||
platform, // Platform (linux/windows)
|
||||
"latest", // Version
|
||||
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