- Posted on
- • Artificial Intelligence
Artificial Intelligence Log Analysis for Security
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
AI-Powered Log Analysis for Security (with Bash-Friendly Workflows)
Attackers don’t knock—they rattle your doors until one opens. Your logs already record the story. The problem is volume: thousands to millions of lines per day, per host. Artificial Intelligence (AI) can turn that torrent into timely, actionable insights by finding patterns and anomalies you’d miss by eye or with static rules.
In this article you’ll:
Understand why AI belongs in your Linux log workflow
Set up a small, local toolkit (no cloud required)
Run a quick anomaly detector for SSH brute-forcing
Reduce log noise with template mining
Wire it up to simple alerts
All examples are shell- and ops-friendly, with installation instructions for apt, dnf, and zypper.
Why use AI for log analysis?
Pattern recognition at scale: Machine learning can quickly find recurring structures in messy, semi-structured logs.
Unsupervised detection: Even with no labels, algorithms like Isolation Forest can flag “weird” behavior—e.g., an IP behaving unlike others.
Noise reduction: Template mining collapses near-duplicate messages into digestible patterns so analysts focus on what changed.
Local and scriptable: You can run everything on a single box, under a Linux user, and glue it together with Bash.
1) Prepare your toolbox
We’ll use Python (for ML), pip/venv (to isolate packages), and jq (for JSON in Bash).
Install prerequisites:
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y python3 python3-pip python3-venv jq build-essential python3-dev
- Fedora/RHEL/CentOS (dnf):
sudo dnf install -y python3 python3-pip jq gcc python3-devel
- openSUSE/SLES (zypper):
sudo zypper refresh
sudo zypper install -y python3 python3-pip jq gcc python3-devel
Create a Python virtual environment:
python3 -m venv ~/.venvs/ailogs
source ~/.venvs/ailogs/bin/activate
pip install --upgrade pip
pip install pandas scikit-learn drain3
Ensure your user can read the relevant logs. On systemd systems, journalctl works via sudo or by adding your user to the systemd-journal group:
sudo usermod -aG systemd-journal "$USER"
# Log out and back in for group change to take effect.
For file-based logs (e.g., /var/log/auth.log, /var/log/secure), make sure you have read permission (typically requires sudo).
2) Quick-win: Detect SSH anomalies with Isolation Forest
Brute force and credential-stuffing attempts show up clearly in SSH auth logs. We’ll parse recent SSH logs, extract per-IP features, and flag suspicious ones.
Create detect_ssh_anomalies.py:
#!/usr/bin/env python3
import sys, re, math
from collections import defaultdict
from datetime import datetime
import pandas as pd
from sklearn.ensemble import IsolationForest
ip_re = re.compile(r'(\d{1,3}\.){3}\d{1,3}')
failed_re = re.compile(r'Failed password')
invalid_user_re = re.compile(r'Invalid user')
accepted_re = re.compile(r'Accepted (password|publickey)')
user_re = re.compile(r'for(?: invalid user)? ([a-zA-Z0-9._-]+)')
# Feature store per IP
stats = defaultdict(lambda: {
'failed': 0,
'invalid_user': 0,
'accepted': 0,
'users': set()
})
for line in sys.stdin:
ip_m = ip_re.search(line)
if not ip_m:
continue
ip = ip_m.group(0)
if failed_re.search(line):
stats[ip]['failed'] += 1
if invalid_user_re.search(line):
stats[ip]['invalid_user'] += 1
if accepted_re.search(line):
stats[ip]['accepted'] += 1
u = user_re.search(line)
if u:
stats[ip]['users'].add(u.group(1))
# Build feature frame
rows = []
for ip, s in stats.items():
rows.append({
'ip': ip,
'failed': s['failed'],
'invalid_user': s['invalid_user'],
'accepted': s['accepted'],
'distinct_users': len(s['users']),
'fail_to_accept_ratio': (s['failed'] / (s['accepted']+1)),
'attacky_score': s['failed'] + 2*s['invalid_user'] + 0.5*s['distinct_users']
})
if not rows:
sys.exit(0)
df = pd.DataFrame(rows)
# Train simple IsolationForest (unsupervised)
model = IsolationForest(
n_estimators=200,
contamination=0.05, # tune to your environment
random_state=42
)
features = df[['failed','invalid_user','accepted','distinct_users','fail_to_accept_ratio','attacky_score']]
model.fit(features)
pred = model.predict(features) # -1 anomalous, 1 normal
score = model.decision_function(features) # lower is more anomalous
df['iforest_pred'] = pred
df['iforest_score'] = score
# Sort by most anomalous (lowest score) and print top
out = df.sort_values('iforest_score').reset_index(drop=True)
# Pretty print CSV to allow easy Bash parsing
print("ip,failed,invalid_user,accepted,distinct_users,fail_to_accept_ratio,attacky_score,iforest_pred,iforest_score")
for _, r in out.iterrows():
print(f"{r.ip},{int(r.failed)},{int(r.invalid_user)},{int(r.accepted)},{int(r.distinct_users)},"
f"{r.fail_to_accept_ratio:.3f},{r.attacky_score:.3f},{int(r.iforest_pred)},{r.iforest_score:.6f}")
Make it executable:
chmod +x detect_ssh_anomalies.py
Run it against the last 24 hours of SSH logs (systemd-journald):
sudo journalctl -u ssh -S -24h --no-pager | ./detect_ssh_anomalies.py
# If your unit is sshd (Fedora/RHEL):
sudo journalctl -u sshd -S -24h --no-pager | ./detect_ssh_anomalies.py
Or against file-based logs:
sudo cat /var/log/auth.log | ./detect_ssh_anomalies.py # Debian/Ubuntu
sudo cat /var/log/secure | ./detect_ssh_anomalies.py # RHEL/Fedora/SUSE
Interpretation:
iforest_pred = -1means “anomalous”Lower
iforest_score= more suspiciousUse
attacky_scoreand/oriforest_scoreas simple thresholds for alerting
Schedule daily with a systemd timer or cron to get a shortlist of suspect IPs for blocking or further triage.
3) Reduce noise with log template mining (Drain3)
Logs are notoriously repetitive with minor differences (IDs, IPs). Template mining clusters similar lines into templates so you can spot “new” or “rare” patterns quickly.
We’ll use Drain3 (installed earlier) to read logs from stdin and print new/changed templates.
Create template_miner.py:
#!/usr/bin/env python3
import sys
from drain3 import TemplateMiner
from drain3.template_miner_config import TemplateMinerConfig
config = TemplateMinerConfig()
config.load_default()
# Tweak if needed:
# config.drain_sim_th = 0.4 # similarity threshold
# config.drain_depth = 5
miner = TemplateMiner(config=config)
seen_templates = {}
for line in sys.stdin:
line = line.strip()
if not line:
continue
r = miner.add_log_message(line)
tid = r["cluster_id"]
tmpl = r["template_mined"]
occ = r["cluster_size"]
# Print when a new template forms or grows beyond a small threshold
if tid not in seen_templates:
seen_templates[tid] = occ
print(f"NEW_TEMPLATE id={tid} size={occ} tmpl={tmpl}")
else:
prev = seen_templates[tid]
if occ in (2, 5, 10, 50) or occ % 100 == 0:
print(f"TEMPLATE_UPDATE id={tid} size={occ} tmpl={tmpl}")
seen_templates[tid] = occ
Make it executable:
chmod +x template_miner.py
Run it on, say, NGINX access logs in real-time:
sudo tail -F /var/log/nginx/access.log | ./template_miner.py
What to look for:
NEW_TEMPLATE indicates previously unseen events—often worthy of attention
Rapid TEMPLATE_UPDATE growth may indicate an emerging issue or attack pattern
Use this to build suppression rules or to focus on outliers while compressing the rest
4) Turn insights into alerts (Bash + curl + jq)
Send anomalies to Slack or any webhook once thresholds are tripped.
Example: Alert top anomalous SSH IPs if any are found:
# Export your Slack Incoming Webhook URL first
# export SLACK_WEBHOOK_URL="https://hooks.slack.com/services/XXX/YYY/ZZZ"
suspicious=$(sudo journalctl -u ssh -S -24h --no-pager \
| ./detect_ssh_anomalies.py \
| awk -F, 'NR>1 && $8=="-1"{print}' \
| head -n 10)
if [ -n "$suspicious" ]; then
payload=$(jq -n --arg text "SSH anomalies detected:\n$suspicious" '{text:$text}')
curl -s -X POST -H 'Content-type: application/json' \
--data "$payload" "$SLACK_WEBHOOK_URL" >/dev/null && echo "Alert sent."
fi
Optional: Summarize with a local LLM for human-friendly context. If you want to try this, install Ollama (single script):
curl -fsSL https://ollama.com/install.sh | sh
# Then run a small model, e.g., mistral
ollama pull mistral
Then:
summary=$(printf "%s" "$suspicious" | ollama run mistral "Summarize these SSH anomalies for a SOC analyst:")
echo "$summary"
Keep this optional—don’t block alerts on LLM availability.
Real-world pointers
Calibrate contamination: Start with
contamination=0.05(5%) and adjust until you get 1–10 high-quality anomalies per day per host.Separate by service: Train per log type/service (SSH vs. web vs. DB) for crisper signals.
Baseline by time/window: Nightly jobs vs. business hours look different. Consider training by window or feeding “hour” as a feature.
Keep a blocklist/allowlist: Pipe confirmed bad IPs into firewall automation, and maintain an allowlist for known scanners or maintenance hosts.
Version your pipelines: Save your scripts/config in git; note when you change thresholds or features.
Conclusion and Next Steps
You don’t need a massive SIEM to get value from AI in log analysis. With a few Bash-friendly scripts and open-source Python libraries, you can:
Flag suspicious SSH sources
Collapse repetitive logs into readable templates
Ship only the important stuff to your eyes (or a chat channel)
Next steps:
Put the SSH anomaly job behind a systemd timer
Add parsers for web server logs and DB audit logs
Expand features (geo-IP, ASN, time-of-day) for stronger detection
Feed outputs into your existing SIEM or ticketing system
Security thrives on fast feedback. Start with the SSH detector today, tune it over a week, and you’ll have an immediately useful, locally controlled AI assistant for your logs.