Architecture
Mezite is built around three core components: the Auth Service, the Proxy Service, and Agents. Together they provide authenticated, authorized, and audited SSH access to infrastructure without exposing backend servers directly to the network.
This page covers the system topology, component responsibilities, port layout, certificate trust model, SSH connection data flow, database schema, and deployment topologies.
System Overview
The diagram below shows how clients, the proxy, the auth service, agents,
and target SSH servers relate to each other. In a combined-mode deployment
(the default),
mezhub runs both Auth and Proxy in a single process.
┌──────────────┐ HTTPS :3080 ┌──────────────────────────────────┐
│ │ ──────────────────────────▶ │ mezhub │
│ msh CLI │ SSH :3023 │ ┌────────────┐ ┌────────────┐ │
│ Web UI │ ──────────────────────────▶ │ │ Proxy │ │ Auth │ │
│ │ │ │ Service │ │ Service │ │
└──────────────┘ │ │ │ │ │ │
│ │ :3080 HTTPS│ │ :3025 gRPC │ │
│ │ :3023 SSH │ │ │ │
│ │ :3024 Tun │ │ User CA │ │
│ │ │ │ Host CA │ │
│ │ │ │ Sessions │ │
│ └─────┬──────┘ └──────┬─────┘ │
│ │ gRPC :3025 │ │
│ └───────┬───────┘ │
└────────────────┼────────────────┘
│
┌──────┴──────┐
│ PostgreSQL │
│ :5432 │
└──────┬──────┘
│
┌──────────────────────────────────────────┘
│
Reverse Tunnel :3024
│
┌────────────────────────────┐ ┌─────────────────────────┐
│ mezd │ │ mezd │
│ (node-01) │ │ (node-02) │
│ │ │ │
│ SSH server │ │ SSH server │
└────────────────────────────┘ └─────────────────────────┘
Components
Auth Service
The Auth service is the cluster's brain. It runs as a gRPC server on port 3025
and is responsible for:
- User authentication — Verifying passwords (with optional TOTP), validating OIDC tokens, SAML assertions, LDAP credentials, and GitHub OAuth tokens, and issuing short-lived SSH certificates.
- Certificate authorities — Managing the User CA (signs user certificates) and Host CA (signs host certificates). Both use Ed25519 keys. CA private keys are stored encrypted in the database.
- RBAC enforcement — Evaluating role bindings against requested actions. Uses label-based matching with deny-overrides-allow semantics and template variables.
- Node registration — Accepting join tokens from agents, issuing host certificates, and maintaining the inventory of registered nodes.
- Session management — Tracking active SSH sessions, enforcing session TTLs, and storing session recordings.
- Audit event storage — Writing structured audit events to PostgreSQL for every authentication, authorization decision, session start/end, and administrative action.
Proxy Service
The Proxy service is the public-facing entry point. It terminates all client connections and routes them to the appropriate agent. It exposes three listeners:
- HTTPS (:3080) — Web UI, REST API, WebSocket session channels, and OIDC callback endpoints.
- SSH (:3023) — Native SSH protocol. Clients connecting via
msh sshland here. The proxy authenticates the user's certificate, resolves the target node, and forwards the connection through the agent's reverse tunnel. - Tunnel (:3024) — Persistent reverse-tunnel connections from agents. Each agent maintains a gRPC stream to this port; the proxy multiplexes client connections over these tunnels.
Agent (mezd)
Agents run on every target machine. They register with the Auth service using a one-time join token, receive a host certificate, and establish a persistent reverse tunnel to the Proxy. Key responsibilities:
- Reverse tunnel — Maintains a persistent outbound connection to the proxy's tunnel port (:3024). This means agents do not need any inbound firewall rules.
- SSH server — Runs an SSH server that accepts connections forwarded through the tunnel. Verifies user certificates against the User CA.
- Session recording — Captures terminal I/O at the PTY level after SSH decryption. The agent sees the clean text that the user sees in their terminal, not encrypted SSH protocol bytes. Recordings are streamed to the Auth service in real-time (node-sync mode) or uploaded after the session ends (node mode).
Certificate Authorities
Mezite operates two certificate authorities, both managed by the Auth service:
- User CA (Ed25519) — Issues short-lived SSH certificates to authenticated users. These certificates encode the user's identity, roles, and permitted principals.
- Host CA (Ed25519) — Issues host certificates to agents during registration. These certificates identify the host to connecting users, preventing MITM attacks.
CA private keys are stored in the certificate_authorities table
in PostgreSQL, optionally encrypted with the ca_key_passphrase setting.
Port Reference
| Port | Protocol | Component | Description |
|---|---|---|---|
3025 | gRPC | Auth Service | Internal auth API. Used by proxies, agents, and admin CLI. Should not be exposed publicly. |
3080 | HTTPS | Proxy Service | Web UI, REST API, OIDC callbacks. The primary public endpoint. |
3023 | SSH | Proxy Service | SSH client connections. Clients connect here via msh. |
3024 | gRPC | Proxy Service | Agent reverse-tunnel connections. Agents connect outbound to this port. |
5432 | PostgreSQL | Database | Mezite's state store. Only auth and admin tools connect here. |
SSH Connection Data Flow
When a user runs msh ssh --login=user node-01, the following
sequence occurs:
1. msh opens an SSH connection to Proxy :3023
2. Proxy verifies the user's SSH certificate (signed by User CA)
3. Proxy evaluates RBAC: does this user's role allow login "user" on node-01?
4. Proxy looks up node-01 in the Auth service node registry
5. Proxy resolves node-01 to the agent's reverse tunnel
6. Proxy forwards the SSH channel through the tunnel to the agent
7. Agent verifies the user certificate against the User CA public key
8. Agent starts an SSH session as the requested login user
9. Agent allocates a PTY and records terminal I/O at the PTY level
10. Agent streams recording chunks to Auth via gRPC in real-time (node-sync mode)
11. Agent streams terminal I/O back through the tunnel to the client
12. Auth stores the recording and writes audit events: session.start, session.end Certificate Trust Model
Mezite uses a mutual SSH certificate trust model. Both users and hosts present certificates signed by trusted CAs. This eliminates the need for password-based SSH, shared keys, or authorized_keys files.
┌─────────────────────────────────────────────────────────┐
│ Auth Service │
│ │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ User CA │ │ Host CA │ │
│ │ (Ed25519) │ │ (Ed25519) │ │
│ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │
└──────────┼─────────────────────────────┼────────────────┘
│ │
▼ ▼
┌────────────────┐ ┌────────────────┐
│ User Certs │ │ Host Certs │
│ │ │ │
│ identity: bob │ │ host: node-01 │
│ roles: [admin] │ │ cluster: prod │
│ principals: │ │ valid: 24h │
│ [root, bob] │ │ │
│ valid: 12h │ │ │
└────────────────┘ └────────────────┘
│ │
│ presented to │ presented to
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Agent (host) │ │ msh (user) │
│ trusts │ │ trusts │
│ User CA │ │ Host CA │
└──────────────┘ └──────────────┘
The trust chain works as follows:
- User login — When a user authenticates (password+TOTP, OIDC, SAML, LDAP, or GitHub OAuth), the Auth service issues a short-lived SSH certificate signed by the User CA. The certificate encodes the user's name, roles, and allowed principals.
- Host registration — When an agent joins the cluster with a valid token, the Auth service issues a host certificate signed by the Host CA. The certificate encodes the node's hostname and cluster membership.
- Mutual verification — During an SSH connection, the agent verifies the user's certificate against the User CA public key, and the user's client verifies the host's certificate against the Host CA public key. Both sides reject connections if the certificate is expired, revoked, or signed by an unknown CA.
Database Schema
All cluster state is stored in the database (SQLite or PostgreSQL). The
schema is managed by
mezhub using
golang-migrate and auto-migrates
on startup. Below are the primary tables and their purpose.
| Table | Description | Key Columns |
|---|---|---|
users | User accounts. Stores credentials (bcrypt hashes for local auth), roles, and metadata. | id, username, password_hash, roles, created_at, updated_at |
roles | RBAC role definitions. Each role specifies allowed logins, node labels, and permissions. | id, name, allowed_logins, node_labels, max_session_ttl |
certificate_authorities | CA keypairs (User CA and Host CA). Private keys are optionally encrypted. | id, type, public_key, private_key, cluster_name, created_at |
nodes | Registered SSH nodes. Updated by agents on heartbeat. | id, hostname, addr, labels, last_heartbeat, tunnel_id |
sessions | Active and completed SSH sessions. | id, type, user, node_id, started_at, ended_at, recording_path |
audit_events | Immutable audit log. Every authentication, authorization decision, session lifecycle event, and administrative action is recorded here. | id, event_type, user, resource, action, status, metadata, created_at |
access_requests | Just-in-time access requests. | id, user, requested_roles, reason, state, resolved_by, created_at, resolved_at, expires_at |
auth_connectors | SSO connector configurations (OIDC, SAML). | id, type, name, config, created_at |
Migration files live in server/migrate/migrations/ and follow the
NNN_description.up.sql / NNN_description.down.sql naming convention. Migrations are applied automatically when mezhub starts.
Deployment Topologies
Combined Mode (default)
A single mezhub process runs both Auth and Proxy services. This
is the simplest deployment and works well for small to medium clusters (up to
~500 nodes).
┌───────────────────────────┐
│ mezhub │
│ Auth :3025 + Proxy :3080 │
│ + SSH :3023 │
│ + Tunnel :3024 │
└─────────────┬─────────────┘
│
PostgreSQL :5432 Separated Mode
For larger deployments or when you need independent scaling, run Auth and Proxy as separate processes (or containers). Multiple proxy instances can share a single Auth backend.
┌─────────────────┐
│ Load Balancer │
└────────┬────────┘
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Proxy #1 │ │ Proxy #2 │ │ Proxy #3 │
│ :3080 :3023│ │ :3080 :3023│ │ :3080 :3023│
│ :3024 │ │ :3024 │ │ :3024 │
└──────┬─────┘ └──────┬─────┘ └──────┬─────┘
│ │ │
└───────────────┼───────────────┘
│ gRPC :3025
┌───────────────┼───────────────┐
▼ ▼ ▼
┌────────────┐ ┌────────────┐
│ Auth #1 │ │ Auth #2 │ (active/standby)
└──────┬─────┘ └──────┬─────┘
│ │
└───────┬───────┘
▼
PostgreSQL
(primary + replica) In separated mode, each proxy handles SSH connections (:3023), HTTPS traffic (:3080), and agent tunnels (:3024). All proxies connect to the Auth service over gRPC (:3025) for authentication and authorization decisions.
Next Steps
- Quickstart — Deploy a combined-mode cluster in five minutes.
- Configuration — Full reference for every setting.
- SSH Access Guide — Deep dive into SSH certificate authentication and session recording.
- RBAC Guide — Define roles and control who can access what.
- Systemd Deployment — Run Mezite as a production service.