Skip to content

anhtuank7c/pamsignal

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

200 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

PAMSignal β€” real-time login & brute-force alerts for Linux servers

PAMSignal 🚨

🌐 English Β· TiαΊΏng Việt

CI Release License Language Platform Stars

PAMSignal is a lightweight, zero-dependency login monitor for Linux servers. It watches the systemd journal for PAM authentication events and sends real-time alerts to your favorite messaging platforms.

If you manage a handful of servers and want to know instantly when someone logs in or tries to brute-force your machineβ€”without deploying Wazuh, EDR, or reading 200 pages of documentationβ€”this is for you.

Think of it as a smoke detector for your servers' front door: it doesn't lock the door (hardening SSH is still your job β€” here's how), but it tells you the instant someone opens it or starts trying to force it.

πŸ‘₯ Is PAMSignal for you?

  • Solo devs & self-hosters β€” get a phone buzz the moment anyone logs into your VPS, or a bot starts hammering it. Two-minute setup, no platform to babysit.
  • Small teams & startups β€” one #security-alerts channel and one fleet dashboard for everyone on call.
  • Hosting providers & MSPs β€” offer per-customer login alerting as a near-zero-cost value-add for the servers you manage β†’ hosting-provider playbook.

Full playbooks for each in Use Cases & Integrations.

πŸ‘€ What you'll actually see

Seconds after an event, a line like this lands in your Telegram, Slack, Teams, Discord, or WhatsApp:

[NOTICE] auth.login_success user=admin src=192.168.1.100:52341 host=web-01 service=sshd auth=publickey
[WARN]   auth.login_failure user=root  src=203.0.113.50:39182 host=web-01 service=sshd auth=password
[ALERT]  auth.brute_force_detected     src=203.0.113.50 attempts=12 window=300s user=root host=web-01

Prefer one screen for the whole fleet instead of per-host pings? PAMSignal also feeds a ready-made Grafana dashboard (preview below).

✨ Why PAMSignal?

  • Real-time Alerts: Native integration for Telegram, Slack, Teams, WhatsApp, Discord, and Custom Webhooks.
  • Brute-Force Protection: Natively tracks failed attempts and seamlessly integrates with Fail2ban to block attackers.
  • Ultra Lightweight: A single C binary with a single config file. The only dependency is libsystemd.
  • Fault-Tolerant: Alert dispatching is isolated via fork+exec. Network timeouts or API failures will never crash the core monitoring process.
  • Fits your stack: Speaks ECS JSON to any SIEM or webhook and ships a Grafana fleet dashboard β€” it feeds the tools you already run instead of being one more console.

🧱 Where PAMSignal fits

PAMSignal is the detection layer of a four-layer defence-in-depth stack. It does that one job well and leaves the others to the right tool β€” it never modifies sshd or blocks anything itself.

Layer Job Your tool
Prevention make the door hard to open SSH key-only auth β†’ Secure SSH guide
Integrity detect tampering with the system AIDE / debsums / rpm -V
Detection / Alerting tell you what's happening, now PAMSignal
Forensics reconstruct events after the fact auditd + journald retention

The natural companion is response: Fail2ban acts on PAMSignal's brute-force signal to block attacker IPs at the firewall. Exactly what PAMSignal can and can't observe is spelled out in the Threat Model.

πŸ—οΈ Architecture

graph LR
    sshd["sshd / sudo / su"]
    journald[("systemd-journald")]
    pamsignal["PAMSignal"]
    admin["πŸ§‘β€πŸ’» Admin"]
    platforms["Telegram / Slack<br/>Teams / WhatsApp / Discord<br/>Custom webhook"]
    fail2ban["Fail2ban<br/>(iptables / ufw)"]

    sshd -- "PAM auth events" --> journald
    pamsignal -- "reads & writes<br/>structured events" --> journald
    admin -- "journalctl -t pamsignal" --> journald
    pamsignal -. "fork+exec curl<br/>(best-effort)" .-> platforms
    platforms -. "alerts" .-> admin
    fail2ban -. "watches pamsignal BRUTE_FORCE_DETECTED events<br/>& blocks attacker IP" .-> journald

    style pamsignal fill:#2d6a4f,stroke:#1b4332,color:#fff
    style journald fill:#264653,stroke:#1d3557,color:#fff
    style sshd fill:#6c757d,stroke:#495057,color:#fff
    style platforms fill:#6c757d,stroke:#495057,color:#fff,stroke-dasharray: 5 5
    style fail2ban fill:#e76f51,stroke:#d62828,color:#fff,stroke-dasharray: 5 5
    style admin fill:#e9c46a,stroke:#f4a261,color:#000
Loading

πŸš€ Quick Start

1. Install

Debian / Ubuntu
sudo install -d -m 0755 /etc/apt/keyrings
curl -fsSL https://anhtuank7c.github.io/pamsignal/key.asc | sudo gpg --dearmor -o /etc/apt/keyrings/pamsignal.gpg
echo "deb [signed-by=/etc/apt/keyrings/pamsignal.gpg] https://anhtuank7c.github.io/pamsignal stable main" | sudo tee /etc/apt/sources.list.d/pamsignal.list
# Refresh only the PamSignal repo, so an unrelated broken repo can't block the install
sudo apt update -o Dir::Etc::sourcelist="sources.list.d/pamsignal.list" \
  -o Dir::Etc::sourceparts="-" -o APT::Get::List-Cleanup="0"
sudo apt install pamsignal
Fedora / CentOS / RHEL

Fedora / CentOS

sudo dnf config-manager addrepo --from-repofile=https://anhtuank7c.github.io/pamsignal/rpm/fedora/pamsignal.repo
sudo dnf install pamsignal

RHEL 9 / AlmaLinux 9 / Rocky Linux 9

sudo dnf config-manager --add-repo https://anhtuank7c.github.io/pamsignal/rpm/el9/pamsignal.repo
sudo dnf install pamsignal
Ubuntu 20.04 LTS (Focal, ESM-only)

20.04 is ESM-only since April 2025 and there's no gh-pages apt pocket for it β€” but a Focal-targeted .deb is built and tested in CI on every release, then attached as a GitHub release asset. Download and install directly:

VERSION=0.5.0   # bump per release β€” see https://github.com/anhtuank7c/pamsignal/releases
curl -fL -o pamsignal_focal.deb \
  "https://github.com/anhtuank7c/pamsignal/releases/download/v${VERSION}/pamsignal_${VERSION}-1_focal_amd64.deb"

# Optional: verify the detached signature (signing key fingerprint below)
curl -fL -o pamsignal_focal.deb.asc \
  "https://github.com/anhtuank7c/pamsignal/releases/download/v${VERSION}/pamsignal_${VERSION}-1_focal_amd64.deb.asc"
gpg --verify pamsignal_focal.deb.asc pamsignal_focal.deb

# Install β€” apt resolves libsystemd0 and other transitive deps from your host's apt sources
sudo apt install ./pamsignal_focal.deb

To upgrade later, re-run the same recipe with the new VERSION. For a fleet, wrap it in a small Ansible / cron / shell script.

πŸ•’ Lifecycle reminder. Focal exits ESM in April 2030. Plan a migration to 22.04 LTS (Standard Support until April 2027) or 24.04 LTS in the next ~12 months. See docs/distros.md for the full support matrix.

Signing key fingerprint: 2D2C 828F A6F4 D019 E446 8FBB B106 2235 2862 2F69

2. Configure Alerts

Edit the configuration file (/etc/pamsignal/pamsignal.conf) and drop in your platform credentials. For example, to enable Telegram:

telegram_bot_token = <your_bot_token>
telegram_chat_id = <your_chat_id>

See Alert Setup Guides for Slack, Teams, WhatsApp, and Discord.

Two tuning keys worth knowing on day one β€” one controls how often you get pinged, the other controls what you get pinged about:

# Minimum seconds between brute-force alerts for the same IP.
# Default 60. Set to 0 to fire on EVERY threshold crossing β€”
# useful for low-traffic hosts where you don't want any signal collapsed.
alert_cooldown_sec = 60

# Which event categories trigger chat alerts. Default is "all" (every category),
# which is noisy in production. Narrow to just what you care about β€”
# most operators only want successful logins and brute-force pings.
enable_notification_type = login_success,brute_force

All six event-type tokens (login_success, login_failed, session_open, session_close, brute_force, all) are documented in Configuration β†’ Notification-type filter. journalctl -t pamsignal keeps the full forensic trail regardless of what you filter out of chat.

3. Custom Webhook Integrations (Optional)

Need to send alerts to a provider we don't support natively? Or want to build your own auto-banning logic? PAMSignal sends structured ECS JSON to any custom webhook.

πŸ‘‰ Check out the Node.js Custom Webhook Example to see how easy it is to build your own receiver!

4. Reload & Monitor

Apply your configuration and watch the live events:

sudo systemctl reload pamsignal
journalctl -t pamsignal -f

πŸ›‘οΈ Hardening with Fail2ban (Optional Advanced Protection)

PAMSignal calculates brute-force thresholds for you. You can take this a step further by automatically blocking attackers' IPs using Fail2ban. Since PAMSignal does the heavy lifting, the Fail2ban setup is incredibly simple.

πŸ‘‰ Read the Fail2ban Integration Guide

First time securing SSH itself? Pair this with Secure SSH & Manage a Fleet β€” PAMSignal watches the door; that guide makes the door strong, and shows you how to drive many servers from one place.

πŸ“Š Fleet view in Grafana

Per-host journalctl and real-time chat alerts cover one host. For fleet-wide auth visibility β€” one queryable view across every server β€” there's a Loki/Alloy/Grafana integration that ships with PAMSignal: ECS-schema events flow into Loki via Alloy, and a single dashboard answers "what's happening with auth across my fleet right now?" at a glance.

PAMSignal Grafana dashboard

Local try-it stack (no Linux fleet required):

cd examples/grafana && docker compose up -d
# β†’ http://localhost:3000 (anonymous Admin, dashboard preloaded)

πŸ‘‰ New to Grafana? Start with Grafana from Zero β€” what Grafana/Loki/Alloy even are, setup both ways (cloud or self-host), and how to read every panel.

πŸ‘‰ Read the Grafana Integration Guide β€” the production reference: full deploy + Alloy install + 4 alert rules

πŸ“š Documentation

Guides β€” start here

  • 🧭 Use Cases & Integrations β€” who it's for (solo Β· team Β· hosting provider) and how to plug PAMSignal into your existing stack
  • πŸ” Secure SSH & Manage a Fleet β€” harden the door PAMSignal watches, and drive 1–50 servers from one ~/.ssh/config
  • πŸ“Š Grafana from Zero β€” stand up a fleet-wide dashboard and learn to read every panel, even if you've never used Grafana

Reference

  • πŸ›οΈ Architecture β€” C4 diagrams, isolation models, and design decisions
  • βš™οΈ Configuration β€” Config reference, CLI flags, and tuning
  • πŸ”” Alerts β€” Webhook payloads and channel setup
  • πŸ”’ Deployment β€” Security hardening and systemd setup
  • 🎯 Threat Model β€” What pamsignal defends against, what it deliberately does not, and the design rationale behind the split
  • πŸ“ Grafana Integration β€” Design β€” Schema, label cardinality, and panel rationale (the deep dive behind the guide above)
  • 🐧 Supported Distributions β€” Three-tier matrix (CI-tested / expected to work / unsupported) with reasoning per row
  • πŸ› οΈ Development β€” Building from source and testing
  • πŸ” Security Policy β€” Responsible-disclosure channel and supported versions
  • πŸ“ Changelog β€” Status, task tracking, and updates

πŸ™ Acknowledgments

This project would look very different β€” or wouldn't exist at all β€” without two friends:

@hongquan
Nguyen HongΒ Quan
@hongquan

Gave the kind of honest, no-punches-pulled feedback on Linux standards and operator expectations that reshaped PAMSignal's roadmap and architecture. The single biggest design decision in this codebase β€” subscribing to systemd-journald for PAM events instead of tailing /var/log/auth.log β€” came directly from his pushback. His strong emphasis on Linux FHS compliance also threads through every file-path choice in the project: the binary under /usr/bin, config under /etc/pamsignal/, runtime state under /run/pamsignal/, the systemd vendor unit under /usr/lib/systemd/system/, and the apt repository keyring at /etc/apt/keyrings/pamsignal.gpg (#14). The result is a daemon that fits the modern Linux stack instead of working around it. πŸ™‡

@lehiep1994
SamuelΒ Le
@lehiep1994

Kept me reading and kept me building. He sent me books on Linux internals at exactly the moments I needed them, and the steady encouragement to not abandon this project β€” through every "is this even worth shipping?" stretch β€” is a real part of why PAMSignal made it to a release. πŸ™‡


πŸ€– Built with AI Collaboration

This project is built with AI assistance (Claude Code). I am open about this workflow: AI catches edge cases, guides architectural decisions, and even performed the OWASP ASVS 5.0 security review that hardened this project. The .claude/ directory is committed to this repo so you can inspect exactly how AI is utilized here. Humans test on real systems and take responsibility for shipping.

About

A lightweight, zero-dependency Linux login monitor. Tracks SSH/sudo events via systemd-journald and sends real-time brute-force alerts to Telegram, Slack, Teams, Discord, and custom webhooks.

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors