fix: Update .gitignore and remove dev files from repository

Remove development and investigation files that shouldn't be in repo:
- Kate editor swap files (*.swp, *.kate-swp)
- Discord development folder (contains credentials)
- Development investigation scripts (db_investigation.sh, etc.)
- Configuration files (docker-compose.dev.yml)

Note: Files removed from git but kept locally (rm --cached)
Files are still present in working directory but won't be tracked
This commit is contained in:
Fimeg
2025-12-20 14:12:11 -05:00
parent 62697df112
commit e7a8cc90dd
11 changed files with 23 additions and 1958 deletions

Binary file not shown.

24
.gitignore vendored
View File

@@ -445,4 +445,26 @@ TEST-CLONE.md
!docs/API.md !docs/API.md
!docs/CONFIGURATION.md !docs/CONFIGURATION.md
!docs/ARCHITECTURE.md !docs/ARCHITECTURE.md
!docs/DEVELOPMENT.md !docs/DEVELOPMENT.md
# =============================================================================
# Development and investigation files (should not be in repo)
# =============================================================================
db_investigation.sh
fix_agent_permissions.sh
install.sh
docker-compose.dev.yml
.migration_temp/
# =============================================================================
# Kate editor swap files
# =============================================================================
*.swp
*.kate-swp
.MIGRATION_STRATEGY.md.kate-swp
# =============================================================================
# Discord bot development (private, contains credentials)
# =============================================================================
discord/
discord/.env.example

View File

@@ -1,56 +0,0 @@
#!/bin/bash
echo "=== RedFlag Database Investigation ==="
echo
# Check if containers are running
echo "1. Checking container status..."
docker ps | grep -E "redflag|postgres"
echo
echo "2. Testing database connection with different credentials..."
# Try with postgres credentials
echo "Trying with postgres user:"
docker exec redflag-postgres psql -U postgres -c "SELECT current_database(), current_user;" 2>/dev/null
# Try with redflag credentials
echo "Trying with redflag user:"
docker exec redflag-postgres psql -U redflag -d redflag -c "SELECT current_database(), current_user;" 2>/dev/null
echo
echo "3. Listing databases:"
docker exec redflag-postgres psql -U postgres -c "\l" 2>/dev/null
echo
echo "4. Checking tables in redflag database:"
docker exec redflag-postgres psql -U postgres -d redflag -c "\dt" 2>/dev/null || echo "Failed to list tables"
echo
echo "5. Checking migration status:"
docker exec redflag-postgres psql -U postgres -d redflag -c "SELECT version, applied_at FROM schema_migrations ORDER BY version;" 2>/dev/null || echo "No schema_migrations table found"
echo
echo "6. Checking users table:"
docker exec redflag-postgres psql -U postgres -d redflag -c "SELECT id, username, email, created_at FROM users LIMIT 5;" 2>/dev/null || echo "Users table not found"
echo
echo "7. Checking for security_* tables:"
docker exec redflag-postgres psql -U postgres -d redflag -c "\dt security_*" 2>/dev/null || echo "No security_* tables found"
echo
echo "8. Checking agent_commands table for signature column:"
docker exec redflag-postgres psql -U postgres -d redflag -c "\d agent_commands" 2>/dev/null | grep signature || echo "Signature column not found"
echo
echo "9. Checking recent logs from server:"
docker logs redflag-server 2>&1 | tail -20
echo
echo "10. Password configuration check:"
echo "From docker-compose.yml POSTGRES_PASSWORD:"
grep "POSTGRES_PASSWORD:" docker-compose.yml
echo "From config/.env POSTGRES_PASSWORD:"
grep "POSTGRES_PASSWORD:" config/.env
echo "From config/.env REDFLAG_DB_PASSWORD:"
grep "REDFLAG_DB_PASSWORD:" config/.env

View File

@@ -1,24 +0,0 @@
# Discord Configuration Template
# Copy this file to .env and fill in your actual values
# Discord Bot Configuration
DISCORD_BOT_TOKEN=your_bot_token_here
DISCORD_SERVER_ID=your_server_id_here
DISCORD_APPLICATION_ID=your_app_id_here
DISCORD_PUBLIC_KEY=your_public_key_here
# Server Management
SERVER_NAME=RedFlag Security
ADMIN_ROLE_ID=your_admin_role_id_here
# Channel IDs (to be filled after creation)
GENERAL_CHANNEL_ID=
ANNOUNCEMENTS_CHANNEL_ID=
SECURITY_ALERTS_CHANNEL_ID=
DEV_CHAT_CHANNEL_ID=
BUG_REPORTS_CHANNEL_ID=
# Category IDs (to be filled after creation)
COMMUNITY_CATEGORY_ID=
DEVELOPMENT_CATEGORY_ID=
SECURITY_CATEGORY_ID=

