feat(ai): Integrate MCP server and threat-analyst with AI Gateway
Route AI requests through the AI Gateway for data sovereignty compliance. Changes: - secubox-mcp-server: ai.sh now prefers AI Gateway (port 4050), falls back to LocalAI - secubox-threat-analyst: UCI config adds ai_gateway_url option - threat-analyst CLI shows both Gateway and LocalAI status - analyzer.sh and appliers.sh use ai_url (Gateway preferred) - README updated with AI Gateway integration section The AI Gateway ensures threat data (IPs, MACs, logs) is classified as LOCAL_ONLY and never leaves the device, supporting ANSSI CSPN compliance. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
f3cea01792
commit
d351ae515a
@ -1,19 +1,38 @@
|
|||||||
# SecuBox MCP Tool: AI-Powered Security Analysis
|
# SecuBox MCP Tool: AI-Powered Security Analysis
|
||||||
# Uses LocalAI for threat analysis, CVE lookups, and filter suggestions
|
# Routes through AI Gateway for data classification and sovereignty compliance
|
||||||
|
|
||||||
|
# AI Gateway endpoint (handles classification, sanitization, provider routing)
|
||||||
|
AI_GATEWAY_API="http://127.0.0.1:4050/v1"
|
||||||
|
|
||||||
|
# Fallback to direct LocalAI if gateway unavailable
|
||||||
LOCALAI_API="http://127.0.0.1:8081/v1"
|
LOCALAI_API="http://127.0.0.1:8081/v1"
|
||||||
LOCALAI_MODEL="tinyllama-1.1b-chat-v1.0.Q4_K_M"
|
LOCALAI_MODEL="tinyllama-1.1b-chat-v1.0.Q4_K_M"
|
||||||
|
|
||||||
# Check if LocalAI is available
|
# Check if AI Gateway is available (preferred)
|
||||||
|
ai_gateway_available() {
|
||||||
|
wget -q -O /dev/null --timeout=2 "http://127.0.0.1:4050/health" 2>/dev/null
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if LocalAI is available (fallback)
|
||||||
localai_available() {
|
localai_available() {
|
||||||
wget -q -O /dev/null --timeout=2 "${LOCALAI_API}/models" 2>/dev/null
|
wget -q -O /dev/null --timeout=2 "${LOCALAI_API}/models" 2>/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
# Call LocalAI for completion
|
# Call AI via Gateway (handles classification/sanitization) or direct LocalAI
|
||||||
localai_complete() {
|
ai_complete() {
|
||||||
local prompt="$1"
|
local prompt="$1"
|
||||||
local max_tokens="${2:-512}"
|
local max_tokens="${2:-512}"
|
||||||
|
|
||||||
|
# Determine API endpoint (Gateway preferred, LocalAI fallback)
|
||||||
|
local api_endpoint="$AI_GATEWAY_API"
|
||||||
|
if ! ai_gateway_available; then
|
||||||
|
if localai_available; then
|
||||||
|
api_endpoint="$LOCALAI_API"
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
local request=$(cat <<EOF
|
local request=$(cat <<EOF
|
||||||
{"model":"$LOCALAI_MODEL","messages":[{"role":"system","content":"You are a cybersecurity analyst for SecuBox, an OpenWrt-based security appliance. Provide concise, actionable security analysis."},{"role":"user","content":"$prompt"}],"max_tokens":$max_tokens,"temperature":0.3}
|
{"model":"$LOCALAI_MODEL","messages":[{"role":"system","content":"You are a cybersecurity analyst for SecuBox, an OpenWrt-based security appliance. Provide concise, actionable security analysis."},{"role":"user","content":"$prompt"}],"max_tokens":$max_tokens,"temperature":0.3}
|
||||||
EOF
|
EOF
|
||||||
@ -21,13 +40,18 @@ EOF
|
|||||||
|
|
||||||
local response=$(echo "$request" | wget -q -O - --post-data=- \
|
local response=$(echo "$request" | wget -q -O - --post-data=- \
|
||||||
--header="Content-Type: application/json" \
|
--header="Content-Type: application/json" \
|
||||||
"${LOCALAI_API}/chat/completions" 2>/dev/null)
|
"${api_endpoint}/chat/completions" 2>/dev/null)
|
||||||
|
|
||||||
if [ -n "$response" ]; then
|
if [ -n "$response" ]; then
|
||||||
echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null
|
echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Backwards compatibility alias
|
||||||
|
localai_complete() {
|
||||||
|
ai_complete "$@"
|
||||||
|
}
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# AI TOOLS
|
# AI TOOLS
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
|
|||||||
@ -59,6 +59,10 @@ UCI config: `/etc/config/threat-analyst`
|
|||||||
config threat-analyst 'main'
|
config threat-analyst 'main'
|
||||||
option enabled '1'
|
option enabled '1'
|
||||||
option interval '300' # Analysis interval (seconds)
|
option interval '300' # Analysis interval (seconds)
|
||||||
|
|
||||||
|
# AI Gateway (preferred) - handles data classification & sovereignty
|
||||||
|
option ai_gateway_url 'http://127.0.0.1:4050'
|
||||||
|
# LocalAI (fallback) - direct connection if gateway unavailable
|
||||||
option localai_url 'http://127.0.0.1:8081'
|
option localai_url 'http://127.0.0.1:8081'
|
||||||
option localai_model 'tinyllama-1.1b-chat-v1.0.Q4_K_M'
|
option localai_model 'tinyllama-1.1b-chat-v1.0.Q4_K_M'
|
||||||
|
|
||||||
@ -71,6 +75,15 @@ config threat-analyst 'main'
|
|||||||
option max_rules_per_cycle '5' # Max rules per cycle
|
option max_rules_per_cycle '5' # Max rules per cycle
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## AI Gateway Integration
|
||||||
|
|
||||||
|
Threat Analyst routes AI requests through the AI Gateway for data sovereignty compliance:
|
||||||
|
|
||||||
|
1. **Gateway (preferred)**: Handles data classification and PII sanitization before routing to providers
|
||||||
|
2. **LocalAI (fallback)**: Direct on-device inference if gateway is unavailable
|
||||||
|
|
||||||
|
The AI Gateway ensures threat data (IPs, MACs, logs) stays LOCAL_ONLY and never leaves the device.
|
||||||
|
|
||||||
## LuCI Dashboard
|
## LuCI Dashboard
|
||||||
|
|
||||||
Navigate to: **SecuBox → Security → Threat Analyst**
|
Navigate to: **SecuBox → Security → Threat Analyst**
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
config threat-analyst 'main'
|
config threat-analyst 'main'
|
||||||
option enabled '1'
|
option enabled '1'
|
||||||
option interval '300'
|
option interval '300'
|
||||||
|
# AI Gateway (preferred) - handles classification, sanitization, provider routing
|
||||||
|
option ai_gateway_url 'http://127.0.0.1:4050'
|
||||||
|
# LocalAI (fallback) - direct connection if gateway unavailable
|
||||||
option localai_url 'http://127.0.0.1:8081'
|
option localai_url 'http://127.0.0.1:8081'
|
||||||
option localai_model 'tinyllama-1.1b-chat-v1.0.Q4_K_M'
|
option localai_model 'tinyllama-1.1b-chat-v1.0.Q4_K_M'
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,7 @@ uci_get() { uci -q get "${CONFIG}.$1"; }
|
|||||||
load_config() {
|
load_config() {
|
||||||
enabled=$(uci_get main.enabled)
|
enabled=$(uci_get main.enabled)
|
||||||
interval=$(uci_get main.interval)
|
interval=$(uci_get main.interval)
|
||||||
|
ai_gateway_url=$(uci_get main.ai_gateway_url)
|
||||||
localai_url=$(uci_get main.localai_url)
|
localai_url=$(uci_get main.localai_url)
|
||||||
localai_model=$(uci_get main.localai_model)
|
localai_model=$(uci_get main.localai_model)
|
||||||
auto_apply_mitmproxy=$(uci_get main.auto_apply_mitmproxy)
|
auto_apply_mitmproxy=$(uci_get main.auto_apply_mitmproxy)
|
||||||
@ -60,6 +61,16 @@ load_config() {
|
|||||||
[ -z "$interval" ] && interval=300
|
[ -z "$interval" ] && interval=300
|
||||||
[ -z "$min_confidence" ] && min_confidence=70
|
[ -z "$min_confidence" ] && min_confidence=70
|
||||||
[ -z "$max_rules" ] && max_rules=5
|
[ -z "$max_rules" ] && max_rules=5
|
||||||
|
[ -z "$ai_gateway_url" ] && ai_gateway_url="http://127.0.0.1:4050"
|
||||||
|
|
||||||
|
# Select AI endpoint (prefer Gateway, fallback to LocalAI)
|
||||||
|
if wget -q -O /dev/null --timeout=2 "${ai_gateway_url}/health" 2>/dev/null; then
|
||||||
|
ai_url="${ai_gateway_url}/v1"
|
||||||
|
ai_provider="gateway"
|
||||||
|
else
|
||||||
|
ai_url="${localai_url}/v1"
|
||||||
|
ai_provider="localai"
|
||||||
|
fi
|
||||||
|
|
||||||
mkdir -p "$STATE_DIR"
|
mkdir -p "$STATE_DIR"
|
||||||
}
|
}
|
||||||
@ -74,17 +85,28 @@ cmd_status() {
|
|||||||
echo ""
|
echo ""
|
||||||
echo "Enabled: $([ "$enabled" = "1" ] && echo "Yes" || echo "No")"
|
echo "Enabled: $([ "$enabled" = "1" ] && echo "Yes" || echo "No")"
|
||||||
echo "Interval: ${interval}s"
|
echo "Interval: ${interval}s"
|
||||||
echo "LocalAI: $localai_url"
|
|
||||||
echo "Model: $localai_model"
|
echo "Model: $localai_model"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Check LocalAI availability
|
# Check AI Gateway availability (preferred)
|
||||||
|
echo "AI Gateway: $ai_gateway_url"
|
||||||
|
if wget -q -O /dev/null --timeout=2 "${ai_gateway_url}/health" 2>/dev/null; then
|
||||||
|
echo "Gateway Status: ONLINE"
|
||||||
|
else
|
||||||
|
echo "Gateway Status: OFFLINE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check LocalAI availability (fallback)
|
||||||
|
echo "LocalAI: $localai_url"
|
||||||
if wget -q -O /dev/null --timeout=2 "${localai_url}/v1/models" 2>/dev/null; then
|
if wget -q -O /dev/null --timeout=2 "${localai_url}/v1/models" 2>/dev/null; then
|
||||||
echo "LocalAI Status: ONLINE"
|
echo "LocalAI Status: ONLINE"
|
||||||
else
|
else
|
||||||
echo "LocalAI Status: OFFLINE"
|
echo "LocalAI Status: OFFLINE"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Active AI: $ai_provider ($ai_url)"
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Auto-apply:"
|
echo "Auto-apply:"
|
||||||
echo " mitmproxy: $([ "$auto_apply_mitmproxy" = "1" ] && echo "Yes" || echo "No (queued)")"
|
echo " mitmproxy: $([ "$auto_apply_mitmproxy" = "1" ] && echo "Yes" || echo "No (queued)")"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
# SecuBox Threat Analyst - Analyzer Module
|
# SecuBox Threat Analyst - Analyzer Module
|
||||||
# Collects and analyzes threats using LocalAI
|
# Collects and analyzes threats using AI Gateway (or LocalAI fallback)
|
||||||
|
|
||||||
# =============================================================================
|
# =============================================================================
|
||||||
# HELPER FUNCTIONS
|
# HELPER FUNCTIONS
|
||||||
@ -143,9 +143,9 @@ merge_json_arrays() {
|
|||||||
analyze_threats() {
|
analyze_threats() {
|
||||||
local threats="$1"
|
local threats="$1"
|
||||||
|
|
||||||
# Check LocalAI availability
|
# Check AI availability (ai_url set by load_config: Gateway or LocalAI)
|
||||||
if ! wget -q -O /dev/null --timeout=3 "${localai_url}/v1/models" 2>/dev/null; then
|
if ! wget -q -O /dev/null --timeout=3 "${ai_url}/models" 2>/dev/null; then
|
||||||
log_warn "LocalAI not available at $localai_url"
|
log_warn "AI not available at $ai_url"
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -176,7 +176,7 @@ Provide actionable, specific recommendations. Format filter patterns as code sni
|
|||||||
|
|
||||||
local response=$(echo "$request" | wget -q -O - --post-data=- \
|
local response=$(echo "$request" | wget -q -O - --post-data=- \
|
||||||
--header="Content-Type: application/json" \
|
--header="Content-Type: application/json" \
|
||||||
"${localai_url}/v1/chat/completions" 2>/dev/null)
|
"${ai_url}/chat/completions" 2>/dev/null)
|
||||||
|
|
||||||
if [ -n "$response" ]; then
|
if [ -n "$response" ]; then
|
||||||
echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null
|
echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null
|
||||||
|
|||||||
@ -207,9 +207,9 @@ apply_all_pending() {
|
|||||||
chat_query() {
|
chat_query() {
|
||||||
local query="$1"
|
local query="$1"
|
||||||
|
|
||||||
# Check LocalAI
|
# Check AI availability (ai_url set by load_config: Gateway or LocalAI)
|
||||||
if ! wget -q -O /dev/null --timeout=3 "${localai_url}/v1/models" 2>/dev/null; then
|
if ! wget -q -O /dev/null --timeout=3 "${ai_url}/models" 2>/dev/null; then
|
||||||
echo '{"error":"LocalAI not available"}'
|
echo '{"error":"AI not available"}'
|
||||||
return 1
|
return 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -232,7 +232,7 @@ EOF
|
|||||||
|
|
||||||
local response=$(echo "$request" | wget -q -O - --post-data=- \
|
local response=$(echo "$request" | wget -q -O - --post-data=- \
|
||||||
--header="Content-Type: application/json" \
|
--header="Content-Type: application/json" \
|
||||||
"${localai_url}/v1/chat/completions" 2>/dev/null)
|
"${ai_url}/chat/completions" 2>/dev/null)
|
||||||
|
|
||||||
if [ -n "$response" ]; then
|
if [ -n "$response" ]; then
|
||||||
local content=$(echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null)
|
local content=$(echo "$response" | jsonfilter -e '@.choices[0].message.content' 2>/dev/null)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user