Defensive SSH security auditing, evidence reporting, and automated hardening validation.
SSHGuardLab is a Python-based cybersecurity project designed to audit the effective security configuration of authorized OpenSSH servers.
Instead of only inspecting configuration files, SSHGuardLab connects to a target through SSH, collects the effective sshd configuration, evaluates security controls, identifies potential hardening opportunities, and generates evidence that can be used to validate remediation.
The project also includes an Ansible-based lab for safely applying and validating SSH hardening changes.
SSH Target
│
▼
┌─────────────────┐
│ SSHGuardLab │
│ Read-Only Audit │
└────────┬────────┘
│
▼
Effective sshd Configuration
│
▼
Security Findings
PASS / WARN / FAIL / INFO
│
┌─────┴─────┐
▼ ▼
JSON Report PDF Report
│
▼
SHA-256 Evidence
│
▼
Ansible Hardening
│
▼
Validation Scan
The goal is to demonstrate a complete defensive security lifecycle:
Audit → Detect → Remediate → Validate
SSHGuardLab performs a read-only assessment of an authorized SSH server and collects information such as:
- Operating system
- Kernel version
- OpenSSH version
- System uptime
- Effective
sshdconfiguration
The scanner evaluates the effective SSH configuration instead of relying only on static configuration-file contents.
Current authentication checks include:
| Check | Description |
|---|---|
SSH-AUTH-001 |
Detect whether SSH root login is disabled |
SSH-AUTH-002 |
Detect whether password authentication is disabled |
SSH-AUTH-003 |
Verify that public-key authentication is enabled |
SSH-AUTH-004 |
Evaluate the configured authentication attempt limit |
Findings are classified as:
PASS
WARN
FAIL
INFO
The scanner uses defensive SSH execution practices including:
BatchMode=yesStrictHostKeyChecking=yesIdentitiesOnly=yes- Connection timeout
- Argument-based subprocess execution
- No
shell=True - No password or private-key storage
An SSH private key can be explicitly supplied with --identity.
SSHGuardLab can generate machine-readable JSON evidence:
sshguard scan user@server \
--identity ~/.ssh/id_ed25519 \
--reportReports are stored under:
reports/
Generated reports are excluded from Git by default.
A visual PDF security assessment can also be generated:
sshguard scan user@server \
--identity ~/.ssh/id_ed25519 \
--pdfThe PDF includes system information, findings, evidence, recommendations, and an assessment summary.
SSHGuardLab also calculates a SHA-256 digest of the generated report so its integrity can be independently verified.
Example:
PDF SECURITY REPORT
----------------------------------------------------------------
Report : reports/sshguard-YYYYMMDDTHHMMSSZ.pdf
SHA-256 : <sha256-digest>
The project contains an Ansible lab demonstrating controlled remediation of an SSH finding.
The current hardening role manages:
MaxAuthTries
The workflow uses:
- Ansible roles
- Variables
- Handlers
- Configuration validation with
sshd -t - Configuration backups
- SSH service reload
- Check mode / dry-run
- Diff inspection
- Post-remediation validation
The default lab value is:
sshguard_max_auth_tries: 3This is a lab hardening baseline and should be evaluated against the operational requirements of each environment.
SSHGuardLab/
├── src/
│ └── sshguardlab/
│ ├── checks/
│ │ ├── authentication.py
│ │ ├── crypto.py
│ │ ├── exposure.py
│ │ ├── logs.py
│ │ └── permissions.py
│ ├── reporting/
│ │ ├── json_report.py
│ │ ├── pdf_report.py
│ │ └── terminal.py
│ ├── cli.py
│ ├── models.py
│ └── scanner.py
│
├── lab/
│ └── ansible/
│ ├── inventory/
│ │ └── lab.ini.example
│ ├── playbooks/
│ │ └── harden_ssh.yml
│ └── roles/
│ └── ssh_hardening/
│ ├── defaults/
│ ├── handlers/
│ └── tasks/
│
├── reports/
├── tests/
├── ansible.cfg
├── pyproject.toml
├── requirements.txt
├── SECURITY.md
└── README.md
SSHGuardLab requires:
- Python 3.12+
- OpenSSH client
- Network access to an authorized SSH server
- SSH public-key authentication
For the optional hardening lab:
- Ansible Core
- A Linux SSH target
- Authorized privilege escalation on the target
Clone the repository:
git clone https://github.com/martins83br/SSHGuardLab.git
cd SSHGuardLabCreate an isolated Python environment:
python3 -m venv .venv
source .venv/bin/activateInstall SSHGuardLab:
pip install .Verify the installation:
sshguard --helpFor development:
pip install -e ".[dev]"This installs the development dependencies used by the project, including pytest and Ruff.
To install SSHGuardLab with the Ansible lab dependencies:
pip install ".[lab]"To install both development and lab dependencies:
pip install -e ".[dev,lab]"A minimal requirements.txt is also provided for users who prefer:
pip install -r requirements.txtBasic syntax:
sshguard scan user@serverUsing a specific SSH private key:
sshguard scan user@server \
--identity ~/.ssh/id_ed25519Using a custom SSH port:
sshguard scan user@server \
--port 2222 \
--identity ~/.ssh/id_ed25519Generate JSON evidence:
sshguard scan user@server \
--identity ~/.ssh/id_ed25519 \
--reportGenerate a PDF security assessment:
sshguard scan user@server \
--identity ~/.ssh/id_ed25519 \
--pdfExample output before remediation:
AUTHENTICATION SECURITY
----------------------------------------------------------------
[PASS] SSH-AUTH-001 - Root login disabled
Evidence: PermitRootLogin no
[PASS] SSH-AUTH-002 - Password authentication disabled
Evidence: PasswordAuthentication no
[PASS] SSH-AUTH-003 - Public-key authentication enabled
Evidence: PubkeyAuthentication yes
[WARN] SSH-AUTH-004 - Authentication attempt limit can be hardened
Evidence: MaxAuthTries 6
SUMMARY
----------------------------------------------------------------
PASS : 3
WARN : 1
FAIL : 0
INFO : 0
After controlled remediation:
[PASS] SSH-AUTH-004 - Authentication attempts restricted
Evidence: MaxAuthTries 3
SUMMARY
----------------------------------------------------------------
PASS : 4
WARN : 0
FAIL : 0
INFO : 0
This demonstrates that SSHGuardLab can be used not only to identify a hardening opportunity but also to validate that remediation changed the effective SSH configuration.
Copy the example inventory:
cp lab/ansible/inventory/lab.ini.example \
lab/ansible/inventory/lab.iniEdit the local inventory with your authorized lab target.
The real lab.ini is intentionally excluded from Git.
ansible \
-i lab/ansible/inventory/lab.ini \
ssh_lab \
-m pingAlways inspect the proposed change first:
ansible-playbook \
-i lab/ansible/inventory/lab.ini \
lab/ansible/playbooks/harden_ssh.yml \
--check \
--diff \
--ask-become-passAfter reviewing the dry-run output:
ansible-playbook \
-i lab/ansible/inventory/lab.ini \
lab/ansible/playbooks/harden_ssh.yml \
--diff \
--ask-become-passAfter applying SSH changes, verify that a new SSH session can be established before closing any existing administrative session.
Then run SSHGuardLab again:
sshguard scan user@server \
--identity ~/.ssh/id_ed25519 \
--pdfThe post-remediation assessment validates the effective SSH configuration.
Run the automated tests:
pytestRun static analysis:
ruff check .The project is designed so security logic can be independently tested without making configuration changes to the target.
SSHGuardLab follows several defensive design principles:
Read-only by default — the scanner audits the target without modifying its SSH configuration.
Effective configuration validation — security decisions are based on the effective sshd configuration.
Explicit trust — SSH host-key verification remains enabled.
No credential storage — passwords and SSH private keys are not embedded in generated reports.
Controlled remediation — configuration changes are separated from the scanner and performed through Ansible.
Validate before reload — SSH configuration changes are validated with sshd -t before being applied.
Evidence integrity — generated reports include a SHA-256 digest.
Local environment isolation — private inventories, generated reports, virtual environments, keys, and local artifacts are excluded from version control.
SSHGuardLab is intended only for systems that you own or are explicitly authorized to assess.
Do not use this project against systems without permission.
SSH hardening changes can affect remote access. Always test changes in a controlled environment and maintain a recovery path before modifying production SSH configurations.
Planned areas of development include:
- Additional SSH authentication checks
- Cryptographic configuration analysis
- SSH exposure checks
- File and permission validation
- Logging and auditing checks
- Expanded automated tests
- Before/after remediation comparison
- Additional evidence-reporting capabilities
- CI validation
Diniz Rodrigues Martins
Cybersecurity • Cloud • Infrastructure • Security Automation
GitHub: martins83br
This project is licensed under the MIT License.
See LICENSE for details.