Skip to content

Commit 4549b81

Browse files
committed
better docs
1 parent 19cc558 commit 4549b81

3 files changed

Lines changed: 78 additions & 62 deletions

File tree

README.md

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,28 @@ If you have isolated Kubernetes clusters, locked-down microservices, or a heavil
4040
- **Data Plane (HTTPS by default):** File bytes stream directly from your S3 storage to the Private Connector, and then securely out to the Edge Gateway over an outbound mTLS connection. Experimental TCP, smux, custom QUIC, and HTTP/3 ingest transports are available as opt-in benchmark/runtime tuning modes; HTTP remains the default and fallback.
4141
- **No Direct S3 Access:** Users get URLs signed for the Edge Gateway, not S3. The Edge handles authorization before the private network even knows about the request.
4242

43-
### Public URL routing modes
43+
### Advanced: Multi-Server Routing and URL Shortening
4444

45-
The default and recommended deployment is still the isolated single-server topology shown below: tickets publish to `AIR3_NATS_SUBJECT` (default `air3.tickets`), and only the Private Connector has S3 credentials or private S3 network access. Public URLs use legacy full paths `/{bucket}/{key}` unless the Edge sets `AIR3_S3_BUCKET`. With `AIR3_S3_BUCKET=demo`, signed URLs generated with `cmd/signurl -default-bucket-path` use short paths such as `/hello.txt`; the signature and connector ticket still carry bucket `demo`, and the Connector fetches from that bucket.
45+
By default, air3 uses a **Single-Server Topology**, where URLs look like `/{bucket}/{key}`. Only the Private Connector knows your S3 credentials, keeping your data highly secure.
4646

47-
`AIR3_S3_BUCKET` is a routing/signing default bucket name, not an S3 credential and not a substitute for the Connector's `AIR3_S3_ACCESS_KEY_ID` or `AIR3_S3_SECRET_ACCESS_KEY`. When single-server default-bucket mode is enabled, short-form parsing wins: `/demo/file.txt` means key `demo/file.txt` in bucket `demo`, not key `file.txt` in bucket `demo`. Leave `AIR3_S3_BUCKET` unset when you need the legacy public `/{bucket}/{key}` shape.
47+
You can configure air3 for more advanced deployments:
48+
49+
#### 1. Short URLs (Single-Server Default Bucket)
50+
If you only serve files from a single bucket, having the bucket name in the public URL is redundant. Setting a default bucket (e.g., `AIR3_S3_BUCKET=demo`) allows clients to request cleaner, shorter URLs like `/file.txt`.
51+
- **Under the hood:** The Edge automatically injects the `demo` bucket into the ticket. The signature validation and the Private Connector's S3 fetch still strictly verify and use the `demo` bucket.
52+
53+
#### 2. Multi-Server Mode
54+
If you have multiple isolated S3 storage backends (e.g., "blue" storage and "green" storage), enable `AIR3_MULTI_SERVER=true`.
55+
- **Public URLs:** URLs change to `/{server_alias}/{bucket}/{key}` (e.g., `/blue/demo-bucket/file.txt`). You can also use Default Buckets per alias so `/blue/file.txt` automatically targets the "blue" server's default bucket.
56+
- **Routing:** The Edge Gateway uses the `{server_alias}` to route the ticket to a specific NATS queue (e.g., `air3.blue`). The Private Connector configured for that alias only listens to its specific queue.
57+
58+
#### 3. Direct Servers (Edge-Direct S3 Access)
59+
In specific scenarios where you explicitly *want* the Edge to connect directly to S3 (bypassing NATS and the Private Connector entirely), you can use `AIR3_DIRECT_SERVERS`.
60+
- **Warning:** This places S3 credentials and direct S3 network reachability on the Edge Gateway, stepping outside the primary zero-trust boundary of air3. Only use this if you intentionally accept placing credentials in your DMZ.
4861

4962
```sh
50-
# Single-server default bucket: emit /hello.txt while signing bucket demo.
63+
# 1. Single-Server Short URL
64+
# The edge uses default bucket "demo". The client uses a short URL path.
5165
AIR3_S3_BUCKET=demo ./bin/edge-gateway
5266

5367
go run ./cmd/signurl \
@@ -58,18 +72,18 @@ go run ./cmd/signurl \
5872
-default-bucket-path
5973
```
6074

