Posted on
Artificial Intelligence

Artificial Intelligence Raspberry Pi Security

Author
  • User
    linuxbash
    Posts by this author
    Posts by this author

Artificial Intelligence + Raspberry Pi Security: A Practical, Bash‑First Guide

If your Raspberry Pi is always on, it’s always a target. Bots comb the internet for weak SSH passwords, misconfigured services, and exposed cameras. The good news: today’s tiny boards can run real AI at the edge. In this guide, you’ll harden your Pi and then put it to work defending your home or lab with lightweight AI—no datacenter required.

What you’ll get:

  • A fast baseline hardening checklist (with apt, dnf, and zypper commands)

  • A person-detecting “AI camera sentinel” using TensorFlow Lite and the built-in camera

  • A production‑friendly alternative using Frigate NVR in Docker

  • Sandboxing tips to secure your AI workloads

Why combine AI and Pi security?

  • Edge privacy: Keep raw video/logs local. Send only alerts off-device.

  • Low cost and low power: Pi‑class boards handle basic models 24/7 for pennies.

  • Resilience: AI augments simple motion or port scans with semantic detection (e.g., only alert when a person is seen).

  • Skills that scale: The same hardening and MLOps patterns apply to servers and fleets.


1) Baseline: Harden your Raspberry Pi before you add AI

Do these first. It’s faster than incident response.

  • Update everything and reboot

    • apt (Raspberry Pi OS/Debian/Ubuntu):
    sudo apt update && sudo apt full-upgrade -y && sudo reboot
    
    • dnf (Fedora):
    sudo dnf upgrade --refresh -y && sudo systemctl reboot
    
    • zypper (openSUSE):
    sudo zypper refresh && sudo zypper update -y && sudo systemctl reboot
    
  • Create a new user, lock down the default one (if it exists), and set strong passwords

    sudo adduser aiadmin
    sudo usermod -aG sudo aiadmin
    # Optional: lock the 'pi' account if present
    sudo passwd -l pi || true
    
  • Install and harden SSH (key‑only auth)

    • apt:
    sudo apt install -y openssh-server
    
    • dnf:
    sudo dnf install -y openssh-server
    
    • zypper:
    sudo zypper install -y openssh
    

    Then:

    mkdir -p ~/.ssh && chmod 700 ~/.ssh
    nano ~/.ssh/authorized_keys  # paste your public key
    chmod 600 ~/.ssh/authorized_keys
    sudo nano /etc/ssh/sshd_config
    # Set or ensure:
    #   PasswordAuthentication no
    #   PermitRootLogin no
    #   PubkeyAuthentication yes
    sudo systemctl restart ssh || sudo systemctl restart sshd
    
  • Enable a host firewall

    • Debian/Ubuntu/openSUSE using UFW:
    • Install
      • apt: sudo apt install -y ufw
      • zypper: sudo zypper install -y ufw
    • Configure: sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow OpenSSH sudo ufw enable sudo ufw status
    • Fedora/openSUSE using firewalld:
    • Install (if needed) and enable
      • dnf: sudo dnf install -y firewalld sudo systemctl enable --now firewalld
      • zypper: sudo zypper install -y firewalld sudo systemctl enable --now firewalld
    • Allow SSH and reload: sudo firewall-cmd --permanent --add-service=ssh sudo firewall-cmd --reload
  • Ban brute‑force attempts with Fail2ban

    • apt:
    sudo apt install -y fail2ban
    
    • dnf:
    sudo dnf install -y fail2ban
    
    • zypper:
    sudo zypper install -y fail2ban
    

    Then:

    sudo systemctl enable --now fail2ban
    sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
    sudo nano /etc/fail2ban/jail.local
    # Ensure [sshd] enabled = true, adjust bantime/findtime/maxretry
    sudo systemctl restart fail2ban
    
  • Set up unattended updates (recommended)

    • apt:
    sudo apt install -y unattended-upgrades
    sudo dpkg-reconfigure --priority=low unattended-upgrades
    
    • dnf (Fedora):
    sudo dnf install -y dnf-automatic
    sudo sed -i 's/^apply_updates = .*/apply_updates = yes/' /etc/dnf/automatic.conf
    sudo systemctl enable --now dnf-automatic.timer
    
    • zypper (openSUSE) via a simple cron job:
    (crontab -l 2>/dev/null; echo "30 3 * * * /usr/bin/sudo /usr/bin/zypper -n refresh && /usr/bin/sudo /usr/bin/zypper -n update") | crontab -
    

