Skip to content

Commit 01df2be

Browse files
authored
docs: reorganize security docs (#26)
1 parent 9bb285b commit 01df2be

File tree

12 files changed

+302
-392
lines changed

12 files changed

+302
-392
lines changed

docs/astro.config.mjs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@ export default defineConfig({
6161
{ label: 'Observability', slug: 'guides/observability' },
6262
{ label: 'Script Node', slug: 'guides/script-node' },
6363
{ label: 'Using the Web UI', slug: 'guides/web-ui' },
64-
{ label: 'Authentication', slug: 'guides/authentication' },
6564
{ label: 'Security', slug: 'guides/security' },
65+
{ label: 'Authentication', slug: 'guides/authentication' },
66+
{ label: 'Authorization & Roles', slug: 'guides/authorization' },
67+
{ label: 'Security Configuration', slug: 'guides/security-configuration' },
6668
{ label: 'Development Workflow', slug: 'guides/development' },
6769
{ label: 'Writing Plugins', slug: 'guides/writing-plugins' },
6870
],

docs/src/content/docs/deployment/docker.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ StreamKit provides Docker images for easy deployment.
1010
## Quick Start
1111

1212
```bash
13-
TAG=v0.1.0 # replace with the latest release tag
13+
TAG=v0.2.0 # replace with the latest release tag
1414
docker run --rm \
1515
-p 127.0.0.1:4545:4545/tcp \
1616
-p 127.0.0.1:4545:4545/udp \
@@ -33,7 +33,7 @@ docker exec <container> skit auth print-admin-token
3333
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**:
3434

3535
```bash
36-
TAG=v0.1.0 # replace with the latest release tag
36+
TAG=v0.2.0 # replace with the latest release tag
3737
docker run --rm -d --name streamkit \
3838
--network host \
3939
-e SK_SERVER__ADDRESS=127.0.0.1:4545 \
@@ -114,7 +114,7 @@ gdb -p 1
114114
# docker-compose.yml
115115
services:
116116
streamkit:
117-
image: ghcr.io/streamer45/streamkit:v0.1.0 # replace with the latest release tag
117+
image: ghcr.io/streamer45/streamkit:v0.2.0 # replace with the latest release tag
118118
ports:
119119
- "127.0.0.1:4545:4545/tcp"
120120
- "127.0.0.1:4545:4545/udp"
@@ -142,7 +142,7 @@ Use `env_file` to avoid putting secrets in your `docker-compose.yml`:
142142
```yaml
143143
services:
144144
streamkit:
145-
image: ghcr.io/streamer45/streamkit:v0.1.0-demo
145+
image: ghcr.io/streamer45/streamkit:v0.2.0-demo
146146
env_file:
147147
- ./streamkit.env
148148
```

docs/src/content/docs/deployment/gpu.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ StreamKit can use NVIDIA GPUs for selected native ML plugins. GPU support depend
1818
## Quick Start (GPU image)
1919

2020
```bash
21-
TAG=v0.1.0 # replace with the latest release tag
21+
TAG=v0.2.0 # replace with the latest release tag
2222
docker run --rm \
2323
--gpus all \
2424
-p 127.0.0.1:4545:4545/tcp \

docs/src/content/docs/deployment/systemd.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ This install path is a middle-ground between Docker and "build from source": you
1212
On a systemd-based Linux host:
1313

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

docs/src/content/docs/getting-started/quick-start.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ This guide gets you from zero to a working StreamKit installation in minutes.
1919
### Option 1: Docker (recommended)
2020

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

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

@@ -84,7 +84,7 @@ docker exec streamkit skit auth print-admin-token
8484
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**:
8585

8686
```bash
87-
TAG=v0.1.0 # replace with the latest release tag
87+
TAG=v0.2.0 # replace with the latest release tag
8888
docker run --rm -d --name streamkit \
8989
--network host \
9090
-e SK_SERVER__ADDRESS=127.0.0.1:4545 \

docs/src/content/docs/guides/authentication.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,4 +139,4 @@ When auth is disabled, `allowed_origins = ["*"]` is allowed (and the server refl
139139

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

142-
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/).
142+
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/).
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
---
2+
# SPDX-FileCopyrightText: © 2025 StreamKit Contributors
3+
# SPDX-License-Identifier: MPL-2.0
4+
title: Authorization & Roles
5+
description: Role-based access control (RBAC) and permissions
6+
---
7+
8+
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.
9+
10+
## How roles are resolved
11+
12+
- **Built-in auth enabled**: the role comes from the JWT (`role` claim) minted by StreamKit.
13+
- **Built-in auth disabled**: the role is resolved in this order:
14+
1. Trusted header (`[permissions].role_header`), if configured
15+
2. `SK_ROLE` environment variable
16+
3. `[permissions].default_role`
17+
18+
> [!CAUTION]
19+
> Only enable `role_header` behind a trusted reverse proxy that strips any incoming header with the same name. Otherwise, clients can impersonate any role.
20+
21+
If you disable built-in auth while binding to a non-loopback address, StreamKit refuses to start unless you explicitly opt in:
22+
23+
```toml
24+
[permissions]
25+
allow_insecure_no_auth = false # default
26+
```
27+
28+
## Configure roles
29+
30+
```toml
31+
[permissions]
32+
# Role assigned to unauthenticated requests
33+
default_role = "viewer"
34+
35+
# Trusted header for role selection (only behind a reverse proxy)
36+
role_header = "X-StreamKit-Role"
37+
38+
# Safety gate: refuse to bind to non-loopback without a trusted auth layer.
39+
# Set this to true only if the server is reachable exclusively by trusted clients.
40+
allow_insecure_no_auth = false # default
41+
42+
# Global limits
43+
max_concurrent_sessions = 10
44+
max_concurrent_oneshots = 5
45+
46+
# Define roles
47+
[permissions.roles.admin]
48+
create_sessions = true
49+
destroy_sessions = true
50+
modify_sessions = true
51+
tune_nodes = true
52+
list_sessions = true
53+
list_nodes = true
54+
list_samples = true
55+
read_samples = true
56+
write_samples = true
57+
delete_samples = true
58+
access_all_sessions = true
59+
load_plugins = true
60+
delete_plugins = true
61+
upload_assets = true
62+
delete_assets = true
63+
allowed_samples = ["*"]
64+
allowed_nodes = ["*"]
65+
allowed_plugins = ["*"]
66+
allowed_assets = ["*"]
67+
68+
[permissions.roles.viewer]
69+
create_sessions = false
70+
destroy_sessions = false
71+
modify_sessions = false
72+
tune_nodes = false
73+
list_sessions = true
74+
list_nodes = true
75+
list_samples = true
76+
read_samples = true
77+
write_samples = false
78+
delete_samples = false
79+
access_all_sessions = false
80+
load_plugins = false
81+
delete_plugins = false
82+
upload_assets = false
83+
delete_assets = false
84+
allowed_samples = ["*"]
85+
allowed_nodes = ["*"]
86+
allowed_assets = ["*"]
87+
88+
[permissions.roles.operator]
89+
create_sessions = true
90+
destroy_sessions = true
91+
modify_sessions = true
92+
tune_nodes = true
93+
list_sessions = true
94+
list_nodes = true
95+
list_samples = true
96+
read_samples = true
97+
write_samples = true
98+
delete_samples = true
99+
access_all_sessions = false # Can only access own sessions
100+
load_plugins = false
101+
delete_plugins = false
102+
upload_assets = true
103+
delete_assets = true
104+
allowed_samples = ["*"]
105+
allowed_nodes = ["audio::*", "core::*"] # Restrict to audio and core nodes
106+
allowed_assets = ["*"]
107+
```
108+
109+
> [!NOTE]
110+
> Role permissions are deny-by-default. If you define a custom role in `skit.toml`, any permission you omit defaults to `false`.
111+
112+
## Permission reference
113+
114+
| Permission | Description |
115+
|------------|-------------|
116+
| `create_sessions` | Create new dynamic pipeline sessions |
117+
| `destroy_sessions` | Destroy sessions |
118+
| `modify_sessions` | Add/remove nodes and connections |
119+
| `tune_nodes` | Update node parameters at runtime |
120+
| `list_sessions` | View session list |
121+
| `list_nodes` | View available node types |
122+
| `list_samples` | List sample pipelines |
123+
| `read_samples` | Read sample pipeline YAML |
124+
| `write_samples` | Save/update user pipelines (writes to disk under `[server].samples_dir/user`) |
125+
| `delete_samples` | Delete user pipelines |
126+
| `access_all_sessions` | Access any user's sessions (vs only own) |
127+
| `load_plugins` | Upload new plugins |
128+
| `delete_plugins` | Remove plugins |
129+
| `upload_assets` | Upload audio assets |
130+
| `delete_assets` | Delete audio assets |
131+
| `allowed_samples` | Glob patterns for allowed sample pipelines (paths are relative to `[server].samples_dir`) |
132+
| `allowed_nodes` | Glob patterns for allowed node types |
133+
| `allowed_plugins` | Glob patterns for allowed plugin names |
134+
| `allowed_assets` | Glob patterns for allowed audio asset paths |
135+
136+
## Example: Multi-tenant setup
137+
138+
```toml
139+
[permissions]
140+
default_role = "user"
141+
role_header = "X-StreamKit-Role"
142+
max_concurrent_sessions = 100
143+
144+
[permissions.roles.user]
145+
create_sessions = true
146+
destroy_sessions = true
147+
modify_sessions = true
148+
tune_nodes = true
149+
list_sessions = true
150+
list_nodes = true
151+
access_all_sessions = false # Only own sessions
152+
load_plugins = false
153+
delete_plugins = false
154+
upload_assets = true
155+
delete_assets = true
156+
allowed_nodes = ["audio::*", "core::passthrough", "core::text_chunker"]
157+
allowed_plugins = [] # No plugins
158+
159+
[permissions.roles.admin]
160+
# Full access for administrators
161+
create_sessions = true
162+
destroy_sessions = true
163+
modify_sessions = true
164+
tune_nodes = true
165+
list_sessions = true
166+
list_nodes = true
167+
access_all_sessions = true
168+
load_plugins = true
169+
delete_plugins = true
170+
upload_assets = true
171+
delete_assets = true
172+
allowed_samples = ["*"]
173+
allowed_nodes = ["*"]
174+
allowed_plugins = ["*"]
175+
```
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
---
2+
# SPDX-FileCopyrightText: © 2025 StreamKit Contributors
3+
# SPDX-License-Identifier: MPL-2.0
4+
title: Security Configuration
5+
description: File access, origin checks, plugin management, and other guardrails
6+
---
7+
8+
This guide covers security-sensitive configuration in `skit.toml` beyond authentication and role setup.
9+
10+
## Runtime plugin management gate
11+
12+
Even when a role has `load_plugins` / `delete_plugins`, StreamKit can globally disable runtime plugin management:
13+
14+
```toml
15+
[plugins]
16+
allow_http_management = false # default
17+
```
18+
19+
Set it to `true` only in trusted environments (local development or behind strong auth).
20+
21+
## File system access
22+
23+
The `core::file_reader` node can read files from disk. Restrict this with allowlists:
24+
25+
```toml
26+
[security]
27+
allowed_file_paths = [
28+
"samples/**", # Allow reading samples
29+
"/data/audio/**", # Allow specific data directory
30+
]
31+
```
32+
33+
Paths use glob patterns. Files outside these patterns cannot be read.
34+
35+
### File writes (core::file_writer)
36+
37+
The `core::file_writer` node can write files to disk. For safety, writes are disabled by default.
38+
39+
```toml
40+
[security]
41+
# Default: [] (deny all writes)
42+
allowed_write_paths = [
43+
"./output/**",
44+
"/data/exports/**",
45+
]
46+
```
47+
48+
This applies to both the HTTP oneshot endpoint and the WebSocket control plane.
49+
50+
## Origin checks (browser safety)
51+
52+
To mitigate cross-site request attacks in browsers, StreamKit validates `Origin` against
53+
`[server.cors].allowed_origins`:
54+
55+
- **WebSocket**: `/api/v1/control`
56+
- **HTTP**: mutating `/api/*` requests (e.g. `POST /api/v1/process`)
57+
58+
Requests without an `Origin` header (CLI/tools) are still allowed.
59+
60+
## Profiling endpoints
61+
62+
If you build with `--features profiling`, the server exposes `/api/v1/profile/cpu` and
63+
`/api/v1/profile/heap`. These endpoints are restricted to roles with admin-level access
64+
(`access_all_sessions = true`) and should not be exposed to untrusted clients.
65+
66+
## Script node controls
67+
68+
The `core::script` node has allowlists and resource limits for safe `fetch()` usage and secrets
69+
injection. See the [Script Node Guide](/guides/script-node/) for the full model, including
70+
`global_fetch_allowlist`, secret mapping, and runtime limits.
71+
72+
## Plugin security model
73+
74+
StreamKit supports two plugin types with different security properties:
75+
76+
- **Native plugins** run in-process with full access. Only load trusted code.
77+
- **WASM plugins** run in a sandboxed environment with no filesystem or network access by default.
78+
79+
See [Writing Plugins](/guides/writing-plugins/) for details and recommended practices.
80+
81+
## Production baseline checklist
82+
83+
- Keep built-in auth enabled for any non-loopback bind.
84+
- Use least-privileged roles and set `default_role` to a low-privilege role.
85+
- Disable runtime plugin management unless you need it.
86+
- Restrict `allowed_file_paths` and `allowed_write_paths`.
87+
- Configure `server.cors.allowed_origins` if you use browsers.
88+
- Review script fetch allowlists and secrets.

0 commit comments

Comments
 (0)