Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# 0.1.0-alpha.0 - Jun. 4, 2026

- VSS service implementing VSS protocol version 0. (#34, #35)
- Rust workspace for the VSS server, API contract types, authentication implementations, and storage backend
implementations. (#34, #35, #43, #72, #79, #101)
- PostgreSQL storage backend with database initialization, migrations, TLS support, key-level versioning, store-level
global versioning, transactional writes, deletes, and paginated key-version listing. (#35, #55, #67, #96)
- Signature-based and JWT-based authorization implementations, with cfg-gated no-op authorization for local development
and tests. (#34, #43, #72, #79, #87)
- Configuration through TOML file and environment variables, including bind address, request body size, logging, JWT
RSA public key, and PostgreSQL settings. (#46, #67, #72, #73, #76, #87)
- Server logging to stdout/stderr and file, with SIGHUP log-file reopening and shutdown on CTRL-C/SIGTERM. (#34, #87)
- Prometheus-compatible `/metrics` health metric. (#99)
- Docker and Docker Compose files for local deployment. (#76, #80)
- Getting-started documentation. (#102)
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ members = ["server", "api", "impls", "auth-impls"]
default-members = ["server"]

[workspace.package]
version = "0.1.0-alpha.0"
rust-version = "1.85.0"

[profile.release]
Expand Down
27 changes: 14 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ VSS is also integrated with [LDK-node] v0.4.x as alpha support.

### Development

* **Build & Deploy**: Refer to [docs/getting-started.md](docs/getting-started.md) for instructions related to
building and deploying VSS.
* **Build & Deploy**: Refer to [docs/getting-started.md](docs/getting-started.md) for concrete PostgreSQL setup,
authentication configuration, local no-auth development mode, and deployment commands.
* **Hosting**: VSS can either be self-hosted or deployed in the cloud. If a service provider is hosting VSS for multiple
users, it must be configured with **HTTPS**, **Authentication/Authorization**, and **rate-limiting**.
* **Authentication and Authorization**: VSS supports authentication via
[Proof-of-Private-Key-Knowledge](#Authentication) or [JWT](https://datatracker.ietf.org/doc/html/rfc7519).
[Proof-of-Private-Key-Knowledge](#authentication) or [JWT](https://datatracker.ietf.org/doc/html/rfc7519).
The API also offers hooks for simple HTTP header-based authentication. Note that the security of authentication
heavily relies on using HTTPS for all requests.
* **Scaling**: VSS itself is stateless and can be horizontally scaled easily. VSS can be configured to point to a
Expand All @@ -99,18 +99,19 @@ VSS is also integrated with [LDK-node] v0.4.x as alpha support.

### Authentication

By default, VSS uses a simple authentication scheme whereby each client must provide a valid signature for a
client-specified public key. The public key identifies the storage that belongs to the client. This scheme does
not impose **any** restrictions on who can interact with VSS; it **only** ensures that each client can only
access *their own* storage. Therefore, this scheme **must** be paired with a network-level gatekeeper to prevent
unauthorized interactions with VSS.
Default builds include signature and JWT authentication. If `jwt_auth_config.rsa_pem` or `VSS_JWT_RSA_PEM` is
configured, VSS verifies RS256 bearer tokens from the HTTP `Authorization` header. The JWT `sub` claim identifies
the storage user. VSS only implements token verification; operators must provide their own token issuance service.

The other option offered is JWT authentication. This form of authentication validates whether a client should
be given access to VSS, *and* which storage the client has access to. VSS only implements the verification half of this
scheme, and users must provide their own JWT issuance service if this solution is chosen.
If JWT is not configured, VSS uses signature authentication. Each client provides a valid signature for a
client-specified secp256k1 public key in the HTTP `Authorization` header. The public key identifies that client's
storage. This scheme does not impose **any** restrictions on who can interact with VSS; it **only** ensures that each
client can only access *their own* storage. Therefore, this scheme **must** be paired with a network-level gatekeeper
and rate limiting to prevent unauthorized interactions with VSS.

Finally, there is an option to completely disable all forms of authentication to VSS. This option should *only* be
used in local development and testing.
Finally, there is a cfg-gated option to disable all forms of authentication for local development and testing. Do not
publicly expose no-auth builds. See [docs/getting-started.md](docs/getting-started.md#authentication-setup) for exact
config and build commands.

### Summary

Expand Down
2 changes: 1 addition & 1 deletion api/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "api"
version = "0.1.0"
version.workspace = true
edition = "2021"
rust-version.workspace = true

Expand Down
2 changes: 1 addition & 1 deletion auth-impls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "auth-impls"
version = "0.1.0"
version.workspace = true
edition = "2021"
rust-version.workspace = true

Expand Down
159 changes: 131 additions & 28 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
@@ -1,42 +1,145 @@
# Versioned Storage Service (Rust)
# Getting Started

### Prerequisites
This guide covers a local source build and the required PostgreSQL and authentication setup. For
the threat model and auth overview, see the root [README](../README.md).

- Install Rust and Cargo (https://www.rust-lang.org/tools/install).
- Install PostgreSQL 15 (https://www.postgresql.org/download/)
- Install OpenSSL (used for TLS connections to the PostgreSQL backend: https://docs.rs/openssl/latest/openssl/#automatic)
## Prerequisites

### Building
- Rust and Cargo, using at least the repository MSRV of 1.85.0.
- PostgreSQL 15 or newer.
- OpenSSL development/runtime libraries for PostgreSQL TLS support.

```
git clone https://github.com/lightningdevkit/vss-server.git
cd vss-server
## Quick Start with Docker PostgreSQL

Start only the PostgreSQL service from the included Compose file:

```bash
docker compose up -d postgres
cargo build --release
cargo run -- server/vss-server-config.toml
```

The sample config connects to `postgres:postgres@127.0.0.1:5432`, creates the `vss` database if it
does not exist, and runs schema migrations on startup. The VSS endpoint is
`http://localhost:8080/vss`; `/metrics` is available without VSS authentication:

```bash
curl -f http://localhost:8080/metrics
```

The default `cargo run` command starts the server with signature authentication, because the sample
config does not include a JWT key. VSS API requests still need a valid `Authorization` header. To
exercise VSS API endpoints without auth headers in a local-only environment, use
[Local No-Auth Mode](#local-no-auth-mode).

To run both PostgreSQL and the server in containers:

```bash
docker compose up --build
```

### Running
1. **Edit Configuration**: Modify `./server/vss-server-config.toml` to set application configuration and
environment variables as needed.
2. VSS will setup a PostgreSQL database on first launch if it is not found. You can also manually create the database
using the statement at `./impls/src/postgres/sql/v0_create_vss_db.sql`.
3. Start server:
```
cargo run server/vss-server-config.toml
```
4. VSS endpoint should be reachable at `http://localhost:8080/vss`.
## PostgreSQL Setup

VSS first connects to `default_database`, then creates `vss_database` if it is missing, then connects
to `vss_database` and applies migrations. With the sample config these are `postgres` and `vss`.

The configured PostgreSQL role must be able to connect to `default_database`. It must also either:

- have permission to run `CREATE DATABASE vss` when `vss_database` does not exist, or
- use an already-created `vss_database` and have privileges to create/alter tables, indexes,
sequences, and rows in that database.

For an existing local PostgreSQL instance, create the database yourself if the VSS user cannot create
databases:

```bash
createdb -U postgres vss
```

Then update `[postgresql_config]` in `server/vss-server-config.toml` or set the corresponding
environment variables:

```bash
VSS_PSQL_USERNAME=postgres
VSS_PSQL_PASSWORD=postgres
VSS_PSQL_ADDRESS=127.0.0.1:5432
VSS_PSQL_DEFAULT_DB=postgres
VSS_PSQL_VSS_DB=vss
```

## Authentication Setup

Default builds include both `jwt` and `sigs` features. At startup, VSS uses JWT auth if an RSA public
key is configured; otherwise it uses signature auth. Both schemes read the HTTP `Authorization`
header.

### Signature Auth

No TOML setting is required. Leave `[jwt_auth_config]` unset and the default build will require each
request to include a proof of private key knowledge in `Authorization`. The proof is the compressed
secp256k1 public key hex, followed by a compact ECDSA signature hex, followed by a Unix timestamp.
The signature covers VSS's signing constant, the public key, and the timestamp. Signature auth
isolates storage by public key, but does not decide who may create a new storage identity;
production deployments still need HTTPS, rate limiting, and an external access control layer.

### JWT Auth

Configure the RSA public key used to verify RS256 JWTs:

```toml
[jwt_auth_config]
rsa_pem = """
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
"""
```

or set `VSS_JWT_RSA_PEM`. Clients must send `Authorization: Bearer <jwt>`. Tokens must be RS256,
include `sub` and `exp` claims, and omit `aud`; `sub` becomes the VSS storage user token. VSS only
verifies tokens, you must run the service that issues them.

### Local No-Auth Mode

For local development only, build with the cfg-gated no-op authorizer:

```bash
RUSTFLAGS="--cfg noop_authorizer" cargo run --no-default-features -- server/vss-server-config.toml
```

Do not expose this mode outside a local test environment.

## Configuration Reference

Default builds read the following settings. Each listed TOML option can be overridden by its
environment variable.

| TOML setting | Environment variable | Purpose |
| --- | --- | --- |
| `server_config.bind_address` | `VSS_BIND_ADDRESS` | HTTP listen address, for example `127.0.0.1:8080`. |
| `server_config.max_request_body_size` | `VSS_MAX_REQUEST_BODY_SIZE` | Request body limit in bytes. Defaults to 1 GiB. |
| `jwt_auth_config.rsa_pem` | `VSS_JWT_RSA_PEM` | RSA public key for JWT verification. Requires the `jwt` feature, which is enabled by default. |
| `postgresql_config.username` | `VSS_PSQL_USERNAME` | PostgreSQL user. |
| `postgresql_config.password` | `VSS_PSQL_PASSWORD` | PostgreSQL password. |
| `postgresql_config.address` | `VSS_PSQL_ADDRESS` | PostgreSQL host and port. |
| `postgresql_config.default_database` | `VSS_PSQL_DEFAULT_DB` | Database used for startup and database creation. |
| `postgresql_config.vss_database` | `VSS_PSQL_VSS_DB` | VSS application database. |
| `postgresql_config.tls` | `VSS_PSQL_TLS` | Enables PostgreSQL TLS with system trust roots. |
| `postgresql_config.tls.crt_pem` | `VSS_PSQL_CRT_PEM` | Adds a PEM root certificate and enables PostgreSQL TLS. |
| `log_config.level` | `VSS_LOG_LEVEL` | Log level. Defaults to `debug`. |
| `log_config.file` | `VSS_LOG_FILE` | Log file path. Defaults to `vss.log`. |

### Configuration
## Production Notes

Refer to `./server/vss-server-config.toml` to see available configuration options.
VSS is stateless and can be run behind a load balancer, but PostgreSQL is the durable state store.
Internet-facing deployments must terminate HTTPS in front of VSS, configure authentication, and add
rate limiting.

### Support
## Support

If you encounter any issues or have questions, feel free to open an issue on
the [GitHub repository](https://github.com/lightningdevkit/vss-server/issues). For further assistance or to discuss the
development of VSS, you can reach out to us in the [LDK Discord](https://discord.gg/5AcknnMfBw) in the `#vss` channel.
Open issues in the [GitHub repository](https://github.com/lightningdevkit/vss-server/issues), or use
the [LDK Discord](https://discord.gg/5AcknnMfBw) `#vss` channel.

[LDK Discord]: https://discord.gg/5AcknnMfBw
## MSRV

### MSRV
The Minimum Supported Rust Version (MSRV) is currently 1.85.0.
The Minimum Supported Rust Version (MSRV) is 1.85.0.
2 changes: 1 addition & 1 deletion impls/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "impls"
version = "0.1.0"
version.workspace = true
edition = "2021"
rust-version.workspace = true

Expand Down
2 changes: 1 addition & 1 deletion server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "vss-server"
version = "0.1.0"
version.workspace = true
edition = "2021"
rust-version.workspace = true

Expand Down
13 changes: 5 additions & 8 deletions server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,10 @@ fn main() {
},
};

#[cfg(any(feature = "jwt", feature = "sigs"))]
let mut authorizer: Option<Arc<dyn Authorizer>> = None;
#[cfg(not(any(feature = "jwt", feature = "sigs")))]
let authorizer: Option<Arc<dyn Authorizer>> = None;
#[cfg(feature = "jwt")]
{
if let Some(rsa_pem) = config.rsa_pem {
Expand Down Expand Up @@ -137,10 +140,7 @@ fn main() {
error!("Failed to start postgres TLS backend: {}", e);
std::process::exit(-1);
});
info!(
"Connected to PostgreSQL TLS backend with DSN: {}/{}",
config.postgresql_prefix, config.vss_db
);
info!("Connected to PostgreSQL TLS backend, database {}", config.vss_db);
Arc::new(postgres_tls_backend)
} else {
let postgres_plaintext_backend = PostgresPlaintextBackend::new(
Expand All @@ -153,10 +153,7 @@ fn main() {
error!("Failed to start postgres plaintext backend: {}", e);
std::process::exit(-1);
});
info!(
"Connected to PostgreSQL plaintext backend with DSN: {}/{}",
config.postgresql_prefix, config.vss_db
);
info!("Connected to PostgreSQL plaintext backend, database {}", config.vss_db);
Arc::new(postgres_plaintext_backend)
};

Expand Down
Loading