61-
Multi-server mode is opt-in with `AIR3_MULTI_SERVER=true` on the Edge. In this mode, public URLs normally include a server alias and bucket: `/{server}/{bucket}/{key}`. The Edge verifies that the signed URL includes the same server alias, then publishes connector tickets to the routed NATS subject rendered from `AIR3_NATS_SUBJECT_TEMPLATE` (default `air3.{server}`). A connector for that alias sets `AIR3_SERVER_NAME=<server>` and subscribes to the same derived subject. For example, `server=blue` routes `/blue/demo-bucket/file.txt` to NATS subject `air3.blue` by default. If the Edge sets `S3_BLUE_BUCKET=demo-bucket`, signed URLs can use the short form `/blue/dir/object.txt`; the signature still binds the real bucket (`demo-bucket`) even though it is omitted from the path. For aliases with a default bucket, short-form parsing wins, so `/blue/demo-bucket/dir/object.txt` means key `demo-bucket/dir/object.txt` in the default bucket rather than an explicit bucket segment.
62-
6375
```sh
64-
# Sign a full-path multi-server URL for the blue connector alias.
76+
# 2. Multi-Server URL
77+
# The URL must include the "blue" alias.
6578
go run ./cmd/signurl \
6679
-base-url https://files.example.com \
6780
-server blue \
6881
-bucket demo-bucket \
6982
-key dir/object.txt \
7083
-secret "$AIR3_SIGNING_SECRET"
7184

72-
# If the Edge has S3_BLUE_BUCKET=demo-bucket, emit /blue/dir/object.txt.
85+
# If the Edge has a default bucket configured for "blue" (S3_BLUE_BUCKET=demo-bucket),
86+
# we can emit a shorter URL: /blue/dir/object.txt.
7387
go run ./cmd/signurl \
7488
-base-url https://files.example.com \
7589
-server blue \
@@ -78,14 +92,10 @@ go run ./cmd/signurl \
7892
-secret "$AIR3_SIGNING_SECRET" \
7993
-default-bucket-path
8094

81-
# Connector for that alias; default template renders air3.blue.
95+
# The Private Connector for this alias will listen to the derived NATS subject (air3.blue)
8296
AIR3_SERVER_NAME=blue ./bin/private-connector
83-
# Or customize both sides with, for example:
84-
# AIR3_NATS_SUBJECT_TEMPLATE='air3.{server}.tickets'
8597
```
8698

87-
Direct servers are a separate opt-in exception for multi-server deployments. Aliases listed in `AIR3_DIRECT_SERVERS` are fetched by the Edge directly from their per-alias S3 configuration instead of using NATS and a Private Connector. A direct alias can also set `S3_{SUFFIX}_BUCKET` for short-form URLs, but that default bucket must be present in `S3_{SUFFIX}_ALLOWED_BUCKETS` so the Edge allowlist still validates the real bucket. Direct mode places S3 credentials and S3 network reachability on the Edge, so use it only when you intentionally accept that different trust boundary.
88-
8999
```mermaid
90100
sequenceDiagram
91101
autonumber
@@ -333,36 +343,38 @@ If you need to serve partial files (like for streaming video), `air3` fully supp
333343

334344
If you're using signed URLs and expect clients to send `Range` headers, you must include the exact range claim when generating the URL (e.g., `cmd/signurl -range 'bytes=0-99'`). The Connector forwards authorized ranges to S3, seamlessly returning a `206 Partial Content` response to the client.
335345

336-
## Optional Read-Only S3-Compatible API
346+
## Optional: Read-Only S3-Compatible API
347+
348+
While air3 primarily relies on its highly-secure HMAC signed URLs, you can optionally enable a **read-only S3-compatible API** (`AIR3_S3_API_ENABLED=true`). This is extremely useful if your clients or internal tools already use standard S3 SDKs (like `aws-cli` or `boto3`) and you want them to fetch files without modifying their code.
349+
350+
### Security First
337351

338-
By default, air3 serves only its HMAC signed gateway URLs. You can opt in to a public, read-only, path-style S3-compatible API by setting `AIR3_S3_API_ENABLED=true` on the Edge and providing `AIR3_S3_API_REGION`, `AIR3_S3_API_ACCESS_KEY_ID`, and `AIR3_S3_API_SECRET_ACCESS_KEY`. These `AIR3_S3_API_*` values are public gateway AWS SigV4 verifier credentials only. They are separate from Connector backend S3 credentials, direct-server `S3_{SUFFIX}_*` credentials, and the Air3 HMAC `AIR3_SIGNING_SECRET`.
352+
- **No Real S3 Credentials at the Edge:** You must define a *brand new, gateway-only* set of credentials (`AIR3_S3_API_ACCESS_KEY_ID` and `AIR3_S3_API_SECRET_ACCESS_KEY`). The Edge Gateway only uses these to verify incoming AWS SigV4 requests. It **does not** give the Edge access to the backend storage. These are completely separate from your real, private S3 credentials and your HMAC `AIR3_SIGNING_SECRET`.
353+
- **Strictly Read-Only:** The API deliberately only supports safe read operations: `GetObject`, `HeadObject`, `ListObjectsV2`, and `HeadBucket`. Any attempt to write, delete, manage buckets, or perform complex bucket operations is immediately rejected at the Edge.
339354

340-
S3-compatible API v1 supports `GetObject`, `HeadObject`, edge-only `HeadBucket` validation, and `ListObjectsV2`. It rejects writes, bucket listing/management, and virtual-hosted-style requests; clients must sign for the exact configured region. Air3 HMAC signed URLs remain supported and are not AWS SigV4 or S3 presigned URLs.
355+
### Using the API (Path-Style)
341356

342-
Path-style examples:
357+
All API requests must use **path-style** addressing. Depending on your routing mode, the "bucket" in the S3 API request behaves differently:
343358

344359
```sh
345-
# Single-server: backend bucket demo, key photos/cat.jpg.
360+
# 1. Single-Server Mode
361+
# The API bucket exactly matches your backend bucket name.
346362
aws --endpoint-url https://files.example.com s3api get-object \
347363
--bucket demo --key photos/cat.jpg cat.jpg
348-
aws --endpoint-url https://files.example.com s3api list-objects-v2 \
349-
--bucket demo --prefix photos/
350364

351-
# Multi-server standard: public bucket blue is the server alias; the first
352-
# key/prefix segment selects backend bucket demo.
365+
# 2. Multi-Server Mode (Standard)
366+
# The API bucket is the server alias ("blue").
367+
# The first folder in the key ("demo/") maps to the backend bucket name.
353368
aws --endpoint-url https://files.example.com s3api get-object \
354369
--bucket blue --key demo/photos/cat.jpg cat.jpg
355-
aws --endpoint-url https://files.example.com s3api list-objects-v2 \
356-
--bucket blue --prefix demo/photos/
357370

358-
# Multi-server default/direct prefix mapping, e.g. S3_DIRECT_BUCKET=demo.
371+
# 3. Multi-Server Mode (With Default Bucket)
372+
# If server "blue" has a default bucket configured, the key maps directly.
359373
aws --endpoint-url https://files.example.com s3api get-object \
360-
--bucket direct --key photos/cat.jpg cat.jpg
361-
aws --endpoint-url https://files.example.com s3api list-objects-v2 \
362-
--bucket direct --prefix photos/
374+
--bucket blue --key photos/cat.jpg cat.jpg
363375
```
364376

365-
See `docs/configuration.md` for the full security model and Compose opt-in notes.
377+
*(See `docs/configuration.md` for the full configuration details and security model.)*
366378

367379
## Local Development & Validation
368380

docs/architecture.md

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,13 @@ sequenceDiagram
4040

4141
When `AIR3_S3_BUCKET` is configured for single-server mode, short-form parsing wins. For example, `/demo/file.txt` means key `demo/file.txt` in default bucket `demo`, not key `file.txt`; leaving `AIR3_S3_BUCKET` unset preserves the legacy full-path interpretation. `AIR3_S3_BUCKET` is only a routing/signing default bucket name on the Edge, not an S3 credential.
4242

43-
## Multi-server routed flow
43+
## Advanced Routing: Multi-Server Flow
4444

45-
Multi-server mode is enabled with `AIR3_MULTI_SERVER=true`. Public URLs use `/{server}/{bucket}/{key}` unless an alias has an Edge-side default bucket from `S3_{SUFFIX}_BUCKET`. With a default such as `S3_BLUE_BUCKET=demo`, signed URLs may use `/blue/{key}`; the server alias and resolved bucket are still included in signed URL validation and ticket payloads. Short-form parsing wins for defaulted aliases, so every segment after `/{server}/` is treated as the key. For connector-routed aliases, the Edge renders the NATS subject from `AIR3_NATS_SUBJECT_TEMPLATE` (default `air3.{server}`), and each connector sets `AIR3_SERVER_NAME` to subscribe to its derived subject.
45+
If you need to connect to multiple disparate S3 storage backends, you can enable Multi-Server mode (`AIR3_MULTI_SERVER=true`).
46+
47+
In this mode, URLs contain a **server alias** (e.g., `/blue/demo-bucket/file.txt`). The Edge Gateway dynamically derives a NATS subject from this alias (e.g., `air3.blue`). You run multiple Private Connectors, each configured with an `AIR3_SERVER_NAME` that tells it which queue to listen to. This allows the Edge to route requests to the correct storage backend seamlessly.
48+
49+
*(You can also configure default buckets per alias (`S3_BLUE_BUCKET=demo`), which shortens the public URL to `/blue/file.txt` while keeping the internal routing intact.)*
4650

4751
```mermaid
4852
sequenceDiagram
@@ -64,9 +68,11 @@ sequenceDiagram
6468
Edge-->>Client: Stream response
6569
```
6670

67-
## Direct-server exception flow
71+
## Exception: Direct-Server Flow
72+
73+
Direct-server aliases (configured via `AIR3_DIRECT_SERVERS`) explicitly bypass NATS and the Private Connector entirely. The Edge Gateway fetches the object directly from the configured S3 endpoint.
6874

69-
Direct-server aliases are configured on the Edge with `AIR3_DIRECT_SERVERS` or `DIRECT_SERVERS` and per-alias `S3_{SUFFIX}_*` settings. They require multi-server paths to select the alias, but they bypass NATS and the Private Connector for that alias. A direct alias may also set `S3_{SUFFIX}_BUCKET` for short-form paths, and startup validates that default bucket against `S3_{SUFFIX}_ALLOWED_BUCKETS`. This is useful only when you deliberately accept that the Edge has S3 credentials and network reachability for that storage. It is not the recommended private-storage boundary.
75+
**This is a significant security exception.** It requires the Edge Gateway to hold S3 credentials and have direct network reachability to the storage backend. This breaks the core isolation boundary of air3. Only use direct servers when you deliberately accept exposing those credentials to your DMZ.
7076

7177
```mermaid
7278
sequenceDiagram

0 commit comments

Comments
 (0)