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:
Binary file not shown.
24
.gitignore
vendored
24
.gitignore
vendored
@@ -445,4 +445,26 @@ TEST-CLONE.md
|
||||
!docs/API.md
|
||||
!docs/CONFIGURATION.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
|
||||
@@ -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
|
||||
@@ -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
31
discord/.gitignore
vendored
@@ -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
@@ -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()
|
||||
@@ -1,4 +0,0 @@
|
||||
discord.py>=2.4.0
|
||||
python-dotenv>=1.0.0
|
||||
aiohttp>=3.8.0
|
||||
asyncio-mqtt>=0.16.0
|
||||
124
discord/setup.py
124
discord/setup.py
@@ -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()
|
||||
@@ -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"
|
||||
383
install.sh
383
install.sh
@@ -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 ""
|
||||
Reference in New Issue
Block a user