{"id":43086296,"url":"https://github.com/styliteag/ssm","last_synced_at":"2026-01-31T15:11:06.548Z","repository":{"id":261086605,"uuid":"816768385","full_name":"styliteag/ssm","owner":"styliteag","description":"WIP: Securely manage your SSH keys on multiple host from a web UI","archived":false,"fork":false,"pushed_at":"2025-12-01T21:56:56.000Z","size":2259,"stargazers_count":5,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-12-04T11:18:36.632Z","etag":null,"topics":["authorized-keys","manager","react","rust","ssh","ssh-key","ssh-key-management"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/styliteag.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2024-06-18T11:18:42.000Z","updated_at":"2025-12-01T21:57:00.000Z","dependencies_parsed_at":"2025-01-14T19:23:30.775Z","dependency_job_id":"517e0e1c-6519-4c1e-9a94-403d4d2e1c7f","html_url":"https://github.com/styliteag/ssm","commit_stats":null,"previous_names":["styliteag/ssm"],"tags_count":57,"template":false,"template_full_name":null,"purl":"pkg:github/styliteag/ssm","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/styliteag%2Fssm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/styliteag%2Fssm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/styliteag%2Fssm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/styliteag%2Fssm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/styliteag","download_url":"https://codeload.github.com/styliteag/ssm/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/styliteag%2Fssm/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28946306,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-31T14:26:55.697Z","status":"ssl_error","status_checked_at":"2026-01-31T14:26:52.545Z","response_time":128,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authorized-keys","manager","react","rust","ssh","ssh-key","ssh-key-management"],"created_at":"2026-01-31T15:11:05.889Z","updated_at":"2026-01-31T15:11:06.536Z","avatar_url":"https://github.com/styliteag.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Secure SSH Manager (SSM)\n\n\u003e [!NOTE]\n\u003e This is pre-release software. Use at your own risk.\n\nA modern web application for managing SSH keys across multiple hosts with a **React frontend** and **Rust API backend**.\n\n## 🚀 Quick Start\n\n### Development Environment\n\n### Prerequisites\n\n- **Rust** (1.75+) with Cargo\n- **Node.js** (24+) with npm\n- **Docker** (optional, for deployment)\n- **htpasswd** utility (for authentication)\n- **SSH** private key (for SSH connections)\n- **just**\n   - install just: `cargo install just`\n- **watch**\n   - install watch: `cargo install cargo-watch`\n\n### Initial Setup\n\nStart both frontend and backend development servers:\n\n```bash\n./start-dev.sh\n```\n\n- **Frontend**: http://localhost:5173 (React + Vite)\n- **Backend API**: http://localhost:8000 (Rust + Actix Web)\n\n### Production Deployment\n\nDeploy with Docker:\n\n```bash\ndocker-compose -f docker/compose.prod.yml up --build\n```\n\n- **Application**: http://localhost/ (nginx serves frontend, proxies API)\n\n## 📋 Overview\n\nSSH Key Manager provides a web interface for managing `authorized_keys` files on remote hosts via SSH connections. The application has been refactored from a monolithic Rust application to a modern distributed architecture:\n\n- **Frontend**: React + TypeScript + Tailwind CSS\n- **Backend**: Rust + Actix Web REST API  \n- **Database**: SQLite (with PostgreSQL/MySQL support)\n- **Deployment**: Multi-stage Docker build with nginx proxy\n- **Authentication**: Session-based with htpasswd integration\n\n## 🏗️ Architecture\n\n### Frontend (`frontend/`)\n- **Framework**: React 19 with TypeScript\n- **Styling**: Tailwind CSS with custom component library\n- **State Management**: Zustand + React Context\n- **Routing**: React Router with protected routes\n- **Build Tool**: Vite for fast development and production builds\n- **API Communication**: Axios with centralized service layer\n\n### Backend (`backend/`)\n- **Framework**: Rust + Actix Web\n- **Database**: Diesel ORM (SQLite/PostgreSQL/MySQL)\n- **Authentication**: Session-based with htpasswd files\n- **SSH Client**: russh for remote host connections\n- **API Design**: RESTful JSON endpoints with structured responses\n\n### Deployment\n- **Multi-stage Docker**: Frontend build → Backend build → Combined runtime\n- **Web Server**: nginx serves React app and proxies API requests\n- **Single Container**: Simplified deployment with internal service communication\n- **Health Checks**: Built-in monitoring and health endpoints\n\n## 🛠️ Development Setup\n\n### Prerequisites\n\n- **Rust** (1.75+) with Cargo\n- **Node.js** (24+) with npm\n- **Docker** (optional, for deployment)\n- **htpasswd** utility (for authentication)\n\n### Initial Setup\n\n1. **Clone the repository**:\n   ```bash\n   git clone \u003crepository-url\u003e\n   cd ssm\n   ```\n\n2. **Set up authentication**:\n   ```bash\n   htpasswd -B -c .htpasswd admin\n   ```\n\n3. **Configure the application**:\n   Create `config.toml` (see [Configuration](#configuration) section)\n\n4. **Set up the database** (from `backend/` directory):\n   ```bash\n   cd backend\n   cargo install diesel_cli --no-default-features --features sqlite\n   diesel setup\n   diesel migration run\n   cd ..\n   ```\n\n5. **Install frontend dependencies**:\n   ```bash\n   cd frontend\n   npm install\n   cd ..\n   ```\n\n### Development Workflow\n\n#### Start Development Servers\n```bash\n# Start both frontend and backend\n./start-dev.sh\n\n# Or start individually:\n# Backend (from backend/ directory)\ncd backend \u0026\u0026 cargo run\n\n# Frontend (from frontend/ directory)  \ncd frontend \u0026\u0026 npm run dev\n```\n\n#### Frontend Development\n```bash\ncd frontend\n\n# Start dev server\nnpm run dev\n\n# Build for production\nnpm run build\n\n# Lint and type check\nnpm run lint\nnpm run type-check\n```\n\n#### Backend Development\n```bash\ncd backend\n\n# Run with auto-reload\ncargo watch -x run\n\n# Run tests\ncargo test\n\n# Database operations\ndiesel migration run\ndiesel migration generate \u003cname\u003e\n```\n\n## 🐳 Docker Deployment\n\n### Production Deployment\n\n```bash\n# Build and start production stack\ndocker-compose -f docker/compose.prod.yml up --build\n\n# Run in background\ndocker-compose -f docker/compose.prod.yml up -d --build\n```\n\n### Development with Docker\n\n```bash\n# Start development stack\ndocker-compose -f docker/compose.yml up --build\n```\n\n### Docker Architecture\n\nThe multi-stage build process:\n\n1. **Frontend Build Stage**: Builds React application with Vite\n2. **Backend Build Stage**: Compiles Rust application with optimizations\n3. **Runtime Stage**: Combines built assets with nginx + Alpine Linux\n\n**Container Structure**:\n- nginx serves React frontend from `/usr/share/nginx/html`\n- nginx proxies `/api/*` requests to Rust backend on port 8000\n- Single container exposes port 80 for all web traffic\n- Persistent volumes for database, configuration, and SSH keys\n\n## ⚙️ Configuration\n\n### Main Configuration (`config.toml`) - Optional\n\nThe `config.toml` file is optional. If it doesn't exist, the server will use environment variables and built-in defaults.\n\n```toml\n# Database URL (SQLite default) - can be overridden by DATABASE_URL env var\n# database_url = \"sqlite://ssm.db\"\n\n# API server configuration\nlisten = \"127.0.0.1\"\nport = 8000\n\n# Logging level\nloglevel = \"info\"\n\n# htpasswd path - can be overridden by HTPASSWD env var\n# htpasswd_path = \".htpasswd\"\n\n[ssh]\n# Path to private key for SSH connections - can be overridden by SSH_KEY env var\n# private_key_file = \"/path/to/your/ssh/private/key\"\n\n# Optional passphrase\n# private_key_passphrase = \"your_passphrase_here\"\n```\n\n### Environment Variables\n\n- `CONFIG` - Path to config file (default: `./config/config.toml`)\n- `DATABASE_URL`, `HTPASSWD`, `SSH_KEY`, `SESSION_KEY` - Take precedence over config file settings\n- `RUST_LOG` - Logging level (overrides config)\n- `VITE_API_URL` - Frontend API URL (for production builds)\n\n### SSH Key Setup\n\n**🔑 IMPORTANT**: The server requires a valid SSH private key file to function. The default path is `keys/id_ssm`. If no `config.toml` exists, set the `SSH_KEY` environment variable:\n\n```bash\nSSH_KEY=/path/to/your/private/key cargo run\n```\n\nThe server will provide detailed instructions for generating an SSH key pair if the file is missing.\n\n**Generating SSH Keys:**\n\nFor ed25519 keys (recommended):\n```bash\n# Generate key pair in the default location\nssh-keygen -t ed25519 -f keys/id_ssm -C 'ssm-server'\n\n# Set proper permissions\nchmod 600 keys/id_ssm\nchmod 644 keys/id_ssm.pub\n```\n\nFor RSA keys (alternative):\n```bash\nssh-keygen -t rsa -b 4096 -f keys/id_ssm -C 'ssm-server'\n```\n\n**Docker Setup:**\nIn Docker, the SSH key should be placed at `/app/keys/id_ssm` (mounted from `docker/data/keys/id_ssm`).\n\n### Authentication Setup\n\n**🔐 IMPORTANT**: Authentication is required for all API endpoints except login/logout.\n\n**Auto-creation**: If no htpasswd file exists when the server starts, it will automatically create one with a default `admin` user and a randomly generated password (displayed on console).\n\n**Manual creation**: You can also create the htpasswd file manually:\n\n```bash\n# Create htpasswd file with bcrypt encryption\nhtpasswd -cB .htpasswd admin\n\n# Add additional users\nhtpasswd -B .htpasswd another_user\n\n# Set secure session key for production\nexport SESSION_KEY=\"your-super-secret-session-key-change-in-production\"\n```\n\n**Security Notes:**\n- All API requests (except authentication) require session-based authentication\n- Session cookies are `HttpOnly` and secure\n- bcrypt encryption is used for password storage\n- Unauthenticated requests return `401 Unauthorized`\n\n### Docker Environment\n\nWhen using Docker, place configuration files in `docker/data/`:\n\n```\ndocker/data/\n├── auth/.htpasswd          # Authentication file\n├── config/config.toml      # Main configuration\n├── ssh-keys/              # SSH private keys\n├── db/                    # Database files\n└── logs/                  # Application logs\n```\n\n## 🔧 API Documentation\n\nFor detailed API documentation including all endpoints, authentication, and examples, see [API_DOCUMENTATION.md](backend/API_DOCUMENTATION.md).\n\n## 📁 Project Structure\n\n```\nssm/\n├── frontend/                 # React frontend application\n│   ├── src/\n│   │   ├── components/      # Reusable React components\n│   │   ├── pages/          # Route components\n│   │   ├── services/       # API communication\n│   │   ├── contexts/       # React contexts\n│   │   └── types/          # TypeScript definitions\n│   ├── package.json\n│   └── vite.config.ts\n├── backend/                 # Rust API backend\n│   ├── src/\n│   │   ├── routes/         # API endpoint handlers\n│   │   ├── db/            # Database models\n│   │   ├── ssh/           # SSH client implementation\n│   │   └── api_types.rs   # API request/response types\n│   ├── migrations/        # Database migrations\n│   └── Cargo.toml\n├── docker/                 # Docker deployment configuration\n│   ├── app/Dockerfile     # Multi-stage build configuration\n│   ├── compose.prod.yml   # Production deployment\n│   └── data/             # Persistent data volumes\n├── start-dev.sh           # Development environment startup\n├── config.toml           # Application configuration\n└── README.md\n```\n\n## 🔐 Security Features\n\n**🛡️ Comprehensive Security Implementation:**\n\n- **🔒 Required Authentication**: All API endpoints (except login) require session-based authentication\n- **🍪 Secure Sessions**: HttpOnly cookies with session signing keys for protection\n- **🔐 bcrypt Encryption**: Industry-standard password hashing for user credentials\n- **⚡ Session Validation**: Real-time authentication checks on every API request\n- **🚫 Unauthorized Access**: 401 responses for unauthenticated requests\n- **🔑 SSH Key Security**: Key-based authentication for all remote SSH connections\n- **✅ Input Validation**: Comprehensive validation and sanitization of all API inputs\n- **🗄️ Database Security**: Prepared statements and foreign key constraints\n- **🌐 CORS Configuration**: Controlled cross-origin resource sharing for frontend integration\n\n**Authentication Flow:**\n1. Login with `.htpasswd` credentials → Session cookie issued\n2. Include session cookie in subsequent API requests\n3. Server validates session on every protected endpoint\n4. Logout to invalidate session\n\n## 🚫 SSH Key Management Controls\n\n### Host Disabling\n- **Disabled Hosts**: Mark hosts as `disabled` to prevent all SSH operations\n- **Use Cases**: Maintenance windows, decommissioned servers, temporary disconnection\n- **Effects**: No SSH connections, no polling, no diff operations, no syncing\n\n### Readonly Controls\nPrevent SSM from modifying keyfiles by creating control files:\n\n- **`.ssh/system_readonly`**: Disables updates for all keyfiles on the host\n- **`.ssh/user_readonly`**: Disables updates for specific user keyfiles\n\nOptional: Include a reason in the file that will be displayed in the UI.\n\n## 🤝 Contributing\n\n### Development Guidelines\n\n1. **API-First Development**: Design API endpoints before frontend implementation\n2. **Type Safety**: Use TypeScript for frontend and structured types for backend\n3. **Component Reusability**: Build modular React components\n4. **Error Handling**: Implement comprehensive error handling and user feedback\n5. **Testing**: Write tests for both frontend and backend components\n\n### Code Style\n\n- **Frontend**: ESLint + TypeScript for code quality\n- **Backend**: `cargo fmt` and `cargo clippy` for Rust code\n- **Consistent Naming**: Use clear, descriptive names for variables and functions\n\n### Pull Request Process\n\n1. Fork the repository and create a feature branch\n2. Implement changes with appropriate tests\n3. Ensure both frontend and backend build successfully\n4. Update documentation if needed\n5. Submit pull request with clear description\n\n## 📄 License\n\nThis project is licensed under GPL-3.0. See LICENSE.txt for details.\n\n## 🔗 Links\n\n- **Repository**: https://github.com/styliteag/ssm\n- **Issues**: Report bugs and feature requests\n- **Documentation**: Additional documentation in `/docs` (coming soon)\n\n---\n\nFor technical implementation details, see [CLAUDE.md](CLAUDE.md) for development guidance.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstyliteag%2Fssm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstyliteag%2Fssm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstyliteag%2Fssm/lists"}