- Posted on
- • Artificial Intelligence
Artificial Intelligence Security Dashboards
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Build an AI-Powered Security Dashboard on Linux (with nothing but Bash and containers)
If your SSH logs suddenly explode at 3 a.m., how fast can you see it, explain it, and react? AI-assisted security dashboards turn raw logs into live, actionable insights—so spikes, anomalies, and stealthy patterns show up before they become incidents.
This guide shows you how to stand up a lightweight, AI-ready security dashboard on any modern Linux distro using Bash and containers. You’ll ingest auth logs, visualize them, and enable anomaly detection—without locking into proprietary stacks. Everything runs locally with Podman, and you can tear it down when you’re done.
What you’ll get:
A compact stack: Fluent Bit (log shipper) + OpenSearch (storage/ML) + OpenSearch Dashboards (UI)
Real-time SSH security visibility
A simple AI detector to flag anomalous failed logins
Note: We deliberately disable built-in security for a quick lab setup. Do not expose this stack to the internet. For production, enable TLS and authentication.
Why AI Security Dashboards are worth your time
You can’t defend what you can’t see: Centralizing telemetry (auth logs, sudo, kernel audit, container events) gives you an immediate view of your risk surface.
AI spots the weird stuff: Thresholds catch volume spikes. Anomaly detection catches novel behavior—like “a little too many failures from an unusual ASN during an odd hour.”
Faster MTTR: A clean dashboard + AI signals make it easier to answer: What changed? How bad is it? Where’s it coming from?
Prerequisites: Minimal tools you can install in one minute
We’ll use Podman for containers and jq for JSON parsing. Install with your package manager of choice:
Debian/Ubuntu (apt):
sudo apt update sudo apt install -y podman jqFedora/RHEL/CentOS (dnf):
sudo dnf -y install podman jqopenSUSE/SLES (zypper):
sudo zypper refresh sudo zypper install -y podman jq
Verify:
podman --version
jq --version
Core build: From logs to AI signals in 5 steps
1) Decide what to watch first (keep it lean)
Start with signals that correlate strongly with intrusions:
SSH and sudo activity (/var/log/auth.log on Debian/Ubuntu; /var/log/secure on Fedora/RHEL/SUSE)
Authentication failures and lockouts
New/modified privileged accounts
Unexpected outbound connections (optional next step)
We’ll focus on SSH failures to keep the example concrete.
2) Stand up the dashboard stack (OpenSearch + Dashboards + Fluent Bit)
Create a working directory and a Fluent Bit config that tails SSH logs and adds a derived field to support anomaly detection.
Create fluent-bit.conf:
cat > fluent-bit.conf <<'EOF'
[SERVICE]
Flush 1
Daemon Off
Log_Level info
# Debian/Ubuntu
[INPUT]
Name tail
Path /var/log/auth.log
Tag ssh.auth
Refresh_Interval 5
Skip_Long_Lines On
# Fedora/RHEL/SUSE
[INPUT]
Name tail
Path /var/log/secure
Tag ssh.secure
Refresh_Interval 5
Skip_Long_Lines On
# Derive a numeric field for failed SSH logins (for anomaly detection)
[FILTER]
Name lua
Match ssh.*
Script /fluent-bit/etc/classify.lua
Call classify
# Add host metadata
[FILTER]
Name modify
Match *
Add pipeline ai-sec
Add stack opensearch
# Ship to OpenSearch using Elasticsearch-compatible output
[OUTPUT]
Name es
Match *
Host localhost
Port 9200
Logstash_Format On
Logstash_Prefix auth
Replace_Dots On
EOF
Create classify.lua to tag failed SSH attempts:
cat > classify.lua <<'EOF'
function classify(tag, ts, record)
local msg = record["log"]
if msg and string.find(msg, "Failed password") then
record["failed_ssh"] = 1
else
record["failed_ssh"] = 0
end
return 1, ts, record
end
EOF
Start a Podman pod and the three containers inside it:
# Create a shared network/ports space
podman pod create --name ai-sec --publish 9200:9200 --publish 5601:5601
# OpenSearch (single-node, security disabled for local demo)
podman run -d --name opensearch --pod ai-sec \
-e "discovery.type=single-node" \
-e "DISABLE_SECURITY_PLUGIN=true" \
-e "DISABLE_INSTALL_DEMO_CONFIG=true" \
-e "OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m" \
--ulimit memlock=-1:-1 \
--ulimit nofile=65536:65536 \
opensearchproject/opensearch:2
# OpenSearch Dashboards
podman run -d --name opensearch-dashboards --pod ai-sec \
-e "OPENSEARCH_HOSTS=['http://localhost:9200']" \
opensearchproject/opensearch-dashboards:2
# Fluent Bit (reads host logs and ships to OpenSearch)
podman run -d --name fluent-bit --pod ai-sec \
-v "$PWD/fluent-bit.conf":/fluent-bit/etc/fluent-bit.conf:ro \
-v "$PWD/classify.lua":/fluent-bit/etc/classify.lua:ro \
-v /var/log:/var/log:ro \
fluent/fluent-bit:2
Check health:
podman ps --pod
curl -s http://localhost:9200 | jq
curl -s http://localhost:9200/_cat/indices?v
Open the UI at:
- OpenSearch Dashboards: http://localhost:5601
First-time UI step: Create an index pattern “auth-*” with time field “@timestamp” so you can visualize ingested logs.
Tip: Generate a few failed logins to see data:
# From another terminal or host, attempt a wrong password a few times:
ssh wronguser@your-host
3) Turn on an anomaly detector for SSH failures
We’ll use OpenSearch’s Anomaly Detection (AD) to model the normal rate of failed SSH attempts and flag outliers.
Create a detector:
cat > detector.json <<'EOF'
{
"name": "ssh-failed-login-anomaly",
"description": "Detect anomalous spikes of failed SSH logins",
"time_field": "@timestamp",
"indices": ["auth-*"],
"feature_attributes": [
{
"feature_name": "failed_ssh_sum",
"feature_enabled": true,
"aggregation_query": {
"failed_ssh_sum": { "sum": { "field": "failed_ssh" } }
}
}
],
"detection_interval": { "period": { "interval": 1, "unit": "MINUTES" } },
"window_delay": { "period": { "interval": 1, "unit": "MINUTES" } }
}
EOF
# Create the detector
DET_ID=$(curl -s -H 'content-type: application/json' \
-X POST http://localhost:9200/_plugins/_anomaly_detection/detectors \
-d @detector.json | jq -r '._id')
echo "Detector ID: $DET_ID"
# Start the detector job
curl -s -X POST "http://localhost:9200/_plugins/_anomaly_detection/detectors/$DET_ID/_start"
Confirm it’s running and check results after a couple of minutes:
curl -s "http://localhost:9200/_plugins/_anomaly_detection/detectors/$DET_ID/_stats" | jq
curl -s "http://localhost:9200/_plugins/_anomaly_detection/detectors/$DET_ID/_results" | jq
In OpenSearch Dashboards, open the Anomaly Detection app to visualize anomaly grades over time. Trigger a small brute-force on your lab host to see the spike.
4) Make the data useful (quick-win visualizations)
In OpenSearch Dashboards, create:
A time series of failed SSH logins (search: “Failed password”), split by source IP.
A table of top source IPs and usernames on “auth-*”.
A single-value visualization for “failed_ssh_sum” with last 15 minutes.
A dashboard that puts these together plus the anomaly line chart.
This gives you both raw counts and an AI signal in one view.
5) Hardening and next steps (don’t skip)
Enable security on OpenSearch and Dashboards:
- Turn off DISABLE_SECURITY_PLUGIN, configure users/roles, and TLS.
Persist data:
- Mount volumes for OpenSearch data and snapshots. Example:
-v /srv/opensearch-data:/usr/share/opensearch/dataAdd more signals:
- sudo logs, auditd events, container runtime logs, and reverse-proxy access logs.
Alerting:
- Use OpenSearch Notifications or integrate with webhooks to Slack/Matrix/Email when anomaly grade > threshold.
Threat intel:
- Enrich source IPs against blocklists or ASN databases to add context to dashboards.
Real-world example: Catching a subtle brute-force
What you see: A small but unusual off-hours bump in failed_ssh_sum with a high anomaly grade.
Drill-down: Top source IP points to an untrusted ASN. The failures are spread across many usernames (spray).
Action: Temporarily geofence or rate-limit SSH, tighten fail2ban, and investigate any successful logins adjacent to the spike.
Troubleshooting
No logs in “auth-*”:
- Ensure your system writes to /var/log/auth.log (Debian/Ubuntu) or /var/log/secure (Fedora/RHEL/SUSE).
- Check Fluent Bit logs:
podman logs -f fluent-bitDetector shows no data:
- Wait a couple of minutes for buckets to fill.
- Verify documents contain failed_ssh fields:
curl -s 'http://localhost:9200/auth-*/_search?q=failed_ssh:1&size=5' | jqResource limits:
- If OpenSearch restarts, increase memory:
-e "OPENSEARCH_JAVA_OPTS=-Xms1g -Xmx1g"- Ensure memlock ulimit is set as in the run command.
Cleanup
When you’re done experimenting:
podman pod stop ai-sec
podman pod rm -f ai-sec
Conclusion and Call to Action
You just stood up an AI-enabled security dashboard on Linux using only Bash and containers. You can now see SSH activity in real time and get anomaly scores that spotlight unusual behavior—without a SaaS bill or heavyweight agents.
Your next steps:
Add sudo, auditd, and web access logs to the pipeline.
Secure the stack (TLS, auth) and persist data.
Generalize the Lua approach to mark other patterns (e.g., “sudo failure”, “password change”, “new key added”).
Wire notifications so anomalies page you before attackers escalate.
Security is a visibility problem first. Make the invisible obvious—then automate the response.