2) Real‑world example: Build an “AI Camera Sentinel” with TensorFlow Lite

Goal: Use your Pi camera to detect people and trigger an alert—no cloud, no streaming your living room to strangers.

What this does:

  • Captures frames using libcamera

  • Runs a lightweight TFLite object detector locally

  • Sends a webhook when “person” is detected with a chosen confidence

Prereqs: Raspberry Pi OS (64‑bit recommended), a Pi Camera Module (libcamera era), or USB camera that works with libcamera.

Install camera tools

  • apt:

    sudo apt install -y libcamera-apps unzip
    
  • dnf (Fedora on Pi):

    sudo dnf install -y libcamera libcamera-tools unzip
    
  • zypper (openSUSE on Pi):

    sudo zypper install -y libcamera libcamera-tools unzip
    

Install Python runtime and create a venv

  • apt:

    sudo apt install -y python3 python3-venv python3-pip
    
  • dnf:

    sudo dnf install -y python3 python3-pip
    
  • zypper:

    sudo zypper install -y python3 python3-pip
    

    Create and activate:

python3 -m venv ~/ai-sec
source ~/ai-sec/bin/activate
pip install --upgrade pip

Install minimal AI dependencies (TensorFlow Lite runtime + Pillow + NumPy)

pip install tflite-runtime==2.12.0 pillow numpy requests

Note: If tflite-runtime fails on your architecture, see Google Coral’s prebuilt wheels or switch to Raspberry Pi OS 64‑bit.

Get a quantized MobileNet SSD model and labels

mkdir -p ~/ai-sentinel && cd ~/ai-sentinel
curl -L -o model.zip https://storage.googleapis.com/download.tensorflow.org/models/tflite/coco_ssd_mobilenet_v1_1.0_quant_2018_06_29.zip
unzip model.zip
# This archive contains detect.tflite and labelmap.txt (or similar)
ls

Create the sentinel script

nano ~/ai-sentinel/sentinel.py

Paste:

#!/usr/bin/env python3
import os, subprocess, time, json
from pathlib import Path
import numpy as np
from PIL import Image
import requests

from tflite_runtime.interpreter import Interpreter

MODEL = str(Path(__file__).with_name("detect.tflite"))
LABELS_FILE = str(Path(__file__).with_name("labelmap.txt"))
THRESHOLD = float(os.getenv("PERSON_THRESHOLD", "0.55"))
CAPTURE_CMD = ["libcamera-still", "-n", "-t", "1", "-o"]  # non-interactive, one shot
FRAME = str(Path("/tmp/ai_frame.jpg"))
WEBHOOK_URL = os.getenv("WEBHOOK_URL", "")  # set to your endpoint, or leave empty to log only
SLEEP = float(os.getenv("SLEEP_SECONDS", "2.0"))

def load_labels(path):
    labels = {}
    with open(path, "r") as f:
        for i, line in enumerate(f):
            labels[i] = line.strip()
    return labels

def notify(payload, image_path=None):
    print("[AI] Alert:", payload)
    if WEBHOOK_URL:
        try:
            if image_path and os.path.exists(image_path):
                with open(image_path, "rb") as img:
                    requests.post(WEBHOOK_URL, data={"alert": json.dumps(payload)}, files={"image": img}, timeout=5)
            else:
                requests.post(WEBHOOK_URL, json=payload, timeout=5)
        except Exception as e:
            print("[AI] webhook error:", e)

def capture_frame(path):
    subprocess.run(CAPTURE_CMD + [path], check=True)

