From 2b6f3e37a56a390e01d7407a231c6781408541dd Mon Sep 17 00:00:00 2001 From: "Arnaud (Arhuman) ASSAD" Date: Wed, 23 Jul 2025 06:35:30 +0200 Subject: [PATCH 1/3] add mkcerts.sh script --- internal/certs/files/mkcerts.sh | 84 +++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100755 internal/certs/files/mkcerts.sh diff --git a/internal/certs/files/mkcerts.sh b/internal/certs/files/mkcerts.sh new file mode 100755 index 0000000..d349dc7 --- /dev/null +++ b/internal/certs/files/mkcerts.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +# This script generates the necessary certificates for the Minexus mTLS implementation. +# It takes three arguments: +# 1. The hostname or IP address of the Nexus server. +# 2. The distinguished name for the certificates (e.g., "/CN=Minexus CA/O=Minexus"). +# 3. The destination directory for the generated certificates. + +set -e + +if [ "$#" -ne 3 ]; then + echo "Usage: $0 " + exit 1 +fi + +NEXUS_HOST=$1 +DIST_NAME=$2 +DEST_DIR=$3 + +mkdir -p "$DEST_DIR" +cd "$DEST_DIR" + +# 1. Generate Certificate Authority +echo "Generating Certificate Authority..." +openssl genrsa -out ca.key 4096 +openssl req -new -x509 -key ca.key -sha256 -subj "$DIST_NAME" -days 3650 -out ca.crt + +# 2. Generate Server Certificate +echo "Generating Server Certificate..." +cat > server.conf << EOF +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req +prompt = no + +[req_distinguished_name] +CN = $NEXUS_HOST +O = Minexus + +[v3_req] +keyUsage = keyEncipherment, dataEncipherment, digitalSignature +extendedKeyUsage = serverAuth +subjectAltName = @alt_names + +[alt_names] +DNS.1 = $NEXUS_HOST +DNS.2 = localhost +IP.1 = 127.0.0.1 +IP.2 = ::1 +EOF + +openssl genrsa -out server.key 4096 +openssl req -new -key server.key -out server.csr -config server.conf +openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ + -out server.crt -days 3650 -sha256 -extensions v3_req -extfile server.conf + +# 3. Generate Console Client Certificate +echo "Generating Console Client Certificate..." +cat > console.conf << EOF +[req] +distinguished_name = req_distinguished_name +req_extensions = v3_req +prompt = no + +[req_distinguished_name] +CN = console +O = Minexus + +[v3_req] +keyUsage = keyEncipherment, dataEncipherment, digitalSignature +extendedKeyUsage = clientAuth +EOF + +openssl genrsa -out console.key 4096 +openssl req -new -key console.key -out console.csr -config console.conf +openssl x509 -req -in console.csr -CA ca.crt -CAkey ca.key -CAcreateserial \ + -out console.crt -days 3650 -sha256 -extensions v3_req -extfile console.conf + +# 4. Verify Certificates +echo "Verifying Certificates..." +openssl verify -CAfile ca.crt server.crt +openssl verify -CAfile ca.crt console.crt + +echo "Certificates generated successfully in $DEST_DIR" From 7aafc24d9517f94074f4a97160f4c244203aee4c Mon Sep 17 00:00:00 2001 From: "Arnaud (Arhuman) ASSAD" Date: Wed, 23 Jul 2025 06:36:10 +0200 Subject: [PATCH 2/3] add internal/util/string.go --- internal/util/string.go | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 internal/util/string.go diff --git a/internal/util/string.go b/internal/util/string.go new file mode 100644 index 0000000..00f1961 --- /dev/null +++ b/internal/util/string.go @@ -0,0 +1,11 @@ +package util + +// IsHexString checks if a string contains only hexadecimal characters +func IsHexString(s string) bool { + for _, c := range s { + if !((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) { + return false + } + } + return true +} From 9a144b2c509faf54c66306cb27d8bdf9666d7c45 Mon Sep 17 00:00:00 2001 From: "Arnaud (Arhuman) ASSAD" Date: Thu, 24 Jul 2025 05:09:46 +0200 Subject: [PATCH 3/3] add Webserver to Nexus --- README.md | 52 ++++++- cmd/nexus/nexus.go | 53 +++++-- documentation/Webserver.md | 302 +++++++++++++++++++++++++++++++++++++ internal/config/config.go | 48 +++++- 4 files changed, 438 insertions(+), 17 deletions(-) create mode 100644 documentation/Webserver.md diff --git a/README.md b/README.md index 2fe729c..a19ae0a 100644 --- a/README.md +++ b/README.md @@ -49,6 +49,7 @@ It's current features include: - **gRPC Communication**: High-performance, cross-platform RPC - **TLS Encryption**: Secure communication between all components +- **Web Interface**: User-friendly HTTP dashboard and REST API - **Tag-based Targeting**: Flexible minion selection using tags - **Real-time Command Streaming**: Live command delivery to minions - **Command Result Tracking**: Complete audit trail of command execution @@ -163,11 +164,16 @@ make build ``` ┌─────────────┐ gRPC ┌─────────────┐ PostgreSQL ┌──────────────┐ │ Console │◄───────────►│ Nexus │◄─────────────────│ Database │ -│ Client │ │ Server │ │ │ -└─────────────┘ └─────────────┘ └──────────────┘ +│ Client │ (mTLS) │ Server │ │ │ +└─────────────┘ :11973 │ │ └──────────────┘ + │ Triple- │ +┌─────────────┐ HTTP │ Server │ +│ Web Browser │◄───────────►│ Architecture│ +│ Dashboard │ :8086 │ │ +└─────────────┘ └─────────────┘ ▲ - gRPC │ - │ + gRPC │ (TLS) + │ :11972 ┌─────────────┼─────────────┐ │ │ │ ▼ ▼ ▼ @@ -177,6 +183,14 @@ make build └─────────────┘ └─────────────┘ └─────────────┘ ``` +### Triple-Server Architecture + +The Nexus server runs three concurrent services: + +- **Minion Server** (port 11972): TLS gRPC server for minion connections +- **Console Server** (port 11973): mTLS gRPC server for console connections +- **Web Server** (port 8086): HTTP server for web interface and REST API + ## Documentation @@ -184,6 +198,7 @@ More documentation is available in the [`documentation/`](documentation/) direct - **[adding_commands.md](documentation/adding_commands.md)** - Developer oriented guide to add commands to Minexus - **[configuration.md](documentation/configuration.md)** - Complete configuration guide for all components +- **[Webserver.md](documentation/Webserver.md)** - Web interface and REST API documentation - **[version.md](documentation/version.md)** - Version handling, building, and querying guide - **[commands.md](documentation/commands.md)** - Complete guide to all console and minion commands - **[testing.md](documentation/testing.md)** - Comprehensive testing guide and best practices @@ -264,9 +279,10 @@ docker compose down ### Service Overview - **nexus_db**: PostgreSQL database with automatic schema initialization -- **nexus**: Nexus server with dual-port architecture: +- **nexus**: Nexus server with triple-server architecture: - **Port 11972** (`NEXUS_MINION_PORT`) - Minion connections with standard TLS - **Port 11973** (`NEXUS_CONSOLE_PORT`) - Console connections with mutual TLS (mTLS) + - **Port 8086** (`NEXUS_WEB_PORT`) - Web interface and REST API over HTTP - **minion**: Single minion client that connects to nexus using `NEXUS_SERVER` + `NEXUS_MINION_PORT` - **console**: Interactive console client that connects using `NEXUS_SERVER` + `NEXUS_CONSOLE_PORT` (optional, use `--profile console`) @@ -289,6 +305,32 @@ docker compose --profile console up docker compose exec console /app/console ``` +### Web Interface Access + +The web interface provides a user-friendly dashboard and REST API for monitoring and managing your Minexus infrastructure: + +```bash +# Access the web dashboard (when nexus is running) +open http://localhost:8086 + +# Or use the REST API directly +curl http://localhost:8086/api/status +curl http://localhost:8086/api/minions +curl http://localhost:8086/api/health + +# Download pre-built binaries +curl -O http://localhost:8086/download/minion/linux-amd64 +curl -O http://localhost:8086/download/console/windows-amd64.exe +``` + +**Web Interface Features:** +- **Dashboard**: Real-time system status, connected minions, and server health +- **REST API**: Programmatic access to system information +- **Binary Downloads**: Direct access to pre-built minion and console binaries +- **Monitoring**: Standard HTTP endpoints for integration with monitoring tools + +For complete web interface documentation, see [documentation/Webserver.md](documentation/Webserver.md). + ## Usage Examples ### Docker Compose Management diff --git a/cmd/nexus/nexus.go b/cmd/nexus/nexus.go index 180feaf..9b64009 100644 --- a/cmd/nexus/nexus.go +++ b/cmd/nexus/nexus.go @@ -18,6 +18,7 @@ import ( "github.com/arhuman/minexus/internal/logging" "github.com/arhuman/minexus/internal/nexus" "github.com/arhuman/minexus/internal/version" + "github.com/arhuman/minexus/internal/web" pb "github.com/arhuman/minexus/protogen" "go.uber.org/zap" @@ -57,7 +58,7 @@ func main() { defer logging.FuncExit(logger, start) // Display version information - logger.Info("Starting Nexus with dual-port architecture", zap.String("version", version.Component("Nexus"))) + logger.Info("Starting Nexus with triple-server architecture", zap.String("version", version.Component("Nexus"))) // Log the configuration (with sensitive data masked) cfg.LogConfig(logger) @@ -104,11 +105,11 @@ func main() { reflection.Register(minionServer) reflection.Register(consoleServer) - // Start both servers concurrently + // Start all three servers concurrently var wg sync.WaitGroup var serverReady sync.WaitGroup - wg.Add(2) - serverReady.Add(2) + wg.Add(3) + serverReady.Add(3) // Start minion server go func() { @@ -148,12 +149,39 @@ func main() { } }() - // Wait for both servers to be ready + // Start web server + go func() { + defer wg.Done() + logger.Info("Web server starting (HTTP)", + zap.Int("port", cfg.WebPort), + zap.Bool("enabled", cfg.WebEnabled)) + + // Signal server is about to start + go func() { + time.Sleep(100 * time.Millisecond) // Brief delay for server to initialize + if cfg.WebEnabled { + logger.Info("Web server ready for connections", zap.Int("port", cfg.WebPort)) + } else { + logger.Info("Web server disabled") + } + serverReady.Done() + }() + + if err := web.StartWebServer(cfg, nexusServer, logger); err != nil { + if cfg.WebEnabled { + logger.Error("Web server failed", zap.Error(err)) + } + } + }() + + // Wait for all three servers to be ready go func() { serverReady.Wait() - logger.Info("🚀 NEXUS FULLY READY - Both minion and console servers accepting connections", + logger.Info("🚀 NEXUS FULLY READY - All servers accepting connections", zap.Int("minion_port", cfg.MinionPort), - zap.Int("console_port", cfg.ConsolePort)) + zap.Int("console_port", cfg.ConsolePort), + zap.Int("web_port", cfg.WebPort), + zap.Bool("web_enabled", cfg.WebEnabled)) }() // Set up graceful shutdown @@ -161,9 +189,9 @@ func main() { signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM) <-quit - logger.Info("Shutting down both gRPC servers...") + logger.Info("Shutting down all servers...") - // Gracefully stop both servers + // Gracefully stop all servers go func() { logger.Info("Stopping minion server...") minionServer.GracefulStop() @@ -174,7 +202,12 @@ func main() { consoleServer.GracefulStop() }() - // Wait for both servers to finish + go func() { + logger.Info("Stopping web server...") + // Web server shutdown is handled by process termination + }() + + // Wait for all servers to finish wg.Wait() logger.Info("All servers stopped") } diff --git a/documentation/Webserver.md b/documentation/Webserver.md new file mode 100644 index 0000000..3ddbeab --- /dev/null +++ b/documentation/Webserver.md @@ -0,0 +1,302 @@ +# Minexus Web Server + +## Overview + +The Minexus web server provides a user-friendly HTTP interface for monitoring and managing the Minexus system. It runs alongside the existing gRPC servers in a triple-server architecture, offering dashboard views, REST API endpoints, and binary download capabilities. + +## Architecture + +### Triple-Server Design + +The Minexus nexus now operates with three concurrent servers: + +- **Minion Server** (port 11972): TLS gRPC server for minion connections +- **Console Server** (port 11973): mTLS gRPC server for console connections +- **Web Server** (port 8086): HTTP server for web interface and API + +All three servers run concurrently and can be configured independently. + +## Configuration + +### Default Settings + +```bash +# Environment Variables +NEXUS_WEB_PORT=8086 # HTTP server port +NEXUS_WEB_ENABLED=true # Enable/disable web server +NEXUS_WEB_ROOT=./webroot # Path to web assets directory +``` + +### Command Line Flags + +```bash +./nexus --web-port=8086 --web-enabled=true --web-root=./webroot +``` + +### Configuration Fields + +The [`NexusConfig`](../internal/config/config.go) struct includes: + +- `WebPort int` - Port for HTTP web server (default: 8086) +- `WebEnabled bool` - Enable/disable web server (default: true) +- `WebRoot string` - Path to webroot directory (default: "./webroot") + +## Web Interface Features + +### Dashboard (`GET /`) + +The main dashboard provides: + +- **System Information** + - Nexus version and build information + - Server uptime display + - Current system status indicator + +- **Connected Minions** + - Total minion count + - Individual minion details with IDs and status + - Connection timestamps + +- **Server Status** + - All three server port statuses + - Database connection status + - Health indicators + +- **Quick Actions** + - Links to binary downloads + - Direct access to API endpoints + +### Binary Downloads (`GET /download/`) + +Provides access to pre-built binaries: + +#### Minion Binaries +- `/download/minion/linux-amd64` - Linux x64 minion binary +- `/download/minion/linux-arm64` - Linux ARM64 minion binary +- `/download/minion/windows-amd64.exe` - Windows x64 minion executable +- `/download/minion/windows-arm64.exe` - Windows ARM64 minion executable +- `/download/minion/darwin-amd64` - macOS x64 minion binary +- `/download/minion/darwin-arm64` - macOS ARM64 minion binary + +#### Console Binaries +- `/download/console/linux-amd64` - Linux x64 console binary +- `/download/console/linux-arm64` - Linux ARM64 console binary +- `/download/console/windows-amd64.exe` - Windows x64 console executable +- `/download/console/windows-arm64.exe` - Windows ARM64 console executable +- `/download/console/darwin-amd64` - macOS x64 console binary +- `/download/console/darwin-arm64` - macOS ARM64 console binary + +**Note**: Binary serving currently returns informational messages. For production use, place pre-built binaries in a `binaries/` directory structure. + +## REST API + +### System Status (`GET /api/status`) + +Returns comprehensive system information: + +```json +{ + "version": "1.0.0", + "uptime": "2h 45m 12s", + "timestamp": "2024-01-15T10:30:00Z", + "servers": { + "minion": { + "port": 11972, + "status": "running", + "connections": 5 + }, + "console": { + "port": 11973, + "status": "running", + "connections": 0 + }, + "web": { + "port": 8086, + "status": "running" + } + }, + "database": { + "status": "connected", + "host": "localhost:5432" + } +} +``` + +### Minions Information (`GET /api/minions`) + +Returns details about connected minions: + +```json +{ + "count": 2, + "minions": [ + { + "id": "minion-001", + "connected_at": "2024-01-15T08:15:30Z", + "last_seen": "2024-01-15T10:29:45Z", + "status": "active" + } + ] +} +``` + +### Health Check (`GET /api/health`) + +Simple health endpoint for monitoring: + +```json +{ + "status": "healthy", + "timestamp": "2024-01-15T10:30:00Z" +} +``` + +## Security Features + +### HTTP Security Headers + +All responses include appropriate security headers: + +- `X-Content-Type-Options: nosniff` +- `X-Frame-Options: DENY` +- `X-XSS-Protection: 1; mode=block` +- `Referrer-Policy: strict-origin-when-cross-origin` + +### CORS Configuration + +API endpoints support cross-origin requests: + +- `Access-Control-Allow-Origin: *` +- `Access-Control-Allow-Methods: GET, OPTIONS` +- `Access-Control-Allow-Headers: Content-Type` + +### Binary Download Security + +- Proper Content-Type headers for binary downloads +- Content-Disposition headers for safe filename handling +- Input validation for component and platform names +- Request logging for download tracking + +## Implementation Details + +### Embedded Assets + +The web server uses embedded static assets and templates: + +- Templates: [`internal/web/templates/`](../internal/web/templates/) +- Static assets: [`internal/web/static/`](../internal/web/static/) +- Assets are compiled into the binary at build time + +### Data Integration + +- Real-time minion data from gRPC [`ListMinions`](../internal/nexus/nexus.go) calls +- Database health checks via nexus server connectivity +- Uptime tracking from server start time +- Live connection counts and status + +### Logging and Monitoring + +All HTTP requests are logged with: + +- Request method and path +- Client remote address and user agent +- Response status code and duration +- Structured logging via zap logger + +### Error Handling + +- Graceful degradation when nexus server unavailable +- Proper HTTP status codes for all conditions +- JSON error responses for API endpoints +- User-friendly error messages + +## Usage Examples + +### Starting the Web Server + +```bash +# Default configuration +./nexus + +# Custom web port +./nexus --web-port=9090 + +# Disable web server +./nexus --web-enabled=false + +# Custom webroot directory +./nexus --web-root=/custom/webroot +``` + +### Accessing the Interface + +```bash +# Main dashboard +curl http://localhost:8086/ + +# System status API +curl http://localhost:8086/api/status + +# Minion information +curl http://localhost:8086/api/minions + +# Health check +curl http://localhost:8086/api/health + +# Download index +curl http://localhost:8086/download/ +``` + +### Monitoring Integration + +The API endpoints are designed for integration with monitoring systems: + +```bash +# Health check for monitoring +curl -f http://localhost:8086/api/health + +# Minion count monitoring +curl -s http://localhost:8086/api/minions | jq '.count' + +# System status for alerting +curl -s http://localhost:8086/api/status | jq '.database.status' +``` + +## Testing + +Comprehensive test coverage includes: + +- HTTP handler testing with mock responses +- Security header validation +- API endpoint response verification +- Binary download functionality +- Template rendering validation +- Error condition handling + +Run tests with: + +```bash +go test ./internal/web -v +``` + +## Benefits + +### Operational Benefits +- **Easy Health Monitoring** - Simple HTTP endpoints for system status +- **User-Friendly Interface** - No specialized gRPC tools required +- **Flexible Configuration** - Comprehensive configuration options +- **Monitoring Integration** - Standard HTTP endpoints for monitoring tools + +### Development Benefits +- **Optional Feature** - Can be disabled without affecting gRPC functionality +- **Embedded Assets** - No external dependencies for web interface +- **Comprehensive Testing** - Full test coverage for reliability +- **Real-time Data** - Live integration with nexus server state + +### Security Benefits +- **Standard HTTP Security** - Industry-standard security headers +- **Read-only Interface** - No administrative functions via web interface +- **Input Validation** - Proper validation for all user inputs +- **Request Logging** - Complete audit trail of web requests + +The web server provides a modern, accessible interface to the Minexus system while maintaining the robust gRPC foundation for core functionality. \ No newline at end of file diff --git a/internal/config/config.go b/internal/config/config.go index 3a3208b..0fe220c 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -323,8 +323,11 @@ type ConsoleConfig struct { // NexusConfig holds configuration for the Nexus server type NexusConfig struct { - MinionPort int // Port for minion connections with standard TLS - ConsolePort int // Port for console connections with mTLS + MinionPort int // Port for minion connections with standard TLS + ConsolePort int // Port for console connections with mTLS + WebPort int // Port for HTTP web server + WebEnabled bool // Enable/disable web server + WebRoot string // Path to webroot directory (for file system assets) DBHost string DBPort int DBUser string @@ -363,6 +366,9 @@ func DefaultNexusConfig() *NexusConfig { return &NexusConfig{ MinionPort: 11972, ConsolePort: 11973, + WebPort: 8086, + WebEnabled: true, + WebRoot: "./webroot", DBHost: "localhost", DBPort: 5432, DBUser: "postgres", @@ -513,6 +519,23 @@ func LoadNexusConfig() (*NexusConfig, error) { config.ConsolePort = consolePort } + // Load and validate web port + if webPort, err := loader.GetIntInRange("NEXUS_WEB_PORT", config.WebPort, 0, 65535); err != nil { + validationErrors = append(validationErrors, err) + } else { + config.WebPort = webPort + } + + // Load web enabled flag + if webEnabled, err := loader.GetBool("NEXUS_WEB_ENABLED", config.WebEnabled); err != nil { + validationErrors = append(validationErrors, err) + } else { + config.WebEnabled = webEnabled + } + + // Load web root directory + config.WebRoot = loader.GetString("NEXUS_WEB_ROOT", config.WebRoot) + // Load database configuration config.DBHost = loader.GetString("DBHOST", config.DBHost) if err := loader.ValidateRequired("DBHOST", config.DBHost); err != nil { @@ -550,6 +573,9 @@ func LoadNexusConfig() (*NexusConfig, error) { // Parse command line flags (highest priority) minionPort := flag.Int("minion-port", config.MinionPort, "Port to listen on for minion connections") consolePort := flag.Int("console-port", config.ConsolePort, "Console port for mTLS connections") + webPort := flag.Int("web-port", config.WebPort, "Port for HTTP web server") + webEnabled := flag.Bool("web-enabled", config.WebEnabled, "Enable/disable web server") + webRoot := flag.String("web-root", config.WebRoot, "Path to webroot directory") dbHost := flag.String("db-host", config.DBHost, "Database host") dbPort := flag.Int("db-port", config.DBPort, "Database port") dbUser := flag.String("db-user", config.DBUser, "Database user") @@ -583,6 +609,21 @@ func LoadNexusConfig() (*NexusConfig, error) { config.ConsolePort = *consolePort } + // Apply and validate web port + if *webPort < 0 || *webPort > 65535 { + validationErrors = append(validationErrors, ValidationError{ + Field: "web-port", + Value: strconv.Itoa(*webPort), + Message: "must be between 0 and 65535 (0 for system-assigned)", + }) + } else { + config.WebPort = *webPort + } + + // Apply web enabled flag and web root + config.WebEnabled = *webEnabled + config.WebRoot = *webRoot + config.DBHost = *dbHost config.DBPort = *dbPort config.DBUser = *dbUser @@ -805,6 +846,9 @@ func (c *NexusConfig) LogConfig(logger *zap.Logger) { logger.Info("Configuration loaded", zap.Int("minion_port", c.MinionPort), zap.Int("console_port", c.ConsolePort), + zap.Int("web_port", c.WebPort), + zap.Bool("web_enabled", c.WebEnabled), + zap.String("web_root", c.WebRoot), zap.String("db_host", c.DBHost), zap.Int("db_port", c.DBPort), zap.String("db_name", c.DBName),