- Posted on
- • Artificial Intelligence
Artificial Intelligence Security Projects
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
4 Practical AI Security Projects You Can Build on Linux (with Bash)
Artificial intelligence is now a core part of production systems—from fraud detection to code assistants to recommendation engines. But as AI goes mainstream, attackers follow. The challenge: how do you raise the security bar for AI systems using tools you already know—Linux, Bash, and a handful of open-source utilities?
This article gives you four hands-on, Linux-friendly AI security projects you can implement quickly. Each one is production-relevant, uses transparent Bash/POSIX tooling, and helps you reduce risk where it matters most: data, models, infrastructure, and secrets.
Note: These projects are meant for defensive, ethical use on systems you own or are authorized to manage.
Project 1: Rapid Log Anomaly Detection for SSH Using Python + Bash
Problem: How do you detect unusual authentication patterns (e.g., brute-force, odd hours, unfamiliar source IP ranges) before they become incidents?
Approach: Extract SSH auth logs with Bash, turn them into simple features, and run an Isolation Forest (unsupervised) to flag anomalies.
Install prerequisites
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y python3 python3-venv python3-pip jq
- Fedora/RHEL (dnf):
sudo dnf install -y python3 python3-pip jq
- openSUSE (zypper):
sudo zypper install -y python3 python3-pip jq
Extract features from logs
This script normalizes across Debian-like (/var/log/auth.log) and RHEL-like (/var/log/secure) systems, then emits a CSV with a few numeric features.
#!/usr/bin/env bash
set -euo pipefail
LOGFILE=""
if [[ -f /var/log/auth.log ]]; then
LOGFILE="/var/log/auth.log"
elif [[ -f /var/log/secure ]]; then
LOGFILE="/var/log/secure"
else
echo "No auth log found."
exit 1
fi
# Last 24h lines containing SSH login attempts
grep -E "sshd.*(Failed password|Accepted password|Accepted publickey)" "$LOGFILE" | \
awk '
function ip2oct(ip, n, i, a) {
n = split(ip,a,/\./);
if (n!=4) return -1;
return a[1]; # crude but useful to bucket by first octet
}
{
# Example lines vary; capture timestamp, user, ip, status
# Try to find an IP address:
match($0, /([0-9]{1,3}\.){3}[0-9]{1,3}/, m);
ip = (m[0] ? m[0] : "0.0.0.0");
status = ($0 ~ /Failed password/ ? 1 : 0); # 1 = failed, 0 = success
user = "unknown";
for (i=1;i<=NF;i++) {
if ($i=="for" && (i+1)<=NF) { user=$(i+1); }
}
# Hour extraction (assumes syslog ts "Mon DD HH:MM:SS")
hour = 0;
match($0, /[A-Z][a-z]{2} +[0-9]{1,2} +([0-9]{2}):[0-9]{2}:[0-9]{2}/, t);
if (t[1]!="") { hour=t[1]; }
oct = ip2oct(ip);
# CSV: hour,user,ip_first_octet,status
print hour","user","oct","status
}
' > /tmp/ssh_features.csv
echo "Wrote features to /tmp/ssh_features.csv"
head -5 /tmp/ssh_features.csv
Train and score anomalies
Create a Python virtual environment and run a small script.
python3 -m venv ~/.venvs/ai-sec && source ~/.venvs/ai-sec/bin/activate
pip install --upgrade pip
pip install scikit-learn pandas
#!/usr/bin/env python3
# file: score_anomalies.py
import pandas as pd
from sklearn.ensemble import IsolationForest
df = pd.read_csv("/tmp/ssh_features.csv", header=None,
names=["hour","user","ip_first_octet","status"])
# Encode categorical "user"
df["user_code"] = df["user"].astype("category").cat.codes
X = df[["hour","ip_first_octet","status","user_code"]].fillna(0)
model = IsolationForest(n_estimators=150, contamination=0.03, random_state=42)
model.fit(X)
df["score"] = model.decision_function(X)
df["is_anomaly"] = model.predict(X) == -1
anomalies = df[df["is_anomaly"]].sort_values("score")
print(anomalies.head(10).to_string(index=False))
Run it:
python3 score_anomalies.py
Actionable next step: cron this daily, alert on anomalies via logger/mail, and feed results into your SIEM.
Project 2: Dataset & Model Integrity Guard (auditd + inotify + minisign)
Problem: Model and dataset tampering is a real threat. You need visibility and integrity checks.
Approach:
Watch critical directories for writes with auditd.
Maintain signed SHA256 manifests of your datasets/models with minisign.
Trigger alerts on unexpected changes using inotify.
Install prerequisites
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y auditd inotify-tools minisign coreutils
- Fedora/RHEL (dnf):
sudo dnf install -y audit inotify-tools minisign coreutils
- openSUSE (zypper):
sudo zypper install -y audit inotify-tools minisign coreutils
Set audit rules
Create rules to monitor your AI asset directories:
sudo mkdir -p /opt/ml/{data,models}
sudo bash -c 'cat >/etc/audit/rules.d/ai.rules' <<'EOF'
-w /opt/ml/data -p wa -k ml-data
-w /opt/ml/models -p wa -k ml-models
EOF
sudo augenrules --load || sudo service auditd restart
Verify logs are flowing:
sudo ausearch -k ml-models --start recent
Baseline and sign your artifacts
cd /opt/ml/models
find . -type f -print0 | xargs -0 sha256sum | sort -k2 > manifest.sha256
# One-time key generation (store keys securely!)
minisign -G -p /root/model_manifest.pub -s /root/model_manifest.sec
# Sign the manifest
minisign -Sm -s /root/model_manifest.sec -m manifest.sha256
Continuous watch with inotify
This script re-hashes on changes and verifies signature. If verification fails, it logs a high-priority message.
#!/usr/bin/env bash
set -euo pipefail
DIR="/opt/ml/models"
PUB="/root/model_manifest.pub"
inotifywait -m -r -e modify,create,delete,move "$DIR" | while read -r _; do
TMP="$(mktemp)"
find "$DIR" -type f -print0 | xargs -0 sha256sum | sort -k2 > "$TMP"
if minisign -Vm "$TMP" -p "$PUB" >/dev/null 2>&1; then
logger -p auth.info "AI integrity: OK for $DIR"
else
logger -p auth.alert "AI integrity: MISMATCH in $DIR (possible tampering)"
fi
rm -f "$TMP"
done
Run as a systemd service to make it persistent, and route auth.alert to your SOC tooling.
Real-world note: This pattern has caught “accidental” overwrites in MLOps pipelines as well as suspicious timestamp anomalies.
Project 3: Rootless, TLS-Terminated Model Serving with Podman + Nginx
Problem: Model APIs often ship as containers that run as root, accept oversized payloads, and expose internals—great for attackers.
Approach: Run your model server rootless with Podman, terminate TLS with Nginx, and enforce sane limits.
Install prerequisites
- Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y podman nginx openssl
- Fedora/RHEL (dnf):
sudo dnf install -y podman nginx openssl
- openSUSE (zypper): ``> sudo zypper install -y podman nginx openssl
### Minimal non-root API container
Create a FastAPI server that echoes model metadata (placeholder for your real model).
`Dockerfile`:
FROM python:3.11-slim
Create non-root user
RUN useradd -m -u 10001 appuser WORKDIR /app
COPY app/ /app/ RUN pip install --no-cache-dir fastapi uvicorn
USER 10001 EXPOSE 8000 CMD ["uvicorn","main:app","--host","0.0.0.0","--port","8000","--proxy-headers"]
`app/main.py`:
from fastapi import FastAPI, HTTPException, Request
app = FastAPI()
@app.get("/healthz") def healthz(): return {"status": "ok"}
@app.post("/infer") async def infer(request: Request): body = await request.body() if len(body) > 1_000_000: # 1MB server-side guardrail raise HTTPException(status_code=413, detail="Payload too large") # Replace with real model inference return {"ok": True, "received_bytes": len(body)}
Build and run rootless:
podman build -t ai-api . podman run --rm -p 127.0.0.1:8000:8000 ai-api
### Generate a dev TLS cert and configure Nginx
Generate a self-signed cert for localhost (use real certs in prod):
sudo mkdir -p /etc/nginx/tls sudo openssl req -x509 -newkey rsa:4096 -nodes -days 365 \ -keyout /etc/nginx/tls/key.pem -out /etc/nginx/tls/cert.pem \ -subj "/CN=localhost"
Nginx site config (limits + reverse proxy):
sudo bash -c 'cat >/etc/nginx/conf.d/ai_api.conf' <<'EOF' limit_req_zone $binary_remote_addr zone=ml:10m rate=5r/s;
server { listen 443 ssl; server_name localhost;
ssl_certificate /etc/nginx/tls/cert.pem; ssl_certificate_key /etc/nginx/tls/key.pem;
client_max_body_size 1m; add_header X-Content-Type-Options nosniff always; add_header Referrer-Policy no-referrer always;
location / { limit_req zone=ml burst=10 nodelay; proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $remote_addr; proxy_http_version 1.1; } } EOF
sudo nginx -t && sudo systemctl reload nginx
Test:
curl -k https://localhost/healthz
Key guardrails you just added:
- Rootless container reduces blast radius.
- TLS by default, no plaintext traffic.
- Strict request size and rate limits to throttle abuse.
---
## Project 4: Secretless Training and Serving with pass + age
Problem: API tokens, database passwords, and keys often leak into training scripts, notebooks, or containers.
Approach: Keep secrets out of repos and images. Store them encrypted with age, load them into env only at execution time.
### Install prerequisites
- Debian/Ubuntu (apt):
sudo apt update sudo apt install -y pass age gnupg
- Fedora/RHEL (dnf):
sudo dnf install -y pass age gnupg2
- openSUSE (zypper):
sudo zypper install -y pass age gpg2
### Create an age key and encrypt secrets
mkdir -p ~/.config/age age-keygen -o ~/.config/age/key.txt echo "Public key:" grep -m1 "public key" ~/.config/age/key.txt | sed 's/# public key: //'
Encrypt a KEY=VALUE file (example uses a Hugging Face token):
mkdir -p ~/secrets cat > ~/secrets/ml.env <<'EOF' HF_API_TOKEN=hf_xxx DB_PASSWORD=supersecret EOF
Replace RECIPIENT with your printed public key (age1...)
age -r RECIPIENT -o ~/secrets/ml.env.age ~/secrets/ml.env shred -u ~/secrets/ml.env # remove plaintext
Load secrets only when you run:
set -a source <(age -d -i ~/.config/age/key.txt ~/secrets/ml.env.age) set +a
Now env vars are present only in this shell
python train.py ```
Tip: In CI or systemd services, decrypt to a protected tmpfs and avoid writing plaintext to disk.
Why These Projects Work
They reduce risk at natural choke points: auth logs (detection), file system changes (integrity), network edge (hardening), and secret handling (exposure).
They’re minimal-dependency, Bash-first, and observable—easy to audit and reason about.
They scale from laptops to clusters: the same primitives (auditd, inotify, TLS, rootless) apply everywhere.
Call to Action
Pick one project and ship it this week:
If you operate servers, start with Project 1 to get anomaly alerts tomorrow.
If you manage data/models, implement Project 2 to catch silent tampering.
If you expose model APIs, harden the edge with Project 3.
If your team handles tokens/keys, roll out Project 4 to stop secrets sprawl.
Iterate: add dashboards, alert routing, and documentation. Security is a practice—use these building blocks to make your AI stack safer, one Bash script at a time.