def preprocess(path, input_shape):
    im = Image.open(path).convert("RGB").resize((input_shape[1], input_shape[2]))
    arr = np.asarray(im)
    return np.expand_dims(arr, axis=0).astype(np.uint8)

def main():
    labels = load_labels(LABELS_FILE)
    interpreter = Interpreter(model_path=MODEL, num_threads=2)
    interpreter.allocate_tensors()
    input_details = interpreter.get_input_details()
    output_details = interpreter.get_output_details()

    input_shape = input_details[0]["shape"]

    while True:
        try:
            capture_frame(FRAME)
            input_data = preprocess(FRAME, input_shape)
            interpreter.set_tensor(input_details[0]["index"], input_data)
            interpreter.invoke()

            boxes = interpreter.get_tensor(output_details[0]["index"])[0]
            classes = interpreter.get_tensor(output_details[1]["index"])[0].astype(int)
            scores = interpreter.get_tensor(output_details[2]["index"])[0]

            for cls, score, box in zip(classes, scores, boxes):
                label = labels.get(cls, str(cls))
                if label.lower() == "person" and score >= THRESHOLD:
                    payload = {
                        "event": "person_detected",
                        "confidence": float(score),
                        "timestamp": time.time(),
                    }
                    notify(payload, FRAME)
                    time.sleep(3)  # avoid flooding
                    break

        except subprocess.CalledProcessError:
            print("[AI] capture failed, retrying...")
        except Exception as e:
            print("[AI] error:", e)

        time.sleep(SLEEP)

if __name__ == "__main__":
    main()

Make it executable:

chmod +x ~/ai-sentinel/sentinel.py

Quick test:

WEBHOOK_URL="" PERSON_THRESHOLD=0.6 SLEEP_SECONDS=1.5 ~/ai-sentinel/sentinel.py

You should see console alerts when a person is in frame. Set WEBHOOK_URL to integrate with your home automation, chat, or a simple webhook catcher.

Optional: run as a systemd service (with sandboxing)

sudo useradd -r -s /usr/sbin/nologin ai
sudo install -d -o ai -g ai /var/lib/ai-sentinel
sudo nano /etc/systemd/system/ai-sentinel.service

Paste:

[Unit]
Description=AI Camera Sentinel (TFLite)
After=network-online.target

[Service]
User=ai
Group=ai
Environment=SLEEP_SECONDS=1.5
Environment=PERSON_THRESHOLD=0.6
# Set your webhook here or use an EnvironmentFile
# Environment=WEBHOOK_URL=https://example.net/webhook
ExecStart=/home/%i/ai-sentinel/sentinel.py
WorkingDirectory=/home/%i/ai-sentinel
# Security hardening
NoNewPrivileges=yes
PrivateTmp=yes
ProtectSystem=strict
ProtectHome=yes
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
LockPersonality=yes
MemoryDenyWriteExecute=yes
SystemCallFilter=@system-service
ReadWritePaths=/tmp
# Camera needs access to /dev/video*; allow device nodes:
DeviceAllow=/dev/video0 rw
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Important: Replace ExecStart/WorkingDirectory paths for the ai user, or run as your own user and adjust permissions. Then:

sudo systemctl daemon-reload
sudo systemctl enable --now ai-sentinel.service
sudo systemctl status ai-sentinel.service

Pro tips:

  • Prefer Raspberry Pi OS 64‑bit for better package and wheel support.

  • Tune THRESHOLD to balance sensitivity and false positives.

  • Store frames only when an alert triggers to protect privacy.


3) Production‑ready option: Frigate NVR + Docker (with or without Coral)

If you want multi‑camera, zones, and polished alerts, Frigate NVR is a great open‑source option that runs on Pi. It uses object detection to reduce noise vs. motion‑only systems.

Install Docker Engine

  • apt (Debian/Ubuntu/Raspberry Pi OS):

    sudo apt install -y docker.io docker-compose-plugin
    sudo usermod -aG docker $USER
    newgrp docker
    sudo systemctl enable --now docker
    
  • dnf (Fedora):

    sudo dnf install -y moby-engine docker-compose-plugin
    sudo usermod -aG docker $USER
    newgrp docker
    sudo systemctl enable --now docker
    
  • zypper (openSUSE):

    sudo zypper install -y docker docker-compose
    sudo usermod -aG docker $USER
    newgrp docker
    sudo systemctl enable --now docker
    

Create a minimal docker compose for Frigate

mkdir -p ~/frigate && cd ~/frigate
nano docker-compose.yml

Paste:

services:
  frigate:
    image: ghcr.io/blakeblackshear/frigate:stable
    container_name: frigate
    privileged: true
    restart: unless-stopped
    shm_size: "64mb"
    volumes:
      - ./config:/config
      - /etc/localtime:/etc/localtime:ro
      - /dev/bus/usb:/dev/bus/usb   # needed if using Coral USB
    ports:
      - "5000:5000"   # web UI
      - "8554:8554"   # RTSP restream
    environment:
      - FRIGATE_RTSP_PASSWORD=changeme

Create a basic config:

mkdir -p config
nano config/config.yml

Example:

mqtt: null
detectors:
  coral:
    type: edgetpu
    device: usb
cameras:
  front:
    ffmpeg:
      inputs:
        - path: rtsp://user:pass@yourcamera/stream1
          roles: [detect, record]
    detect:
      enabled: true
      max_disappeared: 25

Start it:

docker compose up -d

Open http://:5000. If you don’t have a Coral USB, switch detector to CPU in config (type: cpu), but expect higher CPU usage on older Pis.

Security tips for Docker:

  • Don’t publish ports to the internet; keep them on your LAN or behind a VPN.

  • Run on a dedicated VLAN if possible and apply firewall rules (UFW/firewalld) to limit access.

  • Keep Frigate and OS updated.


4) Secure your AI workloads like production software

  • Verify model integrity

    sha256sum detect.tflite > detect.tflite.sha256
    # Keep the checksum under version control; verify after updates:
    sha256sum -c detect.tflite.sha256
    
  • Least privilege: run as a non‑root user, grant only needed device access (/dev/video0).

  • Sandboxing: use systemd directives (ProtectSystem, PrivateTmp, NoNewPrivileges, DeviceAllow) as shown above.

  • Network egress control: if your AI app doesn’t need internet, block it.

    • UFW example:
    sudo ufw default deny outgoing
    sudo ufw allow out 53,123/udp  # DNS/NTP if needed
    
    • firewalld example:
    sudo firewall-cmd --permanent --add-rich-rule='rule family=ipv4 source address=0.0.0.0/0 drop'
    sudo firewall-cmd --reload
    

    Adjust to your needs or use zones/interfaces for fine control.

  • Backups and logs: store configs under git, rotate logs with logrotate, and snapshot your SD/SSD periodically.


Troubleshooting quick hits

  • Camera errors: ensure camera is enabled and only one process owns /dev/video0. Test:

    libcamera-still -n -t 1000 -o test.jpg
    
  • Python wheels: if numpy/tflite wheels fail to install, switch to 64‑bit Raspberry Pi OS and retry.

  • Performance: reduce frame rate or inference frequency (SLEEP_SECONDS) to keep CPU temps down; add a small heatsink/fan if running 24/7.


Conclusion and next steps

You now have a hardened Raspberry Pi that can detect real‑world events with local AI. Start small with the AI Camera Sentinel, or go big with Frigate NVR. Next:

  • Automate alerts to your preferred system (Home Assistant, Matrix/Slack, email, or webhooks).

  • Add zones and schedules to reduce noise.

  • Expand to other AI sensors (audio anomaly detection, package detection, license plates—always respecting local laws and privacy).

Have a favorite tweak or want a follow‑up on GPU/TPU acceleration, audio anomaly detection, or multi‑Pi fleet hardening? Tell me what you’re building and I’ll tailor the next guide.