docs: document standalone mode; bump to 1.4.0

Add README/docs/secrets.js.example coverage for the new
@simpleworkjs/orm-backed standalone mode (no LDAP/SSO), and promote the
CHANGELOG's Unreleased entry to 1.4.0.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-26 21:33:27 -04:00
parent 4879769cc7
commit d33e324b31
9 changed files with 164 additions and 7 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
title: Jump Host
description: An SSH jump host for the theta42 stack — LDAP-authenticated, directory-driven host bridging with audit and metrics.
description: An SSH jump host for the theta42 stack — directory-driven host bridging with audit and metrics; LDAP + SSO Manager by default, or fully standalone.
url: "https://theta42.github.io"
baseurl: "/jump-host"
logo: /assets/img/theta42.svg
+22
View File
@@ -112,6 +112,28 @@ Audit events and counters live in redis. Each event captures: user, auth method,
mode (grammar/picker), target slug/address/port, channel type, client IP,
success + failure reason, downstream host-key fingerprint, timing, and bytes in/out.
## Standalone mode
Everything above describes the default backend. Set `standalone.enabled: true`
and two modules become conditional facades, swapping their entire
implementation at `require` time based on that flag — nothing else in the
codebase (`ssh_server.js`, `bridge.js`, `key_inject.js`, `tui_picker.js`, the
web UI) changes or even knows which mode it's running in:
- **`models/user_ldap.js`** — LDAP client, or `models/user_file.js` (an
[@simpleworkjs/orm](https://www.npmjs.com/package/@simpleworkjs/orm)-backed
store implementing the same `getUser` / `getGroups` / `checkPassword` /
`addSshKey` interface).
- **`utils/access.js`** — LDAP groups + SSO `/api/discovery`, or
`utils/hosts_file.js` (same ORM package, same `accessibleHosts()` interface).
In standalone mode there's no group-based authorization: every stored host
is accessible to every stored user.
The ORM is Sequelize underneath, defaulting to a local SQLite file but
accepting any Sequelize-supported dialect via `conf.orm`. See
[Installation](installation.html#standalone-mode) for config and how to add
users/hosts (there's no admin UI for standalone data yet).
## Where it sits in the stack
- **[SSO Manager](https://theta42.github.io/sso-manager-node/)** — provides the
+4
View File
@@ -74,6 +74,10 @@ changes.
Targets that don't resolve to a host you're allowed to reach are refused (and
audited). Raw IPs that aren't a known directory host are denied by default.
> On a [standalone](architecture.html#standalone-mode) jump host (no LDAP/SSO),
> every registered host is reachable by every registered user — there's no
> group-based restriction to ask an admin about.
## Authentication
The jump host authenticates **you** against the directory:
+9 -1
View File
@@ -1,7 +1,7 @@
---
layout: default
title: Home
description: An SSH jump host for the theta42 stack — one public host, LDAP login, and directory-driven access to every downstream machine you're entitled to.
description: An SSH jump host for the theta42 stack — one public host and directory-driven access to every downstream machine you're entitled to; LDAP by default, or fully standalone.
---
# Jump Host
@@ -30,6 +30,12 @@ Part of the theta42 self-hosted identity stack, alongside
*(click any screenshot to view full size)*
Don't want to run LDAP or the SSO Manager? **Standalone mode** stores users
and hosts in a local SQL database instead (SQLite by default, any
Sequelize-supported dialect if you want something else) — same SSH front door,
key injection, and audit trail. See
[Installation](installation.html#standalone-mode) to get started.
## Two ways to connect
**Direct (WinSCP/SFTP-friendly):**
@@ -88,6 +94,8 @@ This jump host answers both from your directory:
audit log, per-user/per-host counters
- **Full audit trail** — who, target, method, result, bytes, duration, and the
downstream host-key fingerprint
- **Standalone mode** — no LDAP, no SSO Manager; users and hosts live in a
local SQL database (Sequelize, any dialect — SQLite by default)
- Packaged like the rest of the stack: one-command Docker, idempotent bare-metal
installer, or bundled in theta-env
+46 -1
View File
@@ -1,7 +1,7 @@
---
layout: default
title: Installation
description: Install the jump host three ways — bundled in the theta-env stack, standalone Docker, or bare metal — plus the required LDAP write-ACL and port-22 options.
description: Install the jump host three ways — bundled in the theta-env stack, standalone Docker, or bare metal — plus standalone mode (no LDAP/SSO), the LDAP write-ACL, and port-22 options.
---
# Installation
@@ -10,6 +10,51 @@ Three ways to run the jump host, in increasing manual effort. All read their
config through [@simpleworkjs/conf](https://www.npmjs.com/package/@simpleworkjs/conf)
(`conf/base.js` < `conf/<NODE_ENV>.js` < the `CONF_SECRETS` file < `app_*` env).
## Standalone mode (no LDAP/SSO) {#standalone-mode}
Skip LDAP and the SSO Manager entirely. Not to be confused with "Standalone
Docker" below, which is still LDAP + SSO, just run outside theta-env. Set in your secrets/config:
```js
standalone: { enabled: true },
orm: { dialect: 'sqlite', storage: './data/standalone.sqlite', logging: false },
```
`orm` is passed straight to Sequelize, so any supported dialect works — SQLite
is just the zero-dependency default. Everything downstream of auth (bridging,
key injection, the web UI, audit) is unchanged.
There's no admin UI for standalone users/hosts yet, so add them directly with
the ORM models:
```js
const StandaloneUser = require('./models/standalone_user');
const StandaloneHost = require('./models/standalone_host');
const bcrypt = require('bcrypt');
await StandaloneUser.create({
uid: 'alice',
passwordHash: await bcrypt.hash('a real password', 10),
sshPublicKeys: ['ssh-ed25519 AAAA... alice@laptop'],
groups: [],
});
await StandaloneHost.create({
slug: 'host_web01',
displayName: 'web01',
kind: 'host',
metadata: { ip: '10.0.0.5', sshPort: 22 },
});
```
Every host in the standalone inventory is reachable by every standalone user —
there's no group-based authorization yet (`groups` on `StandaloneUser` is
accepted for interface parity with the LDAP path, not enforced).
The rest of this page (requirements, the LDAP write-ACL, the three install
paths) describes the default LDAP + SSO mode — skip it if you're running
standalone.
## Requirements
- The [SSO Manager](https://theta42.github.io/sso-manager-node/) (OpenLDAP