31
discord/.gitignore vendored
View File

@@ -1,31 +0,0 @@
# Environment files
.env
.env.local
.env.*.local
# Python
__pycache__/
*.pyc
*.pyo
*.pyd
.env
venv/
.venv/
env/
venv.bak/
venv/
# IDE
.vscode/
.idea/
*.swp
*.swo
*~
# Logs
*.log
logs/
# OS
.DS_Store
Thumbs.db

File diff suppressed because it is too large Load Diff

View File

@@ -1,153 +0,0 @@
#!/usr/bin/env python3
"""
Secure Discord Environment Manager
Handles loading Discord configuration from .env without exposing secrets
"""
import os
import logging
from typing import Optional, Dict, Any
from dotenv import load_dotenv
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class DiscordEnvManager:
"""Secure environment manager for Discord configuration"""
def __init__(self, env_file: str = ".env"):
self.env_file = env_file
self._config = {}
self._load_config()
def _load_config(self):
"""Load configuration from .env file"""
try:
load_dotenv(self.env_file)
self._config = {
'DISCORD_BOT_TOKEN': os.getenv('DISCORD_BOT_TOKEN'),
'DISCORD_SERVER_ID': os.getenv('DISCORD_SERVER_ID'),
'DISCORD_APPLICATION_ID': os.getenv('DISCORD_APPLICATION_ID'),
'DISCORD_PUBLIC_KEY': os.getenv('DISCORD_PUBLIC_KEY'),
'SERVER_NAME': os.getenv('SERVER_NAME', 'RedFlag Security'),
'ADMIN_ROLE_ID': os.getenv('ADMIN_ROLE_ID'),
'GENERAL_CHANNEL_ID': os.getenv('GENERAL_CHANNEL_ID'),
'ANNOUNCEMENTS_CHANNEL_ID': os.getenv('ANNOUNCEMENTS_CHANNEL_ID'),
'SECURITY_ALERTS_CHANNEL_ID': os.getenv('SECURITY_ALERTS_CHANNEL_ID'),
'DEV_CHAT_CHANNEL_ID': os.getenv('DEV_CHAT_CHANNEL_ID'),
'BUG_REPORTS_CHANNEL_ID': os.getenv('BUG_REPORTS_CHANNEL_ID'),
'COMMUNITY_CATEGORY_ID': os.getenv('COMMUNITY_CATEGORY_ID'),
'DEVELOPMENT_CATEGORY_ID': os.getenv('DEVELOPMENT_CATEGORY_ID'),
'SECURITY_CATEGORY_ID': os.getenv('SECURITY_CATEGORY_ID'),
}
# Validate required fields
required_fields = ['DISCORD_BOT_TOKEN', 'DISCORD_SERVER_ID']
missing = [field for field in required_fields if not self._config.get(field)]
if missing:
logger.error(f"Missing required environment variables: {missing}")
raise ValueError(f"Missing required fields: {missing}")
logger.info("✅ Discord configuration loaded successfully")
except Exception as e:
logger.error(f"Failed to load Discord configuration: {e}")
raise
def get(self, key: str, default: Any = None) -> Optional[str]:
"""Get configuration value"""
return self._config.get(key, default)
def get_required(self, key: str) -> str:
"""Get required configuration value"""
value = self._config.get(key)
if not value:
raise ValueError(f"Required environment variable {key} is not set")
return value
def update_channel_ids(self, channel_name: str, channel_id: str):
"""Update channel ID in config"""
channel_key = f"{channel_name.upper()}_CHANNEL_ID"
self._config[channel_key] = channel_id
# Also update in file
self._update_env_file(channel_key, channel_id)
def update_category_ids(self, category_name: str, category_id: str):
"""Update category ID in config"""
category_key = f"{category_name.upper()}_CATEGORY_ID"
self._config[category_key] = category_id
# Also update in file
self._update_env_file(category_key, category_id)
def _update_env_file(self, key: str, value: str):
"""Update .env file with new value"""
try:
env_path = os.path.join(os.path.dirname(__file__), self.env_file)
# Read current file
if os.path.exists(env_path):
with open(env_path, 'r') as f:
lines = f.readlines()
else:
lines = []
# Update or add the line
updated = False
for i, line in enumerate(lines):
if line.startswith(f"{key}="):
lines[i] = f"{key}={value}\n"
updated = True
break
if not updated:
lines.append(f"{key}={value}\n")
# Write back to file
with open(env_path, 'w') as f:
f.writelines(lines)
logger.info(f"✅ Updated {key} in {self.env_file}")
except Exception as e:
logger.error(f"Failed to update {key} in {self.env_file}: {e}")
def is_configured(self) -> bool:
"""Check if the Discord bot is properly configured"""
return (
self.get('DISCORD_BOT_TOKEN') and
self.get('DISCORD_SERVER_ID') and
self.get('DISCORD_APPLICATION_ID')
)
def mask_sensitive_info(self, text: str) -> str:
"""Mask sensitive information in logs"""
sensitive_words = ['TOKEN', 'KEY']
masked_text = text
for word in sensitive_words:
if f"{word}_ID" not in masked_text: # Don't mask channel IDs
# Find and mask the value
import re
pattern = rf'{word}=\w+'
replacement = f'{word}=***MASKED***'
masked_text = re.sub(pattern, replacement, masked_text)
return masked_text
# Global instance for easy access
discord_env = DiscordEnvManager()
# Convenience functions
def get_discord_config():
"""Get Discord configuration"""
return discord_env
def is_discord_ready():
"""Check if Discord is ready for use"""
return discord_env.is_configured()

View File

@@ -1,4 +0,0 @@
discord.py>=2.4.0
python-dotenv>=1.0.0
aiohttp>=3.8.0
asyncio-mqtt>=0.16.0

View File

@@ -1,124 +0,0 @@
#!/usr/bin/env python3
"""
RedFlag Discord Setup Assistant
Helps configure Discord bot for server management
"""
import os
import sys
from dotenv import load_dotenv
def setup_discord():
"""Interactive Discord setup"""
print("🚀 RedFlag Discord Bot Setup Assistant")
print("=" * 50)
# Check if .env exists
env_file = ".env"
if not os.path.exists(env_file):
print(f"📝 Creating {env_file} from template...")
if os.path.exists(".env.example"):
import shutil
shutil.copy(".env.example", env_file)
print(f"✅ Created {env_file} from .env.example")
else:
# Create basic .env file
with open(env_file, 'w') as f:
f.write("# Discord Bot Configuration\n")
f.write("DISCORD_BOT_TOKEN=your_bot_token_here\n")
f.write("DISCORD_SERVER_ID=your_server_id_here\n")
f.write("DISCORD_APPLICATION_ID=your_app_id_here\n")
f.write("DISCORD_PUBLIC_KEY=your_public_key_here\n")
f.write("\n# Server Settings\n")
f.write("SERVER_NAME=RedFlag Security\n")
f.write("ADMIN_ROLE_ID=\n")
print(f"✅ Created basic {env_file}")
# Load environment
load_dotenv(env_file)
print("\n📋 Discord Configuration Checklist:")
print("1. ✅ Discord Developer Portal: https://discord.com/developers/applications")
print("2. ✅ Create Application: Click 'New Application'")
print("3. ✅ Create Bot: Go to 'Bot''Add Bot'")
print("4. ✅ Enable Privileged Intents:")
print(" - ✅ Server Members Intent")
print(" - ✅ Server Management Intent")
print(" - ✅ Message Content Intent")
print("5. ✅ OAuth2 URL Generator:")
print(" - ✅ Scope: bot")
print(" - ✅ Scope: applications.commands")
print(" - ✅ Permissions: Administrator (or specific)")
print("6. ✅ Invite Bot to Server")
print("7. ✅ Copy Values Below:")
print("\n🔑 Required Discord Information:")
print("From your Discord Developer Portal, copy these values:")
print("-" * 50)
# Get user input (with masking)
def get_sensitive_input(prompt, key):
value = input(f"{prompt}: ").strip()
if value:
# Update .env file
update_env_file(key, value)
# Show masked version
masked_value = value[:8] + "..." + value[-4:] if len(value) > 12 else value
print(f"{key}: {masked_value}")
return value
def update_env_file(key, value):
"""Update .env file with value"""
env_path = os.path.join(os.path.dirname(__file__), env_file)
# Read current file
with open(env_path, 'r') as f:
lines = f.readlines()
# Update or add the line
updated = False
for i, line in enumerate(lines):
if line.startswith(f"{key}="):
lines[i] = f"{key}={value}\n"
updated = True
break
if not updated:
lines.append(f"{key}={value}\n")
# Write back to file
with open(env_path, 'w') as f:
f.writelines(lines)
# Get required values
bot_token = get_sensitive_input("Discord Bot Token", "DISCORD_BOT_TOKEN")
server_id = get_sensitive_input("Discord Server ID", "DISCORD_SERVER_ID")
app_id = get_sensitive_input("Discord Application ID", "DISCORD_APPLICATION_ID")
public_key = get_sensitive_input("Discord Public Key", "DISCORD_PUBLIC_KEY")
print("-" * 50)
print("🎉 Configuration Complete!")
print("\n📝 Next Steps:")
print("1. Run the Discord bot:")
print(" cd /home/memory/Desktop/Projects/RedFlag/discord")
print(" python discord_manager.py")
print("\n2. Available Commands (slash commands):")
print(" • /status - Show server status")
print(" • /create-channels - Create standard channels")
print(" • /list-channels - List all channels")
print(" • /send-message - Send message to channel")
print(" • /create-category - Create new category")
print(" • /help - Show all commands")
print("\n🔒 Security Note:")
print("• Your bot token is stored locally in .env")
print("• Never share the .env file")
print("• The bot only has Administrator permissions you grant it")
print("• All actions are logged locally")
def main():
"""Main setup function"""
setup_discord()
if __name__ == "__main__":
main()

View File

@@ -1,136 +0,0 @@
#!/bin/bash
# Fix RedFlag Agent Permissions Script
# This script fixes the systemd service permissions for the agent
set -e
echo "🔧 RedFlag Agent Permission Fix Script"
echo "======================================"
echo ""
# Check if running as root or with sudo
if [ "$EUID" -ne 0 ]; then
echo "This script needs sudo privileges to modify systemd service files."
echo "You'll be prompted for your password."
echo ""
exec sudo "$0" "$@"
fi
echo "✅ Running with sudo privileges"
echo ""
# Step 1: Check current systemd service
echo "📋 Step 1: Checking current systemd service..."
SERVICE_FILE="/etc/systemd/system/redflag-agent.service"
if [ ! -f "$SERVICE_FILE" ]; then
echo "❌ Service file not found: $SERVICE_FILE"
exit 1
fi
echo "✅ Service file found: $SERVICE_FILE"
echo ""
# Step 2: Check if ReadWritePaths is already configured
echo "📋 Step 2: Checking current service configuration..."
if grep -q "ReadWritePaths=" "$SERVICE_FILE"; then
echo "✅ ReadWritePaths already configured"
grep "ReadWritePaths=" "$SERVICE_FILE"
else
echo "⚠️ ReadWritePaths not found - needs to be added"
fi
echo ""
# Step 3: Backup original service file
echo "💾 Step 3: Creating backup of service file..."
cp "$SERVICE_FILE" "${SERVICE_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
echo "✅ Backup created"
echo ""
# Step 4: Add ReadWritePaths to service file
echo "🔧 Step 4: Adding ReadWritePaths to service file..."
# Check if [Service] section exists
if ! grep -q "^\[Service\]" "$SERVICE_FILE"; then
echo "❌ [Service] section not found in service file"
exit 1
fi
# Add ReadWritePaths after [Service] section if not already present
if ! grep -q "ReadWritePaths=/var/lib/redflag" "$SERVICE_FILE"; then
# Use sed to add the line after [Service]
sed -i '/^\[Service\]/a ReadWritePaths=/var/lib/redflag /etc/redflag /var/log/redflag' "$SERVICE_FILE"
echo "✅ ReadWritePaths added to service file"
else
echo "✅ ReadWritePaths already present"
fi
echo ""
# Step 5: Show the updated service file
echo "📄 Step 5: Updated service file:"
echo "--------------------------------"
grep -A 20 "^\[Service\]" "$SERVICE_FILE" | head -25
echo "--------------------------------"
echo ""
# Step 6: Create necessary directories
echo "📁 Step 6: Creating necessary directories..."
mkdir -p /var/lib/redflag/migration_backups
mkdir -p /var/log/redflag
mkdir -p /etc/redflag
echo "✅ Directories created/verified"
echo ""
# Step 7: Set proper permissions
echo "🔐 Step 7: Setting permissions..."
if id "redflag-agent" &>/dev/null; then
chown -R redflag-agent:redflag-agent /var/lib/redflag
chown -R redflag-agent:redflag-agent /var/log/redflag
echo "✅ Permissions set for redflag-agent user"
else
echo "⚠️ redflag-agent user not found - skipping permission setting"
fi
echo ""
# Step 8: Reload systemd
echo "🔄 Step 8: Reloading systemd..."
systemctl daemon-reload
sleep 2
echo "✅ Systemd reloaded"
echo ""
# Step 9: Restart the agent
echo "🚀 Step 9: Restarting redflag-agent service..."
systemctl restart redflag-agent
sleep 3
echo "✅ Service restarted"
echo ""
# Step 10: Check service status
echo "📊 Step 10: Checking service status..."
echo "--------------------------------"
systemctl status redflag-agent --no-pager -n 10
echo "--------------------------------"
echo ""
# Step 11: Check logs
echo "📝 Step 11: Recent logs..."
echo "--------------------------------"
journalctl -u redflag-agent -n 20 --no-pager
echo "--------------------------------"
echo ""
echo "🎉 Script completed!"
echo ""
echo "Next steps:"
echo "1. Wait 30 seconds for agent to stabilize"
echo "2. Run: sudo journalctl -u redflag-agent -f"
echo "3. Check if agent registers successfully"
echo "4. Verify in UI: http://localhost:3000/agents"
echo ""
echo "If the agent still fails, check:"
echo "- Database connection in /etc/redflag/config.json"
echo "- Network connectivity to aggregator-server"
echo "- Token validity in the database"

