diff --git a/docs/astro.config.mjs b/docs/astro.config.mjs index 9aa0a822..e7ff87cf 100644 --- a/docs/astro.config.mjs +++ b/docs/astro.config.mjs @@ -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' }, ], diff --git a/docs/src/content/docs/deployment/docker.md b/docs/src/content/docs/deployment/docker.md index 164b631e..c5510ac6 100644 --- a/docs/src/content/docs/deployment/docker.md +++ b/docs/src/content/docs/deployment/docker.md @@ -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 \ @@ -33,7 +33,7 @@ docker exec 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 \ @@ -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" @@ -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 ``` diff --git a/docs/src/content/docs/deployment/gpu.md b/docs/src/content/docs/deployment/gpu.md index 29d948e8..4661e157 100644 --- a/docs/src/content/docs/deployment/gpu.md +++ b/docs/src/content/docs/deployment/gpu.md @@ -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 \ diff --git a/docs/src/content/docs/deployment/systemd.md b/docs/src/content/docs/deployment/systemd.md index 2cd4b2cb..709a21c0 100644 --- a/docs/src/content/docs/deployment/systemd.md +++ b/docs/src/content/docs/deployment/systemd.md @@ -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}" diff --git a/docs/src/content/docs/getting-started/quick-start.md b/docs/src/content/docs/getting-started/quick-start.md index d2344089..83a168dc 100644 --- a/docs/src/content/docs/getting-started/quick-start.md +++ b/docs/src/content/docs/getting-started/quick-start.md @@ -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 \ @@ -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 @@ -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 \ diff --git a/docs/src/content/docs/guides/authentication.md b/docs/src/content/docs/guides/authentication.md index ea65e653..f5527949 100644 --- a/docs/src/content/docs/guides/authentication.md +++ b/docs/src/content/docs/guides/authentication.md @@ -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/). diff --git a/docs/src/content/docs/guides/authorization.md b/docs/src/content/docs/guides/authorization.md new file mode 100644 index 00000000..cd689332 --- /dev/null +++ b/docs/src/content/docs/guides/authorization.md @@ -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 = ["*"] +``` diff --git a/docs/src/content/docs/guides/security-configuration.md b/docs/src/content/docs/guides/security-configuration.md new file mode 100644 index 00000000..462d03f7 --- /dev/null +++ b/docs/src/content/docs/guides/security-configuration.md @@ -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. diff --git a/docs/src/content/docs/guides/security.md b/docs/src/content/docs/guides/security.md index e1ae1241..15924e4a 100644 --- a/docs/src/content/docs/guides/security.md +++ b/docs/src/content/docs/guides/security.md @@ -2,388 +2,33 @@ # SPDX-FileCopyrightText: © 2025 StreamKit Contributors # SPDX-License-Identifier: MPL-2.0 title: Security -description: Permissions, secrets, and plugin sandboxing +description: Entry point for securing StreamKit deployments --- -StreamKit provides several security mechanisms for production deployments. +StreamKit is safe-by-default for local development, but production deployments need explicit +security configuration. This page is the entry point and links to the deeper guides. -## Runtime Plugin Management Gate +## Security model at a glance -Even when a role has `load_plugins` / `delete_plugins`, StreamKit can globally disable runtime plugin management. +- Built-in JWT authentication for the API, Web UI, and MoQ/WebTransport +- Role-based access control (RBAC) with least-privileged roles +- Allowlist-based controls for file access and script `fetch()` +- Runtime plugin management gate and plugin sandboxing (WASM) +- Origin validation for browser traffic -```toml -[plugins] -allow_http_management = false # default -``` +## Start here -Set it to `true` only in trusted environments (e.g., local development, or behind an authenticated reverse proxy). +- [Authentication](/guides/authentication/) +- [Authorization & Roles](/guides/authorization/) +- [Security Configuration](/guides/security-configuration/) +- [Script Node Guide](/guides/script-node/) +- [Writing Plugins](/guides/writing-plugins/) -## Role-Based Permissions +## Baseline checklist -StreamKit uses role-based access control (RBAC) to restrict what users can do. When built-in auth is disabled, roles are selected from a trusted header (optional), `SK_ROLE`, or `[permissions].default_role`. - -StreamKit also ships with built-in JWT authentication (recommended for production). See [Authentication](/guides/authentication/) for how auth modes, bootstrap tokens, cookies, and token minting work. - -### Configuring 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 = ["*"] -``` - -### Role Selection - -1. **Default role**: Applied when no role header is present -2. **Header-based**: When `role_header` is set, the specified header determines the role - -> [!CAUTION] -> Only enable `role_header` behind a trusted reverse proxy that strips the header from client requests. Otherwise, clients can impersonate any role. - -### Permission Reference - -> [!NOTE] -> Role permissions are **deny-by-default**. If you define a custom role in `skit.toml`, any permission you omit defaults to `false`. - -| 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 | - -## File System Security - -The `core::file_reader` node can read files from disk. Restrict this with: - -```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**. - -To enable file writes, explicitly allow destination paths: - -```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. - -## WebSocket Origin Checks - -To mitigate Cross-Site WebSocket Hijacking (CSWSH) in browsers, StreamKit validates the WebSocket `Origin` -header for `/api/v1/control` against `[server.cors].allowed_origins`. Non-browser clients that don't send -`Origin` are still allowed. - -## HTTP Origin Checks - -For additional defense-in-depth in browser environments, StreamKit also validates the `Origin` header on -mutating `/api/*` requests (e.g. `POST /api/v1/process`) against `[server.cors].allowed_origins`. -This helps prevent cross-site attacks against local/self-hosted instances. Requests without an `Origin` -header (typical for 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 Security - -The `core::script` node executes JavaScript. It has built-in security controls. - -Notes: -- `fetch()` is controlled by a global server allowlist (empty allowlist blocks all). -- Allowlist checks are performed against the parsed URL host/path (not a raw string match). -- To reduce DoS risk from many concurrent `fetch()` calls, StreamKit limits in-flight `fetch()` operations globally. You can override the limit with `SK_SCRIPT_FETCH_MAX_INFLIGHT` (default: 16). -- Redirects are disabled for `fetch()` to avoid allowlist bypass and secret leakage. - -### Fetch Allowlist - -By default, scripts cannot make HTTP requests. Enable specific URLs: - -```toml -[script] -default_timeout_ms = 100 -default_memory_limit_mb = 64 - -# Allow API calls -[[script.global_fetch_allowlist]] -url = "https://api.example.com/*" -methods = ["GET", "POST"] - -[[script.global_fetch_allowlist]] -url = "https://webhook.site/*" -methods = ["POST"] -``` - -### Secrets Management - -Pass secrets to scripts without exposing them in pipeline YAML: - -```toml -[script.secrets] -[script.secrets.OPENAI_KEY] -env = "OPENAI_API_KEY" -type = "apikey" -allowed_fetch_urls = ["https://api.openai.com/*"] -description = "OpenAI API key for completions" - -[script.secrets.WEBHOOK_URL] -env = "WEBHOOK_URL" -type = "url" -description = "Webhook endpoint for notifications" -``` - -If you set `allowed_fetch_urls`, StreamKit only injects that secret into `fetch()` requests whose URL matches one of the patterns. - -Secrets are not directly accessible from JavaScript. Instead, map them into HTTP headers for `fetch()`: - -```yaml -mode: dynamic -steps: - - kind: core::script - params: - headers: - - secret: OPENAI_KEY - header: Authorization - template: "Bearer {}" - - secret: WEBHOOK_URL - header: X-Webhook-Url - script: | - function process(packet) { - // fetch() will include the configured secret-backed headers - const response = fetch("https://api.example.com/..."); - return packet; - } -``` - -### Resource Limits - -Each script execution has: -- **Timeout**: `default_timeout_ms` (default: 100ms per packet) -- **Memory**: `default_memory_limit_mb` (default: 64 MB) - -These can be overridden per-node in the pipeline YAML. - -## Plugin Security - -StreamKit supports two plugin types with different security models. - -### Native Plugins - -Native plugins (`.so`/`.dylib`/`.dll`) run in-process with full access: - -- **No sandbox**: Full system access -- **Trusted code only**: Only load plugins you trust -- **Use case**: Performance-critical, first-party plugins - -### WASM Plugins - -WASM plugins run in a sandboxed environment: - -- **Sandboxed**: Cannot access filesystem, network, or system APIs -- **Capabilities**: Only exposed APIs (packet processing, logging) -- **Use case**: Third-party plugins, untrusted code - -### Plugin Loading Permissions - -Control who can load plugins: - -```toml -[permissions.roles.operator] -load_plugins = false # Cannot upload plugins -delete_plugins = false # Cannot remove plugins - -[permissions.roles.admin] -load_plugins = true -delete_plugins = true -``` - -## Production Recommendations - -### 1. Use a Reverse Proxy - -Place StreamKit behind a reverse proxy (Caddy, nginx) for: -- TLS termination -- Authentication -- Rate limiting -- Role header injection - -### 2. Restrict Default Role - -```toml -[permissions] -default_role = "viewer" # Not "admin" -``` - -### 3. Enable TLS - -```toml -[server] -tls = true -cert_path = "/path/to/cert.pem" -key_path = "/path/to/key.pem" -``` - -### 4. Limit Concurrent Operations - -```toml -[permissions] -max_concurrent_sessions = 10 -max_concurrent_oneshots = 5 -``` - -### 5. Restrict File Access - -```toml -[security] -allowed_file_paths = ["samples/**"] # Minimal access -``` - -### 6. Audit Script Allowlists - -Only allow necessary URLs in `global_fetch_allowlist`. Start with none and add as needed. - -## 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 = ["*"] -``` +- Keep auth enabled for any non-loopback bind (`auth.mode = "auto"` or `"enabled"`). +- Set `default_role` to a least-privileged role and review permissions. +- Disable runtime plugin management unless you need it. +- Restrict file read/write paths via `[security]` allowlists. +- Configure `server.cors.allowed_origins` when using browsers. +- Review script fetch allowlists and secrets. diff --git a/docs/src/content/docs/guides/writing-plugins.md b/docs/src/content/docs/guides/writing-plugins.md index 27e02aed..b7191070 100644 --- a/docs/src/content/docs/guides/writing-plugins.md +++ b/docs/src/content/docs/guides/writing-plugins.md @@ -28,7 +28,7 @@ Runtime plugin upload is powerful and dangerous: - Treat runtime plugin upload/delete as an admin-only feature: use built-in authentication (recommended) or a trusted reverse proxy + role header for access control. - HTTP plugin upload/delete is globally disabled by default. To enable it, set `[plugins].allow_http_management = true` and ensure only trusted callers have the `load_plugins` / `delete_plugins` permissions. -See the [Security guide](/guides/security/) for recommended deployment patterns. +See [Security Configuration](/guides/security-configuration/) for recommended deployment patterns. Uploaded plugins are stored under your configured plugin directory (default: `.plugins/`), in subfolders: diff --git a/docs/src/content/docs/index.mdx b/docs/src/content/docs/index.mdx index d7be5fb6..51673998 100644 --- a/docs/src/content/docs/index.mdx +++ b/docs/src/content/docs/index.mdx @@ -25,7 +25,7 @@ import { Card, CardGrid } from '@astrojs/starlight/components'; > The hosted demo is a public instance. Don’t use sensitive data. > [!CAUTION] -> StreamKit is early-stage (`v0.1.0`). Breaking changes are expected and the security model is still evolving. +> StreamKit is early-stage (`v0.2.0`). Breaking changes are expected and the security model is still evolving. > If you expose a StreamKit instance to other machines, read the [Security](/guides/security/) guide first. ## A quick look @@ -86,7 +86,7 @@ StreamKit is built for developers who need to process real-time media — whethe Run the server (Docker): ```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 \ diff --git a/docs/src/content/docs/reference/cli.md b/docs/src/content/docs/reference/cli.md index 923b5620..9ff27fc3 100644 --- a/docs/src/content/docs/reference/cli.md +++ b/docs/src/content/docs/reference/cli.md @@ -19,7 +19,7 @@ Each GitHub Release includes a Linux x86_64 tarball containing both binaries: Install steps: ```bash -TAG=v0.1.0 # replace with the latest release tag +TAG=v0.2.0 # replace with the latest release tag curl -LO https://github.com/streamer45/streamkit/releases/download/${TAG}/streamkit-${TAG}-linux-x64.tar.gz curl -LO https://github.com/streamer45/streamkit/releases/download/${TAG}/streamkit-${TAG}-linux-x64.tar.gz.sha256 sha256sum -c streamkit-${TAG}-linux-x64.tar.gz.sha256