|
1 | 1 | # Trusted Server |
2 | 2 |
|
3 | | -:information_source: Trusted Server is an open-source, cloud based orchestration framework and runtime for publishers. It moves code execution and operations that traditionally occurs in browsers (via 3rd party JS) to secure, zero-cold-start [WASM](https://webassembly.org) binaries running in [WASI](https://github.com/WebAssembly/WASI) supported environments. It importantly gives publishers benefits such as: dramatically increasing control over how and who they share their data with (while maintaining user-privacy compliance), increasing revenue from inventory inside cookie restricted or non-JS environments, ability to serve all assets under 1st party context, and provides secure cryptographic functions to ensure trust across the programmatic ad ecosystem. |
| 3 | +Trusted Server is an open-source, cloud-based orchestration framework and runtime for publishers. It moves code execution and operations that traditionally occur in browsers (via 3rd party JS) to secure, zero-cold-start [WASM](https://webassembly.org) binaries running in [WASI](https://github.com/WebAssembly/WASI) supported environments. |
4 | 4 |
|
5 | | -Trusted Server is the new execution layer for the open-web, returning control of 1st party data, security, and overall user-experience back to publishers. |
| 5 | +**Key benefits:** |
6 | 6 |
|
7 | | -At this time, Trusted Server is designed to work with Fastly Compute. Follow these steps to configure Fastly Compute and deploy it. |
| 7 | +- Dramatically increases control over data sharing while maintaining privacy compliance |
| 8 | +- Increases revenue from inventory in cookie-restricted or non-JS environments |
| 9 | +- Serves all assets under first-party context |
| 10 | +- Provides secure cryptographic functions for trust across the programmatic ad ecosystem |
8 | 11 |
|
9 | | -## Getting Started: Edge-Cloud Support on Fastly |
| 12 | +At this time, Trusted Server is designed to work with [Fastly Compute](https://www.fastly.com/products/compute). |
10 | 13 |
|
11 | | -- Create account at Fastly if you don’t have one - manage.fastly.com |
12 | | -- Log in to the Fastly control panel. |
13 | | - - Go to Account > API tokens > Personal tokens. |
14 | | - - Click Create token |
15 | | - - Name the Token |
16 | | - - Choose User Token |
17 | | - - Choose Global API Access |
18 | | - - Choose what makes sense for your Org in terms of Service Access |
19 | | - - Copy key to a secure location because you will not be able to see it again |
| 14 | +## Documentation |
20 | 15 |
|
21 | | -- Create new Compute Service |
22 | | - - Click Compute and Create Service |
23 | | - - Click “Create Empty Service” (below main options) |
24 | | - - Add your domain of the website you’ll be testing or using and click update |
25 | | - - Click on “Origins” section and add your ad-server / SSP integration information as hostnames (note after you save this information you can select port numbers and TLS on/off) |
26 | | - - IMPORTANT: when you enter the FQDN or IP ADDR information and click Add you need to enter a “Name” in the first field that will be referenced in your code so something like “my_ad_integration_1” |
27 | | - - |
| 16 | +📚 **[View Full Documentation](docs/guide/getting-started.md)** |
28 | 17 |
|
29 | | -:warning: With a dev account, Fastly gives you a test domain by default, but you’re also able to create a CNAME to your own domain when you’re ready, along with 2 free TLS certs (non-wildcard). Note that Fastly Compute ONLY accepts client traffic via TLS, though origins and backends can be non-TLS. |
| 18 | +| Guide | Description | |
| 19 | +| ---------------------------------------------------- | -------------------------------------------- | |
| 20 | +| [Getting Started](docs/guide/getting-started.md) | Installation, setup, and first deployment | |
| 21 | +| [Fastly Setup](docs/guide/fastly.md) | Fastly account, Compute service, and origins | |
| 22 | +| [Configuration](docs/guide/configuration.md) | Configuration options and settings | |
| 23 | +| [Synthetic IDs](docs/guide/synthetic-ids.md) | Privacy-preserving identifier generation | |
| 24 | +| [Ad Serving](docs/guide/ad-serving.md) | Ad server integration and setup | |
| 25 | +| [First-Party Proxy](docs/guide/first-party-proxy.md) | Proxy configuration for first-party context | |
| 26 | +| [Request Signing](docs/guide/request-signing.md) | Cryptographic request signing with Ed25519 | |
| 27 | +| [API Reference](docs/guide/api-reference.md) | Complete API endpoint documentation | |
| 28 | +| [Integration Guide](docs/guide/integration-guide.md) | Building custom integrations | |
30 | 29 |
|
31 | | -## CLI and OS Tools Installation |
| 30 | +## License |
32 | 31 |
|
33 | | -### Brew |
34 | | - |
35 | | -:warning: Follow the prompts before and afterwards (to configure system path, etc) |
36 | | - |
37 | | -#### Install Brew |
38 | | - |
39 | | -```sh |
40 | | -/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" |
41 | | -``` |
42 | | - |
43 | | -### Fastly CLI |
44 | | - |
45 | | -#### Install Fastly CLI |
46 | | - |
47 | | -```sh |
48 | | -brew install fastly/tap/fastly |
49 | | -``` |
50 | | - |
51 | | -#### Verify Installation and Version |
52 | | - |
53 | | -```sh |
54 | | -fastly version |
55 | | -``` |
56 | | - |
57 | | -:warning: fastly cli version should be at least v12.1.0 |
58 | | - |
59 | | -#### Create profile and follow interactive prompt for pasting your API Token created earlier: |
60 | | - |
61 | | -```sh |
62 | | -fastly profile create |
63 | | -``` |
64 | | - |
65 | | -### Rust |
66 | | - |
67 | | -#### Install Rust with asdf (our preference) |
68 | | - |
69 | | -```sh |
70 | | -brew install asdf |
71 | | -asdf plugin add rust |
72 | | -asdf install rust $(grep '^rust ' .tool-versions | awk '{print $2}') |
73 | | -asdf reshim |
74 | | -``` |
75 | | - |
76 | | -### NodeJS |
77 | | - |
78 | | -#### Install NodeJS with asdf |
79 | | - |
80 | | -```sh |
81 | | -brew install asdf |
82 | | -asdf plugin add nodejs |
83 | | -asdf install nodejs $(grep '^nodejs ' .tool-versions | awk '{print $2}') |
84 | | -asdf reshim |
85 | | -``` |
86 | | - |
87 | | -#### Fix path for Bash |
88 | | - |
89 | | -Edit ~/.bash_profile to add path for asdf shims: |
90 | | - |
91 | | -```sh |
92 | | -export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH" |
93 | | -``` |
94 | | - |
95 | | -#### Fix path for ZSH |
96 | | - |
97 | | -Edit ~/.zshrc to add path for asdf shims: |
98 | | - |
99 | | -```sh |
100 | | -export PATH="${ASDF_DATA_DIR:-$HOME/.asdf}/shims:$PATH" |
101 | | -``` |
102 | | - |
103 | | -#### Other shells |
104 | | - |
105 | | -See https://asdf-vm.com/guide/getting-started.html#_2-configure-asdf |
106 | | - |
107 | | -### Clone Trusted Server and Configure Build |
108 | | - |
109 | | -#### Clone Project (assumes you have 'git' installed on your system) |
110 | | - |
111 | | -```sh |
112 | | -git clone [email protected]:IABTechLab/trusted-server.git |
113 | | -``` |
114 | | - |
115 | | -### Configure |
116 | | - |
117 | | -#### Edit configuration files |
118 | | - |
119 | | -:information_source: Note that you'll have to edit the following files for your setup: |
120 | | - |
121 | | -- fastly.toml (service ID, author, description, Config/Secret Store IDs for request signing) |
122 | | -- trusted-server.toml (KV store ID names - optional, request signing configuration) |
123 | | - |
124 | | -### Build |
125 | | - |
126 | | -```sh |
127 | | -cargo build |
128 | | -``` |
129 | | - |
130 | | -### Deploy to Fastly |
131 | | - |
132 | | -```sh |
133 | | -fastly compute publish |
134 | | -``` |
135 | | - |
136 | | -## Devleopment |
137 | | - |
138 | | -#### Install viceroy for running tests |
139 | | - |
140 | | -```sh |
141 | | -cargo install viceroy |
142 | | -``` |
143 | | - |
144 | | -#### Run Fastly server locally |
145 | | - |
146 | | -- Review configuration for [local_server](fastly.toml#L16) |
147 | | -- Review env variables overrides in [.env.dev](.env.dev) |
148 | | - |
149 | | -```sh |
150 | | -export $(grep -v '^#' .env.dev | xargs -0) |
151 | | -``` |
152 | | - |
153 | | -```sh |
154 | | -fastly -i compute serve |
155 | | -``` |
156 | | - |
157 | | -#### Tests |
158 | | - |
159 | | -```sh |
160 | | -cargo test |
161 | | -``` |
162 | | - |
163 | | -:warning: if test fails `viceroy` will not display line number of the failed test. Rerun it with `cargo test_details`. |
164 | | - |
165 | | -#### Additional Rust Commands |
166 | | - |
167 | | -- `cargo fmt`: Ensure uniform code formatting |
168 | | -- `cargo clippy`: Ensure idiomatic code |
169 | | -- `cargo check`: Ensure compilation succeeds on Linux, MacOS, Windows and WebAssembly |
170 | | -- `cargo bench`: Run all benchmarks |
171 | | - |
172 | | -## Request Signing |
173 | | - |
174 | | -Trusted Server supports cryptographic signing of OpenRTB requests and other API calls using Ed25519 keys. |
175 | | - |
176 | | -### Configuration |
177 | | - |
178 | | -Request signing requires Fastly Config Store and Secret Store for key management: |
179 | | - |
180 | | -1. **Create Fastly Stores** (via Fastly Control Panel or CLI): |
181 | | - - Config Store: `jwks_store` - stores public keys (JWKs) and key metadata |
182 | | - - Secret Store: `signing_keys` - stores private signing keys |
183 | | - |
184 | | -2. **Configure in trusted-server.toml**: |
185 | | - |
186 | | -```toml |
187 | | -[request_signing] |
188 | | -enabled = true # Set to true to enable request signing |
189 | | -config_store_id = "<your-fastly-config-store-id>" # Config Store ID from Fastly |
190 | | -secret_store_id = "<your-fastly-secret-store-id>" # Secret Store ID from Fastly |
191 | | -``` |
192 | | - |
193 | | -### Key Management Endpoints |
194 | | - |
195 | | -Once configured, the following endpoints are available: |
196 | | - |
197 | | -- **`GET /.well-known/ts.jwks.json`**: Returns active public keys in JWKS format for signature verification |
198 | | -- **`POST /verify-signature`**: Verifies a signature against a payload and key ID (useful for testing) |
199 | | - - Request body: `{"payload": "...", "signature": "...", "kid": "..."}` |
200 | | - - Response: `{"verified": true/false, "kid": "...", "message": "..."}` |
201 | | - |
202 | | -#### Admin Endpoints (Key Rotation) |
203 | | - |
204 | | -- **`POST /admin/keys/rotate`**: Generates and activates a new signing key |
205 | | - - Optional body: `{"kid": "custom-key-id"}` (auto-generates date-based ID if omitted) |
206 | | - - Response includes new key ID, previous key ID, and active keys list |
207 | | -- **`POST /admin/keys/deactivate`**: Deactivates or deletes a key |
208 | | - - Request body: `{"kid": "key-to-deactivate", "delete": false}` |
209 | | - - Set `delete: true` to permanently remove the key (also deactivates it) |
210 | | - |
211 | | -:warning: Key rotation keeps both the new and previous key active to allow for graceful transitions. Deactivate old keys manually when no longer needed. |
212 | | - |
213 | | -## First-Party Endpoints |
214 | | - |
215 | | -- `/first-party/ad` (GET): returns HTML for a single slot (`slot`, `w`, `h` query params). The server inspects returned creative HTML and rewrites: |
216 | | -- All absolute images and iframes to `/first-party/proxy?tsurl=<base-url>&<original-query-params>&tstoken=<sig>` (1×1 pixels are detected server‑side heuristically for logging). The `tstoken` is derived from encrypting the full target URL and hashing it. |
217 | | -- `/third-party/ad` (POST): accepts tsjs ad units and proxies to Prebid Server. |
218 | | -- `/first-party/proxy` (GET): unified proxy for resources referenced by creatives. |
219 | | - - Query params: |
220 | | - - `tsurl`: Target URL without query (base URL) — required |
221 | | - - Any original target query parameters are included at top level as-is (order preserved) |
222 | | - - `tstoken`: Base64 URL‑safe (no padding) SHA‑256 digest of the encrypted full target URL — required |
223 | | - - Behavior: |
224 | | - - Reconstructs the full target URL from `tsurl` + provided parameters in order, computes `tstoken` by encrypting with XChaCha20‑Poly1305 (deterministic nonce) and hashing the bytes with SHA‑256, and validates it. |
225 | | - - HTML responses: proxied and rewritten (images/iframes/pixels) via creative rewriter |
226 | | - - Image responses: proxied; if content‑type is missing, sets `image/*`; logs likely 1×1 pixels via size/URL heuristics |
227 | | - - Follows HTTP redirects (301/302/303/307/308) up to four hops, reapplying the forwarded synthetic ID and switching to `GET` after a 303; logs when the redirect limit is reached. |
228 | | - - When forwarding to the target URL, no `tstoken` is included (it is not part of the target URL). |
229 | | -- Synthetic ID propagation: reads the trusted ID from the incoming cookie/header and appends `synthetic_id=<value>` to the target URL sent to the third-party origin while preserving existing query strings. |
230 | | - - Redirect following re-applies the identifier on each hop so downstream origins see a consistent ID even when assets bounce through intermediate trackers. |
231 | | - |
232 | | -- `/first-party/click` (GET): first‑party click redirect handler for anchors and clickable areas. |
233 | | - - Query params: same as `/first-party/proxy` (uses `tsurl`, original params, `tstoken`). |
234 | | - - Behavior: |
235 | | - - Validates `tstoken` against the reconstructed full URL (same enc+SHA256 scheme). |
236 | | - - Emits a `302 Found` with `Location: <reconstructed_target_url>` — content is not parsed or proxied. |
237 | | - - If a synthetic identifier is available, appends `synthetic_id=<value>` to the redirect target. |
238 | | - - Logs click metadata (tsurl, whether params are present, target URL, referer, user agent, and Trusted Server ID header) for observability. |
239 | | - |
240 | | -- Publisher origin proxy (`handle_publisher_request`): retrieves/generates the synthetic ID, stamps the response with `X-Synthetic-*` headers, and sets the `synthetic_id` cookie (Secure, SameSite=Lax) when absent so subsequent creative and click proxies can propagate the identifier. |
241 | | - |
242 | | -Notes |
243 | | - |
244 | | -- Rewriting uses `lol_html`. Only absolute and protocol‑relative URLs are rewritten; relative URLs are left unchanged. |
245 | | -- For the proxy endpoint, the base URL is carried in `tsurl`, the original query parameters are preserved individually, and `tstoken` authenticates the reconstructed full URL. |
246 | | -- Synthetic identifiers are generated by `crates/common/src/synthetic.rs` and are surfaced in three places: publisher responses (headers + cookie), creative proxy target URLs (`synthetic_id` query param), and click redirect URLs. This ensures downstream integrations can correlate impressions and clicks without direct third-party cookies. |
247 | | - |
248 | | -## Integration Modules |
249 | | - |
250 | | -- See [`docs/integration_guide.md`](docs/integration_guide.md) for the full integration module guide, covering configuration, proxy routing, HTML shim hooks, and the `testlight` example implementation. |
| 32 | +Apache License 2.0 |
0 commit comments