Skip to content

styliteag/ssm

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1,182 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Secure SSH Manager (SSM)

Note

This is pre-release software. Use at your own risk.

A web application for managing SSH authorized_keys files across multiple hosts — React frontend, Python/FastAPI backend.

Prerequisites

Quick Start

just dev          # starts backend + frontend in dev mode

Or individually:

just backend-install   # uv sync
just backend-run       # uvicorn with --reload

just frontend-install  # npm install
just frontend-dev      # vite dev server

Run just to see all available commands.

Architecture

Layer Stack
Frontend React 19 + TypeScript + Tailwind CSS + Vite
Backend Python 3.12 + FastAPI + SQLAlchemy (async)
Database SQLite (default) — swappable via DATABASE_URL
Migrations Alembic
Auth htpasswd credential store + JWT (HS256)
SSH asyncssh

The production Docker image is a single all-in-one container: nginx serves the built React SPA on port 80 and reverse-proxies /api/* to uvicorn on 127.0.0.1:8000. Migrations run automatically on startup.

Development Workflow

Backend

just backend-test       # pytest
just backend-test-cov   # pytest with coverage report
just backend-lint       # ruff check
just backend-fmt        # ruff format
just backend-typecheck  # mypy
just backend-security   # bandit

Frontend

just frontend-lint        # eslint
just frontend-typecheck   # tsc --noEmit
just frontend-build       # production build

Database

just migrate              # alembic upgrade head
just migrate-new <name>   # create autogenerated revision
just migrate-down         # downgrade one step
just migrate-history      # show migration history

Configuration

Every setting is read from environment variables. A backend/.env file is loaded automatically on startup via python-dotenv — copy backend/.env.example and edit. Shell variables always win over .env values. Set DOTENV=/path/to/file.env to load a different file.

Variable Default Description
DATABASE_URL sqlite:///ssm.db SQLAlchemy database URL
JWT_SECRET Required in production (32+ chars)
SSH_KEY keys/id_ssm Path to SSH private key
SSH_KEY_PASSPHRASE Passphrase if the SSH key is encrypted
SSH_TIMEOUT 120 SSH connection timeout in seconds
HTPASSWD .htpasswd Path to htpasswd credential file
LOGLEVEL info Logging level
PORT 8000 Listen port
LISTEN :: Listen address
DOTENV ./.env Path to the .env file to load

SESSION_KEY is accepted as an alias for JWT_SECRET.

SSH Key

Generate a key for the server to use when connecting to managed hosts:

ssh-keygen -t ed25519 -f backend/keys/id_ssm -C 'ssm-server' -N ''

Authentication

The server auto-creates an .htpasswd file with a random admin password on first start (printed to console). To set credentials manually:

htpasswd -cB backend/.htpasswd admin    # create file
htpasswd -B backend/.htpasswd user2     # add user

Production Deployment

The combined image (ghcr.io/styliteag/ssm/ssm:latest) ships nginx + the SPA + the FastAPI backend in one container, listening on port 80.

just up      # docker compose up -d --build
just down    # docker compose down
just logs    # tail logs

The compose file (docker/compose.prod.yml) expects persistent volumes at docker/data/:

docker/data/
├── config/.env           # main config (optional, env vars)
├── config/.htpasswd      # credentials
├── keys/id_ssm           # SSH private key
├── db/                   # SQLite database
└── logs/                 # nginx + app logs

JWT_SECRET must be set — uncomment the line in compose.prod.yml and supply a 32+ character value.

Local combined-image dev run

To exercise the production image locally on http://localhost:8080 without affecting prod data:

just docker-build     # build docker/app/Dockerfile (frontend + backend + nginx)
just docker-run       # run it on :8080 with a scratch data dir under /tmp
just docker-stop      # tear it down

Release

just release          # patch bump
just release minor    # minor bump
just release major    # major bump

Bumps VERSION, commits, tags, and pushes. The tag push triggers the CI build.

SSH Management Controls

  • Disabled hosts: mark a host as disabled in the UI to skip all SSH operations (maintenance, decommission)
  • .ssh/system_readonly on a remote host: prevents SSM from modifying any keyfile
  • .ssh/user_readonly on a remote host: prevents modifications for a specific user

Both files accept an optional reason string that is displayed in the UI.

Security Features

  • All /api/v2 endpoints require a valid JWT Bearer token (except /api/v2/auth/login)
  • Passwords stored as bcrypt hashes in htpasswd format
  • JWT tokens signed with HS256; access and refresh tokens are distinct types (not interchangeable)
  • SSH connections use key-based authentication only

License

GPL-3.0 — see LICENSE.txt.

About

STYLiTE Orbit SSH Manager. manage your SSH keys on multiple host from a web UI

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors