PSSP broker guide
Operations guide

Run and configure the PSSP broker

The broker is an independent Windows/Linux/macOS service. It authenticates clients, checks ACLs, stores finite in-memory topic buffers, distributes opaque bytes, and never parses media or application payloads.

New management and worker-group configuration

See Brocker configuration for the authenticated management listener, allowed-service scopes, SQLite isolation, workerID, shared worker groups, broadcast clients, and WebService environment variables. When the Broker is running, applications must use that management listener instead of opening SQLite or invoking mutating CLI commands.

Where to find and how to run pssp-broker

The Cargo package and executable are named pssp-broker, but its source directory is named broker/. A repository checkout does not automatically install the executable into the shell's PATH. Therefore, a bare command such as pssp-broker list-principals ... may report “command not found” even though the Broker source and a locally built binary are present.

WhatLocation or command from the repository rootWhen to use it
Broker sourcebroker/Rust source, Broker configuration examples, deployment definitions, and its package manifest.
Cargo-managed executioncargo run -p pssp-broker -- <arguments>Recommended for repository development. Cargo builds the package when necessary and passes everything after -- to the Broker.
Debug executabletarget/debug/pssp-broker
Windows: target\debug\pssp-broker.exe
Created by cargo build -p pssp-broker or cargo run -p pssp-broker.
Release executabletarget/release/pssp-broker
Windows: target\release\pssp-broker.exe
Created by cargo build --release -p pssp-broker; use this artifact for deployment.
Installed executablepssp-brokerWorks only after the executable has been installed or copied to a directory in PATH. A service may instead use an explicit absolute path.

These forms are equivalent for a locally built debug Broker:

# Let Cargo build and run it
cargo run -p pssp-broker -- --help
cargo run -p pssp-broker -- list-principals --config broker/config/pssp.example.toml

# Run the built artifact directly on macOS/Linux
./target/debug/pssp-broker --help
./target/debug/pssp-broker list-principals --config broker/config/pssp.example.toml

# Windows PowerShell
.\target\debug\pssp-broker.exe --help
How to read commands on this page

Commands beginning with bare pssp-broker assume an installed deployment whose executable is in PATH. When working from the repository root, replace that prefix with cargo run -p pssp-broker --, ./target/debug/pssp-broker, or the appropriate release/Windows path. Check availability with command -v pssp-broker on macOS/Linux or Get-Command pssp-broker in PowerShell.

Quick start: local trusted network

  1. Build or check the workspace from the repository root.
    cargo check --workspace
  2. Initialize the broker-owned SQLite database. With the included development config and repository-root working directory, this creates data/pssp-broker.sqlite3. The command securely prompts for the password.
    cargo run -p pssp-broker -- setup --config broker/config/pssp.example.toml \
      --bootstrap-client-id pssp-admin --bootstrap-username admin
  3. Run the provided profile.
    cargo run -p pssp-broker -- serve --config broker/config/pssp.example.toml
Plain transport is not secure

The local profile uses direct TCP/UDP. The SQLite password is Argon2id-hashed at rest, but credentials and payloads are readable on the network. Never expose this profile to an untrusted network.

Choose a transport mode

Use caseTLSPSSP AESExplicit transport flagResult
ProductiontruetruefalseTLS 1.3 wraps TCP. A fresh per-session AES-256-GCM key protects PSSP records. UDP is AES protected after bind.
Certificate-free protected networkfalsetruefalseClient pins the Broker X25519 public key. Ephemeral X25519 + HKDF derives a new AES key before encrypted authentication; the symmetric key never crosses TCP.
Trusted/private networkfalsefalsetrueDirect TCP QoS 1 and UDP QoS 0. No TLS/AES; broker issues a temporary RAM-only UDP association token after authentication.
Independent controls

TLS and PSSP AES can be enabled separately. The plaintext opt-in transport.allow_insecure_tcp_udp = true is required only when both are disabled, and is rejected whenever TLS or AES is enabled.

# Trusted/private-network mode only
[tls]
enabled = false

[encryption]
enabled = false

[transport]
allow_insecure_tcp_udp = true

Configuration reference

Start from broker/config/pssp.example.toml for local testing or broker/config/pssp.production.example.toml for a secure deployment.

