Skip to content
Merged
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
4 changes: 3 additions & 1 deletion docs/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,10 @@ export default defineConfig({
{ label: 'Observability', slug: 'guides/observability' },
{ label: 'Script Node', slug: 'guides/script-node' },
{ label: 'Using the Web UI', slug: 'guides/web-ui' },
{ label: 'Authentication', slug: 'guides/authentication' },
{ label: 'Security', slug: 'guides/security' },
{ label: 'Authentication', slug: 'guides/authentication' },
{ label: 'Authorization & Roles', slug: 'guides/authorization' },
{ label: 'Security Configuration', slug: 'guides/security-configuration' },
{ label: 'Development Workflow', slug: 'guides/development' },
{ label: 'Writing Plugins', slug: 'guides/writing-plugins' },
],
Expand Down
8 changes: 4 additions & 4 deletions docs/src/content/docs/deployment/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ StreamKit provides Docker images for easy deployment.
## Quick Start

```bash
TAG=v0.1.0 # replace with the latest release tag
TAG=v0.2.0 # replace with the latest release tag
docker run --rm \
-p 127.0.0.1:4545:4545/tcp \
-p 127.0.0.1:4545:4545/udp \
Expand All @@ -33,7 +33,7 @@ docker exec <container> skit auth print-admin-token
If you want a frictionless demo (no login) and you’re running on **Linux**, you can run StreamKit with host networking and bind to loopback inside the container. In `auth.mode = "auto"`, this keeps built-in auth **disabled**:

```bash
TAG=v0.1.0 # replace with the latest release tag
TAG=v0.2.0 # replace with the latest release tag
docker run --rm -d --name streamkit \
--network host \
-e SK_SERVER__ADDRESS=127.0.0.1:4545 \
Expand Down Expand Up @@ -114,7 +114,7 @@ gdb -p 1
# docker-compose.yml
services:
streamkit:
image: ghcr.io/streamer45/streamkit:v0.1.0 # replace with the latest release tag
image: ghcr.io/streamer45/streamkit:v0.2.0 # replace with the latest release tag
ports:
- "127.0.0.1:4545:4545/tcp"
- "127.0.0.1:4545:4545/udp"
Expand Down Expand Up @@ -142,7 +142,7 @@ Use `env_file` to avoid putting secrets in your `docker-compose.yml`:
```yaml
services:
streamkit:
image: ghcr.io/streamer45/streamkit:v0.1.0-demo
image: ghcr.io/streamer45/streamkit:v0.2.0-demo
env_file:
- ./streamkit.env
```
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/deployment/gpu.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ StreamKit can use NVIDIA GPUs for selected native ML plugins. GPU support depend
## Quick Start (GPU image)

```bash
TAG=v0.1.0 # replace with the latest release tag
TAG=v0.2.0 # replace with the latest release tag
docker run --rm \
--gpus all \
-p 127.0.0.1:4545:4545/tcp \
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/deployment/systemd.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ This install path is a middle-ground between Docker and "build from source": you
On a systemd-based Linux host:

```bash
export TAG=v0.1.0 # replace with the latest release tag
export TAG=v0.2.0 # replace with the latest release tag
curl -fsSL "https://raw.githubusercontent.com/streamer45/streamkit/${TAG}/deploy/systemd/install.sh" -o streamkit-install.sh
chmod +x streamkit-install.sh
sudo ./streamkit-install.sh --tag "${TAG}"
Expand Down
6 changes: 3 additions & 3 deletions docs/src/content/docs/getting-started/quick-start.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ This guide gets you from zero to a working StreamKit installation in minutes.
### Option 1: Docker (recommended)

```bash
TAG=v0.1.0 # replace with the latest release tag
TAG=v0.2.0 # replace with the latest release tag
docker run --rm -d --name streamkit \
-p 127.0.0.1:4545:4545/tcp \
-p 127.0.0.1:4545:4545/udp \
Expand All @@ -42,7 +42,7 @@ docker stop streamkit
### Option 2: GitHub Release + systemd (Linux)

```bash
TAG=v0.1.0 # replace with the latest release tag
TAG=v0.2.0 # replace with the latest release tag
curl -fsSL https://raw.githubusercontent.com/streamer45/streamkit/${TAG}/deploy/systemd/install.sh -o streamkit-install.sh
chmod +x streamkit-install.sh

Expand Down Expand Up @@ -84,7 +84,7 @@ docker exec streamkit skit auth print-admin-token
If you’re on **Linux** and want a frictionless demo (no login), you can run with host networking and bind to loopback inside the container. In `auth.mode = "auto"`, this keeps built-in auth **disabled**:

```bash
TAG=v0.1.0 # replace with the latest release tag
TAG=v0.2.0 # replace with the latest release tag
docker run --rm -d --name streamkit \
--network host \
-e SK_SERVER__ADDRESS=127.0.0.1:4545 \
Expand Down
2 changes: 1 addition & 1 deletion docs/src/content/docs/guides/authentication.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,4 +139,4 @@ When auth is disabled, `allowed_origins = ["*"]` is allowed (and the server refl

You can still run StreamKit behind a reverse proxy for TLS, firewalling, rate limiting, etc.

If you prefer **external authentication** instead of StreamKit’s built-in auth, set `auth.mode = "disabled"` and configure a trusted role header (`[permissions].role_header`) that your proxy sets after authenticating the caller. See the [Security guide](/guides/security/).
If you prefer **external authentication** instead of StreamKit’s built-in auth, set `auth.mode = "disabled"` and configure a trusted role header (`[permissions].role_header`) that your proxy sets after authenticating the caller. See [Authorization & Roles](/guides/authorization/).
175 changes: 175 additions & 0 deletions docs/src/content/docs/guides/authorization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
---
# SPDX-FileCopyrightText: © 2025 StreamKit Contributors
# SPDX-License-Identifier: MPL-2.0
title: Authorization & Roles
description: Role-based access control (RBAC) and permissions
---

Authorization determines what a caller can do. StreamKit uses role-based access control (RBAC): every request resolves to a role, and that role's permissions gate the API, Web UI actions, and runtime management features.

## How roles are resolved

- **Built-in auth enabled**: the role comes from the JWT (`role` claim) minted by StreamKit.
- **Built-in auth disabled**: the role is resolved in this order:
1. Trusted header (`[permissions].role_header`), if configured
2. `SK_ROLE` environment variable
3. `[permissions].default_role`

> [!CAUTION]
> Only enable `role_header` behind a trusted reverse proxy that strips any incoming header with the same name. Otherwise, clients can impersonate any role.

If you disable built-in auth while binding to a non-loopback address, StreamKit refuses to start unless you explicitly opt in:

```toml
[permissions]
allow_insecure_no_auth = false # default
```

## Configure roles

```toml
[permissions]
# Role assigned to unauthenticated requests
default_role = "viewer"

# Trusted header for role selection (only behind a reverse proxy)
role_header = "X-StreamKit-Role"

# Safety gate: refuse to bind to non-loopback without a trusted auth layer.
# Set this to true only if the server is reachable exclusively by trusted clients.
allow_insecure_no_auth = false # default

# Global limits
max_concurrent_sessions = 10
max_concurrent_oneshots = 5

# Define roles
[permissions.roles.admin]
create_sessions = true
destroy_sessions = true
modify_sessions = true
tune_nodes = true
list_sessions = true
list_nodes = true
list_samples = true
read_samples = true
write_samples = true
delete_samples = true
access_all_sessions = true
load_plugins = true
delete_plugins = true
upload_assets = true
delete_assets = true
allowed_samples = ["*"]
allowed_nodes = ["*"]
allowed_plugins = ["*"]
allowed_assets = ["*"]

[permissions.roles.viewer]
create_sessions = false
destroy_sessions = false
modify_sessions = false
tune_nodes = false
list_sessions = true
list_nodes = true
list_samples = true
read_samples = true
write_samples = false
delete_samples = false
access_all_sessions = false
load_plugins = false
delete_plugins = false
upload_assets = false
delete_assets = false
allowed_samples = ["*"]
allowed_nodes = ["*"]
allowed_assets = ["*"]

[permissions.roles.operator]
create_sessions = true
destroy_sessions = true
modify_sessions = true
tune_nodes = true
list_sessions = true
list_nodes = true
list_samples = true
read_samples = true
write_samples = true
delete_samples = true
access_all_sessions = false # Can only access own sessions
load_plugins = false
delete_plugins = false
upload_assets = true
delete_assets = true
allowed_samples = ["*"]
allowed_nodes = ["audio::*", "core::*"] # Restrict to audio and core nodes
allowed_assets = ["*"]
```

> [!NOTE]
> Role permissions are deny-by-default. If you define a custom role in `skit.toml`, any permission you omit defaults to `false`.

## Permission reference

| Permission | Description |
|------------|-------------|
| `create_sessions` | Create new dynamic pipeline sessions |
| `destroy_sessions` | Destroy sessions |
| `modify_sessions` | Add/remove nodes and connections |
| `tune_nodes` | Update node parameters at runtime |
| `list_sessions` | View session list |
| `list_nodes` | View available node types |
| `list_samples` | List sample pipelines |
| `read_samples` | Read sample pipeline YAML |
| `write_samples` | Save/update user pipelines (writes to disk under `[server].samples_dir/user`) |
| `delete_samples` | Delete user pipelines |
| `access_all_sessions` | Access any user's sessions (vs only own) |
| `load_plugins` | Upload new plugins |
| `delete_plugins` | Remove plugins |
| `upload_assets` | Upload audio assets |
| `delete_assets` | Delete audio assets |
| `allowed_samples` | Glob patterns for allowed sample pipelines (paths are relative to `[server].samples_dir`) |
| `allowed_nodes` | Glob patterns for allowed node types |
| `allowed_plugins` | Glob patterns for allowed plugin names |
| `allowed_assets` | Glob patterns for allowed audio asset paths |

## Example: Multi-tenant setup

```toml
[permissions]
default_role = "user"
role_header = "X-StreamKit-Role"
max_concurrent_sessions = 100

[permissions.roles.user]
create_sessions = true
destroy_sessions = true
modify_sessions = true
tune_nodes = true
list_sessions = true
list_nodes = true
access_all_sessions = false # Only own sessions
load_plugins = false
delete_plugins = false
upload_assets = true
delete_assets = true
allowed_nodes = ["audio::*", "core::passthrough", "core::text_chunker"]
allowed_plugins = [] # No plugins

[permissions.roles.admin]
# Full access for administrators
create_sessions = true
destroy_sessions = true
modify_sessions = true
tune_nodes = true
list_sessions = true
list_nodes = true
access_all_sessions = true
load_plugins = true
delete_plugins = true
upload_assets = true
delete_assets = true
allowed_samples = ["*"]
allowed_nodes = ["*"]
allowed_plugins = ["*"]
```
88 changes: 88 additions & 0 deletions docs/src/content/docs/guides/security-configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
# SPDX-FileCopyrightText: © 2025 StreamKit Contributors
# SPDX-License-Identifier: MPL-2.0
title: Security Configuration
description: File access, origin checks, plugin management, and other guardrails
---

This guide covers security-sensitive configuration in `skit.toml` beyond authentication and role setup.

## Runtime plugin management gate

Even when a role has `load_plugins` / `delete_plugins`, StreamKit can globally disable runtime plugin management:

```toml
[plugins]
allow_http_management = false # default
```

Set it to `true` only in trusted environments (local development or behind strong auth).

## File system access

The `core::file_reader` node can read files from disk. Restrict this with allowlists:

```toml
[security]
allowed_file_paths = [
"samples/**", # Allow reading samples
"/data/audio/**", # Allow specific data directory
]
```

Paths use glob patterns. Files outside these patterns cannot be read.

### File writes (core::file_writer)

The `core::file_writer` node can write files to disk. For safety, writes are disabled by default.

```toml
[security]
# Default: [] (deny all writes)
allowed_write_paths = [
"./output/**",
"/data/exports/**",
]
```

This applies to both the HTTP oneshot endpoint and the WebSocket control plane.

## Origin checks (browser safety)

To mitigate cross-site request attacks in browsers, StreamKit validates `Origin` against
`[server.cors].allowed_origins`:

- **WebSocket**: `/api/v1/control`
- **HTTP**: mutating `/api/*` requests (e.g. `POST /api/v1/process`)

Requests without an `Origin` header (CLI/tools) are still allowed.

## Profiling endpoints

If you build with `--features profiling`, the server exposes `/api/v1/profile/cpu` and
`/api/v1/profile/heap`. These endpoints are restricted to roles with admin-level access
(`access_all_sessions = true`) and should not be exposed to untrusted clients.

## Script node controls

The `core::script` node has allowlists and resource limits for safe `fetch()` usage and secrets
injection. See the [Script Node Guide](/guides/script-node/) for the full model, including
`global_fetch_allowlist`, secret mapping, and runtime limits.

## Plugin security model

StreamKit supports two plugin types with different security properties:

- **Native plugins** run in-process with full access. Only load trusted code.
- **WASM plugins** run in a sandboxed environment with no filesystem or network access by default.

See [Writing Plugins](/guides/writing-plugins/) for details and recommended practices.

## Production baseline checklist

- Keep built-in auth enabled for any non-loopback bind.
- Use least-privileged roles and set `default_role` to a low-privilege role.
- Disable runtime plugin management unless you need it.
- Restrict `allowed_file_paths` and `allowed_write_paths`.
- Configure `server.cors.allowed_origins` if you use browsers.
- Review script fetch allowlists and secrets.
Loading
Loading