View File

@@ -1,383 +0,0 @@
#!/bin/bash
set -e
# RedFlag Agent Installation Script
# This script installs the RedFlag agent as a systemd service with proper security hardening
REDFLAG_SERVER="http://localhost:8080"
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"
echo "=== RedFlag Agent Installation ==="
echo ""
# Check if running as root
if [ "$EUID" -ne 0 ]; then
echo "ERROR: This script must be run as root (use sudo)"
exit 1
fi
# Detect architecture
ARCH=$(uname -m)
case "$ARCH" in
x86_64)
DOWNLOAD_ARCH="amd64"
;;
aarch64|arm64)
DOWNLOAD_ARCH="arm64"
;;
*)
echo "ERROR: Unsupported architecture: $ARCH"
echo "Supported: x86_64 (amd64), aarch64 (arm64)"
exit 1
;;
esac
echo "Detected architecture: $ARCH (using linux-$DOWNLOAD_ARCH)"
echo ""
# Step 1: Create system user
echo "Step 1: Creating system user..."
if id "$AGENT_USER" &>/dev/null; then
echo "✓ User $AGENT_USER already exists"
else
useradd -r -s /bin/false -d "$AGENT_HOME" -m "$AGENT_USER"
echo "✓ User $AGENT_USER created"
fi
# Create home directory if it doesn't exist
if [ ! -d "$AGENT_HOME" ]; then
mkdir -p "$AGENT_HOME"
chown "$AGENT_USER:$AGENT_USER" "$AGENT_HOME"
echo "✓ Home directory created"
fi
# Stop existing service if running (to allow binary update)
if systemctl is-active --quiet redflag-agent 2>/dev/null; then
echo ""
echo "Existing service detected - stopping to allow update..."
systemctl stop redflag-agent
sleep 2
echo "✓ Service stopped"
fi
# Step 2: Download agent binary
echo ""
echo "Step 2: Downloading agent binary..."
echo "Downloading from ${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}..."
# Download to temporary file first (to avoid root permission issues)
TEMP_FILE="/tmp/redflag-agent-${DOWNLOAD_ARCH}"
echo "Downloading to temporary file: $TEMP_FILE"
# Try curl first (most reliable)
if curl -sL "${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}" -o "$TEMP_FILE"; then
echo "✓ Download successful, moving to final location"
mv "$TEMP_FILE" "${AGENT_BINARY}"
chmod 755 "${AGENT_BINARY}"
chown root:root "${AGENT_BINARY}"
echo "✓ Agent binary downloaded and installed"
else
echo "✗ Download with curl failed"
# Fallback to wget if available
if command -v wget >/dev/null 2>&1; then
echo "Trying wget fallback..."
if wget -q "${REDFLAG_SERVER}/api/v1/downloads/linux-${DOWNLOAD_ARCH}" -O "$TEMP_FILE"; then
echo "✓ Download successful with wget, moving to final location"
mv "$TEMP_FILE" "${AGENT_BINARY}"
chmod 755 "${AGENT_BINARY}"
chown root:root "${AGENT_BINARY}"
echo "✓ Agent binary downloaded and installed (using wget fallback)"
else
echo "ERROR: Failed to download agent binary"
echo "Both curl and wget failed"
echo "Please ensure ${REDFLAG_SERVER} is accessible"
# Clean up temp file if it exists
rm -f "$TEMP_FILE"
exit 1
fi
else
echo "ERROR: Failed to download agent binary"
echo "curl failed and wget is not available"
echo "Please ensure ${REDFLAG_SERVER} is accessible"
# Clean up temp file if it exists
rm -f "$TEMP_FILE"
exit 1
fi
fi
# Clean up temp file if it still exists
rm -f "$TEMP_FILE"
# Set SELinux context for binary if SELinux is enabled
if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" != "Disabled" ]; then
echo "SELinux detected, setting file context for binary..."
restorecon -v "${AGENT_BINARY}" 2>/dev/null || true
echo "✓ SELinux context set for binary"
fi
# Step 3: Install sudoers configuration
echo ""
echo "Step 3: Installing sudoers configuration..."
cat > "$SUDOERS_FILE" <<'SUDOERS_EOF'
# RedFlag Agent minimal sudo permissions
# This file grants the redflag-agent user limited sudo access for package management
# 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 "✓ Sudoers configuration installed and validated"
else
echo "ERROR: Sudoers configuration is invalid"
rm -f "$SUDOERS_FILE"
exit 1
fi
# Step 4: Create configuration and state directories
echo ""
echo "Step 4: Creating configuration and state directories..."
mkdir -p "$CONFIG_DIR"
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR"
chmod 755 "$CONFIG_DIR"
# Create state directory for acknowledgment tracking (v0.1.19+)
mkdir -p "$STATE_DIR"
chown "$AGENT_USER:$AGENT_USER" "$STATE_DIR"
chmod 755 "$STATE_DIR"
echo "✓ Configuration and state directories created"
# Set SELinux context for directories if SELinux is enabled
if command -v getenforce >/dev/null 2>&1 && [ "$(getenforce)" != "Disabled" ]; then
echo "Setting SELinux context for directories..."
restorecon -Rv "$CONFIG_DIR" "$STATE_DIR" 2>/dev/null || true
echo "✓ SELinux context set for directories"
fi
# Step 5: Install systemd service
echo ""
echo "Step 5: Installing systemd service..."
cat > "$SERVICE_FILE" <<SERVICE_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
# NoNewPrivileges=true - DISABLED: Prevents sudo from working, which agent needs for package management
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
SERVICE_EOF
chmod 644 "$SERVICE_FILE"
echo "✓ Systemd service installed"
# Step 6: Register agent with server
echo ""
echo "Step 6: Agent registration"
echo "=========================================="
echo ""
# Check if token was provided as parameter (for one-liner support)
if [ -n "$1" ]; then
REGISTRATION_TOKEN="$1"
echo "Using provided registration token"
else
# Check if stdin is a terminal (not being piped)
if [ -t 0 ]; then
echo "Registration token required to enroll this agent with the server."
echo ""
echo "To get a token:"
echo " 1. Visit: ${REDFLAG_SERVER}/settings/tokens"
echo " 2. Copy the active token from the list"
echo ""
echo "Enter registration token (or press Enter to skip):"
read -p "> " REGISTRATION_TOKEN
else
echo ""
echo "IMPORTANT: Registration token required!"
echo ""
echo "Since you're running this via pipe, you need to:"
echo ""
echo "Option 1 - One-liner with token:"
echo " curl -sfL ${REDFLAG_SERVER}/api/v1/install/linux | sudo bash -s -- YOUR_TOKEN"
echo ""
echo "Option 2 - Download and run interactively:"
echo " curl -sfL ${REDFLAG_SERVER}/api/v1/install/linux -o install.sh"
echo " chmod +x install.sh"
echo " sudo ./install.sh"
echo ""
echo "Skipping registration for now."
echo "Please register manually after installation."
fi
fi
# Check if agent is already registered
if [ -f "$CONFIG_DIR/config.json" ]; then
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 ""
elif [ -n "$REGISTRATION_TOKEN" ]; then
echo ""
echo "Registering agent..."
# Create config file and register
cat > "$CONFIG_DIR/config.json" <<EOF
{
"server_url": "${REDFLAG_SERVER}",
"registration_token": "${REGISTRATION_TOKEN}"
}
EOF
# Set proper permissions
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR/config.json"
chmod 600 "$CONFIG_DIR/config.json"
# Run agent registration as the agent user with explicit server and token
echo "Running: sudo -u $AGENT_USER ${AGENT_BINARY} --server ${REDFLAG_SERVER} --token $REGISTRATION_TOKEN --register"
if sudo -u "$AGENT_USER" "${AGENT_BINARY}" --server "${REDFLAG_SERVER}" --token "$REGISTRATION_TOKEN" --register; then
echo "✓ Agent registered successfully"
# Update config file with the new agent credentials
if [ -f "$CONFIG_DIR/config.json" ]; then
chown "$AGENT_USER:$AGENT_USER" "$CONFIG_DIR/config.json"
chmod 600 "$CONFIG_DIR/config.json"
echo "✓ Configuration file updated and secured"
fi
else
echo "ERROR: Agent registration failed"
echo "Please check the token and server URL, then try again"
echo ""
echo "To retry manually:"
echo " sudo -u $AGENT_USER ${AGENT_BINARY} --server ${REDFLAG_SERVER} --token $REGISTRATION_TOKEN --register"
exit 1
fi
else
echo ""
echo "Skipping registration. You'll need to register manually before starting the service."
echo ""
echo "To register later:"
echo " 1. Visit ${REDFLAG_SERVER}/settings/tokens"
echo " 2. Copy a registration token"
echo " 3. Run: sudo -u $AGENT_USER ${AGENT_BINARY} --server ${REDFLAG_SERVER} --token YOUR_TOKEN"
echo ""
echo "Installation will continue, but the service will not start until registered."
fi
# Step 7: Enable and start service
echo ""
echo "Step 7: Enabling and starting service..."
systemctl daemon-reload
# Check if agent is registered
if [ -f "$CONFIG_DIR/config.json" ]; then
systemctl enable redflag-agent
systemctl restart redflag-agent
# Wait for service to start
sleep 2
if systemctl is-active --quiet redflag-agent; then
echo "✓ Service started successfully"
else
echo "⚠ Service failed to start. Check logs:"
echo " sudo journalctl -u redflag-agent -n 50"
exit 1
fi
else
echo "⚠ Service not started (agent not registered)"
echo " Run registration command above, then:"
echo " sudo systemctl enable redflag-agent"
echo " sudo systemctl start redflag-agent"
fi
# Step 8: Show status
echo ""
echo "=== Installation Complete ==="
echo ""
echo "The RedFlag agent has been installed with the following security features:"
echo " ✓ Dedicated system user (redflag-agent)"
echo " ✓ Limited sudo access via /etc/sudoers.d/redflag-agent"
echo " ✓ Systemd service with security hardening"
echo " ✓ Protected configuration directory"
echo ""
if systemctl is-active --quiet redflag-agent; then
echo "Service Status: ✓ RUNNING"
echo ""
systemctl status redflag-agent --no-pager -l | head -n 15
echo ""
else
echo "Service Status: ⚠ NOT RUNNING (waiting for registration)"
echo ""
fi
echo "Useful commands:"
echo " Check status: sudo systemctl status redflag-agent"
echo " View logs: sudo journalctl -u redflag-agent -f"
echo " Restart: sudo systemctl restart redflag-agent"
echo " Stop: sudo systemctl stop redflag-agent"
echo ""
echo "Configuration:"
echo " Config file: $CONFIG_DIR/config.json"
echo " Binary: $AGENT_BINARY"
echo " Service: $SERVICE_FILE"
echo " Sudoers: $SUDOERS_FILE"
echo ""