SectionKeyDescription
[listener]tcp_bind, udp_bindTCP QoS 1/control and UDP QoS 0 listener addresses. Default is 0.0.0.0:6688 for both.
[tls]enabledWrap TCP with TLS 1.3. Requires certificate_file and private_key_file.
[encryption]enabledEnable PSSP AES-256-GCM session records independently from TLS. With TLS off, also configure static_private_key and pin its derived X25519 public key in each client.
[transport]allow_insecure_tcp_udpRequired opt-in only for no-TLS/no-AES direct TCP/UDP mode. Must be false whenever TLS or AES is enabled.
[limits]max_connectionsMaximum simultaneous TCP sessions; default 2,000.
[limits]max_header_bytes, max_payload_bytesMaximum PSSP JSON header and opaque payload sizes; defaults 1,024 and 65,536 bytes.
[limits]max_outbound_queue_bytesPer-session sending capacity. Slow subscribers do not block publishers; their live delivery can be dropped while retained topic data remains available for replay.
[limits]idle_timeout_secondsMaximum silent TCP interval before the session closes.
[limits]subscriber_resume_ttl_secondsHow long broker keeps an offline subscriber's acknowledgement cursor for resume.
[topic_defaults]max_bytes, max_messages, max_age_secondsPer-topic in-memory retention limits. Eviction produces a GAP notice to affected subscribers.
[storage]sqlite_pathLocation of the broker-owned SQLite database for principals, Argon2id password hashes, ACLs, and credential audit events. Relative paths are resolved from the Broker process working directory; prefer an absolute path for installed services.
[storage]unix_owner_user, unix_owner_groupOptional Unix service identity that owns the protected SQLite directory, database, and sidecars after a mutating CLI command. Set both or neither. The account and group must already exist, and setup must run with permission to apply that ownership.
[storage]auth_cache_seconds, auth_cache_entriesBounded authentication cache lifetime and entry count. Account changes take effect after the cache expires.

Database creation and filesystem access

storage.sqlite_path is the source of truth; the Broker does not always place SQLite in one operating-system directory. The local config selects data/pssp-broker.sqlite3. The supplied Linux production config selects /var/lib/pssp/pssp-broker.sqlite3 only when that template value is retained, while the Windows production config selects C:\ProgramData\PSSP\pssp-broker.sqlite3. For other deployments, choose an absolute protected path and use the same config for setup, administration, and serving.

setup creates missing parent directories and the database, initializes the schema, creates the bootstrap administrator, and grants that administrator publish and subscribe access to #. On Unix it restricts the database and existing SQLite sidecars to 0600. If unix_owner_user and unix_owner_group are configured, setup and later mutating administration commands also assign the directory and files to that service identity and restrict the parent directory to 0700.

Two separate permission systems

Unix ownership and modes only let the Broker process open SQLite. They do not authorize a PSSP client. Client topic access comes from SQLite ACL records managed with grant-acl and revoke-acl; a principal created with create-principal starts with no topic grants.

Credentials and topic ACLs

SQLite is the sole authentication source. The Broker never calls a WebService, and clients only send the standard AUTH record. During offline bootstrap/maintenance, administrators may use create-principal or provision-principal. Once serve is running, the Broker exclusively locks SQLite and online provisioning tools must use the authenticated, scoped management listener documented in Brocker configuration.

Generic non-interactive provisioning

pssp-broker provision-principal --config /etc/pssp/pssp.toml \
  --client-id any-client-001 \
  --username any-user-001 \
  --principal-kind device \
  --publish '/tenant/001/telemetry' \
  --publish '/tenant/001/audio' \
  --subscribe '/tenant/001/commands'

The command prints a versioned JSON object containing client_id, username, password, principal_kind, publish, and subscribe. Capture stdout through a protected pipe and deliver the password once. Re-running the command for the same client ID and username rotates the password, re-enables the principal, and replaces its ACLs in one SQLite transaction. Do not log the JSON output.

Provision a device account

  1. Choose a stable client ID and username, then create the principal. The CLI securely prompts for the new password; nothing is displayed while it is entered.
    pssp-broker create-principal --config /etc/pssp/pssp.toml \
      --client-id ox-device-OXRC-001 \
      --username device-OXRC-001 \
      --principal-kind device
  2. Grant permission to publish the device heartbeat over QoS 0 UDP.
    pssp-broker grant-acl --config /etc/pssp/pssp.toml \
      --client-id ox-device-OXRC-001 --username device-OXRC-001 \
      --action publish \
      --topic-filter '/api/devices/OXRC-001/heartbeat'
  3. Grant permission to publish audio over QoS 1 TCP.
    pssp-broker grant-acl --config /etc/pssp/pssp.toml \
      --client-id ox-device-OXRC-001 --username device-OXRC-001 \
      --action publish \
      --topic-filter '/api/devices/OXRC-001/audio/chunks'
  4. Grant permission to subscribe to QoS 1 commands.
    pssp-broker grant-acl --config /etc/pssp/pssp.toml \
      --client-id ox-device-OXRC-001 --username device-OXRC-001 \
      --action subscribe \
      --topic-filter '/api/devices/OXRC-001/commands'
  5. Verify the account and its effective ACL entries.
    pssp-broker list-principals --config /etc/pssp/pssp.toml
    pssp-broker list-acls --config /etc/pssp/pssp.toml \
      --client-id ox-device-OXRC-001 --username device-OXRC-001
  6. Configure the client with the exact client ID, username, and password entered above, plus the Broker address and pinned AES-only public key.
Passwords cannot be recovered

The Broker stores only an Argon2id password hash. list-principals can show the client ID and username, but no command can display the original password. If it is lost, rotate it and securely update the client.

Account lifecycle

Rotate a lost or expired password; the CLI securely prompts for the replacement:

pssp-broker rotate-password --config /etc/pssp/pssp.toml \
  --client-id ox-device-OXRC-001 --username device-OXRC-001

Revoke a permission by specifying the exact action and topic filter originally granted:

pssp-broker revoke-acl --config /etc/pssp/pssp.toml \
  --client-id ox-device-OXRC-001 --username device-OXRC-001 \
  --action publish \
  --topic-filter '/api/devices/OXRC-001/audio/chunks'

Disable an account by omitting --enabled; add --enabled to enable it again:

# Disable
pssp-broker set-principal-enabled --config /etc/pssp/pssp.toml \
  --client-id ox-device-OXRC-001 --username device-OXRC-001

# Enable again
pssp-broker set-principal-enabled --config /etc/pssp/pssp.toml \
  --client-id ox-device-OXRC-001 --username device-OXRC-001 --enabled

Permanently delete an account and all of its ACLs only when it is no longer needed:

pssp-broker delete-principal --config /etc/pssp/pssp.toml \
  --client-id ox-device-OXRC-001 --username device-OXRC-001

For offline non-interactive provisioning with a caller-supplied secret, use create-principal --password-file or --password-stdin instead of putting a password directly in shell history. For an offline Broker-generated one-time secret and atomic ACL setup, use provision-principal. These direct commands fail while the Broker is running; online changes go through the management listener and invalidate the Broker authentication cache immediately.

Publish entries must be concrete topics. ACL entries and subscriptions can use + for one segment and final # for descendants. Access is denied unless a matching allow rule exists.

Topic buffers, acknowledgement, and resource bounds

Publisher path

A QoS 1 publisher supplies publisherSessionId + publisherSequence. The broker accepts a sequence only once, places the payload in the topic ring, returns PUBACK, then fans out to subscribers.

Subscriber path

A subscriber sends MSGACK only after its application accepts the data. For a durable integration, persist or durably queue before the ACK. Reconnect with the same workerID and use resume.

Topic memory remains volatile: a broker restart removes topic rings, deduplication state, session keys, subscriptions, UDP associations, and resume cursors. Only principals, password hashes, ACLs, and credential audit events persist in SQLite.

Secure deployment

  1. Build the release binary.
    cargo build --release -p pssp-broker
  2. Copy the appropriate production template to a protected location. Set storage.sqlite_path to an absolute protected database path for that deployment; do not assume the repository development path or a path from another operating system.
  3. On Unix, create the service account/group first and set both unix_owner_user and unix_owner_group to that identity. On Windows, protect the selected ProgramData directory for the scheduled-task identity.
  4. Configure TLS or the AES-only X25519 private key and keep allow_insecure_tcp_udp = false.
  5. Configure the separate management key and explicit allowed-service scopes described in Brocker configuration.
  6. Run pssp-broker setup with the final config. It creates and secures SQLite and the bootstrap administrator. Complete any offline bootstrap administration before starting the service.
  7. Install the supplied systemd, launchd, or Windows Task Scheduler definition and ensure it uses the same config path. After startup, make credential changes through the authenticated management listener.

Windows background task

Build with the Rust MSVC toolchain, use config/pssp.windows.production.example.toml as the protected configuration template, then run the installer from elevated PowerShell:

.\broker\deploy\Install-PsspBrokerTask.ps1 `
  -BrokerPath 'C:\Program Files\PSSP Broker\pssp-broker.exe' `
  -ConfigPath 'C:\ProgramData\PSSP\pssp.toml'

The PowerShell installer creates an automatic startup Task Scheduler background task as LocalSystem with restart recovery settings. A normal console binary cannot be installed directly as a Windows Service without a Service Control Manager wrapper. Use -Action Uninstall to remove the task. Add Windows Firewall rules for TCP 6688 and UDP 6688 only for approved networks.

Firewall rule

Allow TCP 6688 for QoS 1/control and UDP 6688 for QoS 0 only from approved networks. If UDP heartbeats are not needed, block UDP at the network boundary.

Operational behaviour and troubleshooting

For startup diagnostics, database-permission recovery, complete AES-only setup, and a larger error catalog, see the PSSP troubleshooting guide.

ObservationMeaning / action
Client rejected before traffic beginsCheck TLS checkbox and certificate name match when TLS is enabled. In TLS-off AES mode, paste the exact pinned Broker X25519 public key into the client.
authentication_failedConfirm the exact client ID/username exists and is enabled in SQLite, the password is current, and the auth cache has expired after a recent change.
publish_not_authorized or subscribe_not_authorizedGrant or revoke the principal's SQLite ACLs with the broker CLI.
GAP receivedThe requested topic data passed the configured memory limit. Recover it from application storage or enlarge retention after sizing memory deliberately.
UDP bind/ping failsKeep TCP connected, permit UDP 6688 through firewall/NAT, and use the same broker host/port. Complete the selected TLS and/or AES session setup first.
Same client ID has two sessionsThis is intentional. Each connection has a unique broker connection ID, session key, outbound queue, and UDP association.