zuplo 6.70.69 → 6.70.70

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/docs/ai-gateway/getting-started.mdx +12 -8
  2. package/docs/ai-gateway/introduction.mdx +11 -9
  3. package/docs/articles/api-key-buckets.mdx +4 -2
  4. package/docs/articles/archiving-requests-to-storage.mdx +4 -4
  5. package/docs/articles/branch-based-deployments.mdx +10 -8
  6. package/docs/articles/ci-cd-github/cleanup-on-branch-delete.mdx +52 -31
  7. package/docs/articles/ci-cd-github/pr-preview-environments.mdx +17 -6
  8. package/docs/articles/custom-ci-cd-azure.mdx +1 -1
  9. package/docs/articles/custom-ci-cd-bitbucket.mdx +1 -1
  10. package/docs/articles/custom-ci-cd-circleci.mdx +1 -1
  11. package/docs/articles/custom-ci-cd-github.mdx +1 -1
  12. package/docs/articles/custom-ci-cd-gitlab.mdx +1 -1
  13. package/docs/articles/graphql.mdx +276 -0
  14. package/docs/articles/monorepo-deployment.mdx +17 -3
  15. package/docs/articles/opentelemetry.mdx +5 -2
  16. package/docs/articles/per-user-rate-limits-using-db.mdx +5 -6
  17. package/docs/articles/securing-the-gateway-with-client-mtls.mdx +68 -43
  18. package/docs/articles/step-1-setup-basic-gateway.mdx +1 -3
  19. package/docs/articles/step-2-add-rate-limiting.mdx +1 -1
  20. package/docs/articles/testing.mdx +1 -1
  21. package/docs/articles/troubleshooting.md +7 -3
  22. package/docs/articles/waf-ddos-akamai.md +35 -16
  23. package/docs/articles/waf-ddos-aws-waf-shield.mdx +35 -16
  24. package/docs/articles/waf-ddos-fastly.mdx +10 -7
  25. package/docs/cli/deploy.mdx +13 -10
  26. package/docs/cli/deploy.partial.mdx +13 -10
  27. package/docs/dev-portal/zudoku/components/sidecar-box.mdx +131 -0
  28. package/docs/dev-portal/zudoku/configuration/api-catalog.md +62 -42
  29. package/docs/dev-portal/zudoku/configuration/api-reference.md +5 -4
  30. package/docs/dev-portal/zudoku/configuration/navigation.mdx +70 -7
  31. package/docs/guides/canary-routing-for-employees.mdx +103 -39
  32. package/docs/guides/modify-openapi-paths.mdx +3 -3
  33. package/docs/handlers/legacy-dev-portal-handler.mdx +1 -1
  34. package/docs/handlers/mcp-server.mdx +13 -11
  35. package/docs/handlers/url-forward.mdx +5 -1
  36. package/docs/handlers/url-rewrite.mdx +7 -2
  37. package/docs/handlers/websocket-handler.mdx +5 -1
  38. package/docs/mcp-gateway/observability/logging.mdx +19 -12
  39. package/docs/mcp-server/resources.mdx +27 -15
  40. package/docs/mcp-server/testing.mdx +0 -2
  41. package/docs/policies/archive-request-azure-storage-inbound/doc.md +1 -1
  42. package/docs/policies/archive-response-azure-storage-outbound/doc.md +1 -1
  43. package/docs/policies/ip-restriction-inbound/policy.ts +1 -1
  44. package/docs/programmable-api/http-problems.mdx +0 -18
  45. package/docs/programmable-api/jwt-service-plugin.mdx +131 -109
  46. package/docs/programmable-api/runtime-behaviors.mdx +4 -2
  47. package/docs/programmable-api/streaming-zone-cache.mdx +4 -6
  48. package/docs/programmable-api/web-crypto-apis.mdx +10 -6
  49. package/package.json +4 -4
  50. package/docs/errors/get-head-body-error.mdx +0 -41
@@ -222,8 +222,11 @@ export function runtimeInit(runtime: RuntimeExtensions) {
222
222
  ### Tracing and Logging Configuration
223
223
 
224
224
  Logging is only enabled when specifically configured with its own endpoint using
225
- the `logUrl` property. When using both tracing and logging, you can configure
226
- them with separate endpoints.
225
+ the `logUrl` property. When using both tracing and logging, use the top-level
226
+ `traceUrl`, `logUrl`, and `headers` properties instead of the `exporter` object
227
+ shown above. The plugin supports both configuration shapes, but they're mutually
228
+ exclusive: `exporter` configures tracing only, while `traceUrl` and `logUrl`
229
+ configure tracing and logging together with a shared set of `headers`.
227
230
 
228
231
  ```ts title="zuplo.runtime.ts"
229
232
  import { OpenTelemetryPlugin } from "@zuplo/otel";
@@ -10,10 +10,9 @@ tags:
10
10
  ---
11
11
 
12
12
  In this example we show a more advanced implementation of
13
- [dynamic rate limiting](../articles/per-user-rate-limits-using-db.mdx). It uses
14
- a database lookup to get the customer details and combines that with the
15
- ZoneCache to improve performance, reduce latency and lower the load on the
16
- database.
13
+ [dynamic rate limiting](./step-5-dynamic-rate-limiting.mdx). It uses a database
14
+ lookup to get the customer details and combines that with the ZoneCache to
15
+ improve performance, reduce latency and lower the load on the database.
17
16
 
18
17
  In this example we use [Supabase](https://supabase.com) as the database but you
19
18
  could use your own API, [Xata](https://xata.io),
@@ -22,8 +21,8 @@ all.
22
21
 
23
22
  If you haven't already, check out the
24
23
  [rate-limiting policy](../policies/rate-limit-inbound.mdx) and the
25
- [dynamic rate limiting quickstart](../articles/per-user-rate-limits-using-db.mdx).
26
- Then you should be oriented to how dynamic rate limiting works.
24
+ [dynamic rate limiting quickstart](./step-5-dynamic-rate-limiting.mdx). Then you
25
+ should be oriented to how dynamic rate limiting works.
27
26
 
28
27
  Below is a full implementation of a custom rate limiting function. In our
29
28
  example this is a module called `per-user-rate-limiting.ts`.
@@ -1,39 +1,45 @@
1
1
  ---
2
- title: Client mTLS Authentication
2
+ title: Client mTLS authentication
3
+ sidebar_label: Client mTLS
4
+ description:
5
+ Require API callers to present client certificates signed by a CA you trust
6
+ before they reach your Zuplo gateway.
3
7
  ---
4
8
 
5
9
  <EnterpriseFeature name="Client mTLS" />
6
10
 
7
11
  Client mTLS authentication lets your Zuplo gateway verify the identity of
8
- clients calling your API using certificates issued by your own Certificate
9
- Authority (CA). Both the client and the gateway authenticate each other during
10
- the TLS handshake, so only clients holding a certificate signed by your CA can
11
- reach your API.
12
+ clients calling your API with certificates issued by your own certificate
13
+ authority (CA). Both the client and the gateway authenticate each other during
14
+ the TLS handshake. Routes protected by the `mtls-auth-inbound` policy only allow
15
+ clients that present a valid certificate chain anchored by a CA you uploaded to
16
+ Zuplo.
12
17
 
13
- ## How Client mTLS Works
18
+ ## How client mTLS works
14
19
 
15
20
  When a client calls your Zuplo gateway:
16
21
 
17
- 1. The client presents a certificate issued by your CA during the TLS handshake.
18
- 2. Zuplo's edge verifies the certificate against the CA you've uploaded and
19
- passes the verification result (and parsed certificate) to your gateway
20
- workers.
21
- 3. The [`mtls-auth-inbound`](../policies/mtls-auth-inbound.md) policy on your
22
+ 1. The client presents a certificate during the TLS handshake.
23
+ 2. Zuplo's edge verifies the client certificate chain against the CA
24
+ certificates uploaded to your account, then passes the verification result
25
+ and parsed client certificate to your gateway workers.
26
+ 3. The [`mtls-auth-inbound`](../policies/mtls-auth-inbound.mdx) policy on your
22
27
  route reads the verification result, enforces it, and attaches the parsed
23
28
  certificate metadata to `request.user.data.mtlsAuth` for use in your handlers
24
29
  and downstream policies.
25
30
 
26
31
  CA certificates are scoped to your Zuplo **account**, not a single project or
27
- deployment. Once a CA is uploaded, every gateway domain on the account will
28
- verify presented client certificates against it. The policy on each route
32
+ deployment. Once a CA is uploaded, every gateway domain on the account can
33
+ verify presented client certificate chains against it. The policy on each route
29
34
  controls whether unverified traffic is rejected or allowed through.
30
35
 
31
36
  ## Prerequisites
32
37
 
33
38
  Before you begin, you need:
34
39
 
35
- - A public CA certificate (PEM-encoded) that issued or will issue the client
36
- certificates you want to accept
40
+ - A public CA certificate (PEM-encoded) that has issued, or will issue, the
41
+ client certificates you want to accept, either directly or through
42
+ intermediate CAs
37
43
  - The [Zuplo CLI](../cli/overview.mdx) installed and authenticated
38
44
  - A Zuplo project where you can add the `mtls-auth-inbound` policy to a route
39
45
 
@@ -44,7 +50,7 @@ client certificates stay with you and your clients.
44
50
 
45
51
  :::
46
52
 
47
- ## 1/ Upload Your CA Certificate
53
+ ## 1/ Upload your CA certificate
48
54
 
49
55
  Use the Zuplo CLI to upload your CA certificate. The CA is registered against
50
56
  your account and is automatically made available on all of your gateway domains.
@@ -79,21 +85,21 @@ CAs on the account at any time:
79
85
  zuplo ca-certificate list --account your-account
80
86
  ```
81
87
 
82
- See the [`ca-certificate` CLI reference](../cli/ca-certificate-create.md) for
88
+ See the [`ca-certificate` CLI reference](../cli/ca-certificate-create.mdx) for
83
89
  all available subcommands (`create`, `list`, `describe`, `update`, `delete`).
84
90
 
85
91
  :::tip{title="Using an intermediate CA"}
86
92
 
87
93
  If your client certificates are issued by an intermediate CA (rather than
88
- directly by your root), upload the **intermediate** itself as the CA not the
89
- root. The client certs used must be directly signed by the CA certificate you
90
- provide to Zuplo.
94
+ directly by your root), upload the root CA certificate that anchors the chain.
95
+ Clients must send the leaf certificate plus any intermediate certificates when
96
+ they connect.
91
97
 
92
98
  :::
93
99
 
94
- ## 2/ Add the mTLS Auth Inbound Policy
100
+ ## 2/ Add the mTLS auth inbound policy
95
101
 
96
- Add the [`mtls-auth-inbound`](../policies/mtls-auth-inbound.md) policy to any
102
+ Add the [`mtls-auth-inbound`](../policies/mtls-auth-inbound.mdx) policy to any
97
103
  route that should require a verified client certificate. The policy reads the
98
104
  verification result that Zuplo's edge attached to the request and either rejects
99
105
  unverified traffic or allows it through, depending on configuration.
@@ -115,34 +121,35 @@ unverified traffic or allows it through, depending on configuration.
115
121
 
116
122
  **Key options:**
117
123
 
118
- - `allowUnauthenticatedRequests` (default `false`): When `false`, the policy
119
- rejects requests that don't present a valid client certificate signed by a CA
120
- on your account. When `true`, the policy lets traffic through but still
121
- attaches certificate metadata when a parseable client certificate is present —
122
- useful for staged rollouts or logging-only modes.
124
+ - `allowUnauthenticatedRequests` (default `false`): When set to `false`, the
125
+ policy rejects requests that don't present a valid client certificate signed
126
+ by a CA on your account. When set to `true`, the policy lets traffic through
127
+ but still attaches certificate metadata when a parseable client certificate is
128
+ present, which is useful for staged rollouts or logging-only modes.
123
129
  - `certIssuerDN`: The fully qualified issuer distinguished name that the client
124
- certificate must be signed by.
130
+ certificate must be signed by. This is the issuer DN on the client
131
+ certificate, which may be an intermediate CA when the client sends a chain.
125
132
 
126
- See the full [policy reference](../policies/mtls-auth-inbound.md) for all
133
+ See the full [policy reference](../policies/mtls-auth-inbound.mdx) for all
127
134
  options.
128
135
 
129
136
  :::tip{title="Finding your certIssuerDN value"}
130
137
 
131
- The issuer DN of a client certificate is the subject DN of the CA that signed
132
- it. Read it directly from your CA's PEM file with `openssl`:
138
+ The issuer DN is stored on the client certificate itself. Read it from a client
139
+ certificate that Zuplo should accept:
133
140
 
134
141
  ```bash
135
- openssl x509 -in ca.pem -noout -subject -nameopt RFC2253
142
+ openssl x509 -in client.pem -noout -issuer -nameopt RFC2253
136
143
  ```
137
144
 
138
- This prints something like `subject=CN=example-ca,O=Example,C=US`. Copy the part
139
- after `subject=` into `certIssuerDN`. The policy tolerates casing and whitespace
145
+ This prints something like `issuer=CN=example-ca,O=Example,C=US`. Copy the part
146
+ after `issuer=` into `certIssuerDN`. The policy tolerates casing and whitespace
140
147
  differences, but not RDN reordering, so keep the order produced by `openssl`
141
148
  as-is.
142
149
 
143
150
  :::
144
151
 
145
- ## 3/ Read Certificate Metadata in Your Handler
152
+ ## 3/ Read certificate metadata in your handler
146
153
 
147
154
  When verification succeeds, the policy attaches parsed certificate metadata to
148
155
  `request.user.data.mtlsAuth`. If `request.user` does not already exist, the
@@ -188,7 +195,7 @@ forward it to a backend.
188
195
 
189
196
  Once your CA is uploaded and the policy is on the route, you can verify the
190
197
  end-to-end flow with `curl`. You'll need a client certificate and private key
191
- issued by the CA you uploaded.
198
+ issued by, or chained to, the CA you uploaded.
192
199
 
193
200
  Send the certificate and key with `--cert` and `--key`:
194
201
 
@@ -201,11 +208,27 @@ Confirm that:
201
208
 
202
209
  - A request **without** `--cert` is rejected with `401` when
203
210
  `allowUnauthenticatedRequests` is `false`.
204
- - A request with a certificate signed by your uploaded CA succeeds and your
211
+ - A request with a certificate that chains to your uploaded CA succeeds and your
205
212
  handler sees the parsed certificate on `request.user.data.mtlsAuth`.
206
213
  - A request with a certificate signed by a different CA is rejected.
207
214
 
208
- ## Managing CA Certificates
215
+ :::tip{title="Using client certificates as part of a certificate chain"}
216
+
217
+ If your client certificates are issued by an intermediate CA (rather than
218
+ directly by your root), pass a certificate bundle to `curl` that includes the
219
+ leaf client certificate followed by any intermediate CA certificates. Do not
220
+ include the root CA in the client certificate bundle.
221
+
222
+ ```bash
223
+ cat client.pem intermediate.pem > client-chain.pem
224
+
225
+ curl --cert ./client-chain.pem --key ./client.key \
226
+ https://your-gateway.zuplo.app/v1/example
227
+ ```
228
+
229
+ :::
230
+
231
+ ## Manage CA certificates
209
232
 
210
233
  ### Listing CAs
211
234
 
@@ -270,7 +293,7 @@ the CA's subject DN, update `certIssuerDN` to match the new value before cutting
270
293
  clients over — or temporarily set `allowUnauthenticatedRequests: true` to allow
271
294
  both issuers during the transition.
272
295
 
273
- ## Local Development
296
+ ## Local development
274
297
 
275
298
  The `mtls-auth-inbound` policy relies on verification metadata supplied by
276
299
  Zuplo's edge proxy and does not work in local development with `zuplo dev`. Test
@@ -281,7 +304,9 @@ the policy in a working-copy or preview environment.
281
304
  ### Requests are rejected with 401
282
305
 
283
306
  - Confirm the client is presenting a certificate signed by a CA that's been
284
- uploaded with `zuplo ca-certificate list`.
307
+ uploaded with `zuplo ca-certificate list`. If the client certificate is issued
308
+ by an intermediate CA, confirm the client sends the intermediate certificate
309
+ chain.
285
310
  - If you've set `certIssuerDN`, verify it matches
286
311
  `request.user.data.mtlsAuth.issuer` exactly (casing and whitespace are
287
312
  tolerated, but RDN order is not).
@@ -306,10 +331,10 @@ that custom domain.
306
331
  If you add a custom domain later and your clients aren't being verified against
307
332
  it, contact [support@zuplo.com](mailto:support@zuplo.com).
308
333
 
309
- ## Additional Resources
334
+ ## Additional resources
310
335
 
311
- - [`mtls-auth-inbound` policy reference](../policies/mtls-auth-inbound.md)
312
- - [`ca-certificate` CLI reference](../cli/ca-certificate-create.md)
336
+ - [`mtls-auth-inbound` policy reference](../policies/mtls-auth-inbound.mdx)
337
+ - [`ca-certificate` CLI reference](../cli/ca-certificate-create.mdx)
313
338
  - [Gateway to Origin mTLS Authentication](./securing-backend-mtls.mdx) — the
314
339
  reverse direction, where Zuplo authenticates to your backend with a client
315
340
  certificate
@@ -9,7 +9,7 @@ sidebar_label: "1 - Setup Your Gateway"
9
9
  />
10
10
 
11
11
  In this tutorial we'll set up a simple gateway. We'll use a simple origin API at
12
- [getting-started.zuplo.io](https://getting-started.zuplo.io).
12
+ [echo.zuplo.io](https://echo.zuplo.io).
13
13
 
14
14
  Note - Zuplo also supports building and running your API locally. To learn more
15
15
  [see the documentation](./local-development.mdx).
@@ -78,8 +78,6 @@ Note - Zuplo also supports building and running your API locally. To learn more
78
78
  }
79
79
  ```
80
80
 
81
- A secret? Let's try and find out what this API is hiding!
82
-
83
81
  1. Put the base URL in an **Environment Variable**
84
82
 
85
83
  When working with Zuplo, you'll eventually want each
@@ -69,7 +69,7 @@ limiter.
69
69
  </ModalScreenshot>
70
70
 
71
71
  Your rate limiting policy is now intercepting excess requests, protecting the
72
- `getting-started` API.
72
+ echo API.
73
73
 
74
74
  </Stepper>
75
75
 
@@ -258,7 +258,7 @@ For CI/CD examples with other providers, see
258
258
 
259
259
  ## Writing tests
260
260
 
261
- Using Node.js 18 and the Zuplo CLI, it's very easy to write tests that make
261
+ Using Node.js and the Zuplo CLI, it's very easy to write tests that make
262
262
  requests to your API using `fetch` and then validate expectations with `expect`
263
263
  from [chai](https://www.chaijs.com/api/bdd/).
264
264
 
@@ -289,11 +289,15 @@ details.
289
289
 
290
290
  ### GET or HEAD requests with a body
291
291
 
292
- Sending a body with a `GET` or `HEAD` request results in a `GET_HEAD_BODY_ERROR`
293
- response. Some HTTP clients attach a body by default.
292
+ Zuplo removes the body from any `GET` or `HEAD` request on entry and adds a
293
+ `zp-body-removed: true` header so the backend knows the body was removed. The
294
+ request then proceeds as normal, so the symptom is a missing body at the backend
295
+ rather than an error response. Some HTTP clients attach a body by default.
294
296
 
295
297
  **Fix:** Remove the request body for `GET` and `HEAD` requests, or change the
296
- HTTP method to `POST` or `PUT` if a body is required.
298
+ HTTP method to `POST` or `PUT` if a body is required. See
299
+ [zp-body-removed](../programmable-api/zp-body-removed.mdx) for details,
300
+ including an example policy that rejects these requests instead.
297
301
 
298
302
  ## Getting help
299
303
 
@@ -24,19 +24,22 @@ your API Gateway. This is a good way to ensure that only Akamai can access your
24
24
  API Gateway. However, as Akamai is a multi-tenant service, this method isn't
25
25
  sufficient to protect unauthorized traffic from hitting your API Gateway.
26
26
 
27
- In Zuplo, you can utilize the IP Address Restriction policy to limit traffic to
28
- only the Akamai IP addresses. You don't need to provide the address list
29
- manually, instead you can utilize the built-in list as shown below.
27
+ In Zuplo, you can use the custom
28
+ [IP Restriction policy](../policies/ip-restriction-inbound.mdx) to limit traffic
29
+ to only the Akamai IP addresses. Copy the policy code from that page into a
30
+ module in your project (for example, `modules/ip-restriction-inbound.ts`), then
31
+ configure the policy with the IP ranges that Akamai publishes for your account
32
+ in Akamai Control Center.
30
33
 
31
34
  ```json
32
35
  {
33
36
  "name": "allow-akamai-only",
34
- "policyType": "ip-address-restriction-inbound",
37
+ "policyType": "ip-restriction-inbound",
35
38
  "handler": {
36
- "export": "IPAddressRestrictionInbound",
37
- "module": "$import(@zuplo/runtime)",
39
+ "export": "default",
40
+ "module": "$import(./modules/ip-restriction-inbound)",
38
41
  "options": {
39
- "allowedIpAddresses": ["list:akamai"]
42
+ "allowedIpAddresses": ["23.32.0.0/11", "104.64.0.0/10"]
40
43
  }
41
44
  }
42
45
  }
@@ -57,20 +60,36 @@ In Akamai, you can configure custom headers using the Property Manager or the
57
60
  Akamai API. Add a custom header with a secret value that only you and Akamai
58
61
  know.
59
62
 
60
- In Zuplo, you can utilize the Header Restriction policy to limit traffic to only
61
- those requests that include the custom header and secret value.
63
+ In Zuplo, you can use a small custom code policy to limit traffic to only those
64
+ requests that include the custom header and secret value.
65
+
66
+ ```ts title="modules/require-akamai-header.ts"
67
+ import {
68
+ environment,
69
+ HttpProblems,
70
+ ZuploContext,
71
+ ZuploRequest,
72
+ } from "@zuplo/runtime";
73
+
74
+ export default async function policy(
75
+ request: ZuploRequest,
76
+ context: ZuploContext,
77
+ ) {
78
+ const headerValue = request.headers.get("x-akamai-auth");
79
+ if (!headerValue || headerValue !== environment.AKAMAI_SECRET_HEADER_VALUE) {
80
+ return HttpProblems.unauthorized(request, context);
81
+ }
82
+ return request;
83
+ }
84
+ ```
62
85
 
63
86
  ```json
64
87
  {
65
88
  "name": "allow-akamai-custom-header",
66
- "policyType": "require-header-inbound",
89
+ "policyType": "custom-code-inbound",
67
90
  "handler": {
68
- "export": "RequireHeaderInboundPolicy",
69
- "module": "$import(@zuplo/runtime)",
70
- "options": {
71
- "headerName": "x-akamai-auth",
72
- "allowedValues": ["$env(AKAMAI_SECRET_HEADER_VALUE)"]
73
- }
91
+ "export": "default",
92
+ "module": "$import(./modules/require-akamai-header)"
74
93
  }
75
94
  }
76
95
  ```
@@ -26,19 +26,22 @@ way to ensure that only CloudFront can access your API Gateway. However, as
26
26
  CloudFront is available to any AWS customer, this method isn't sufficient to
27
27
  protect unauthorized traffic from hitting your API Gateway.
28
28
 
29
- In Zuplo, you can utilize the IP Address Restriction policy to limit traffic to
30
- only the CloudFront IP addresses. You don't need to provide the address list
31
- manually, instead you can utilize the built-in list as shown below.
29
+ In Zuplo, you can use the custom
30
+ [IP Restriction policy](../policies/ip-restriction-inbound.mdx) to limit traffic
31
+ to only the CloudFront IP addresses. Copy the policy code from that page into a
32
+ module in your project (for example, `modules/ip-restriction-inbound.ts`), then
33
+ configure the policy with the `CLOUDFRONT` ranges from the
34
+ [AWS IP address ranges list](https://ip-ranges.amazonaws.com/ip-ranges.json).
32
35
 
33
36
  ```json
34
37
  {
35
38
  "name": "allow-cloudfront-only",
36
- "policyType": "ip-address-restriction-inbound",
39
+ "policyType": "ip-restriction-inbound",
37
40
  "handler": {
38
- "export": "IPAddressRestrictionInbound",
39
- "module": "$import(@zuplo/runtime)",
41
+ "export": "default",
42
+ "module": "$import(./modules/ip-restriction-inbound)",
40
43
  "options": {
41
- "allowedIpAddresses": ["list:aws-cloudfront"]
44
+ "allowedIpAddresses": ["13.32.0.0/15", "13.35.0.0/16"]
42
45
  }
43
46
  }
44
47
  }
@@ -55,20 +58,36 @@ checked by your API Gateway. This provides an additional layer of security on
55
58
  top of IP address restrictions and prevents any unauthorized traffic from
56
59
  hitting your API Gateway - regardless of the source.
57
60
 
58
- In Zuplo, you can utilize the Header Restriction policy to limit traffic to only
59
- those requests that include the custom header and secret value.
61
+ In Zuplo, you can use a small custom code policy to limit traffic to only those
62
+ requests that include the custom header and secret value.
63
+
64
+ ```ts title="modules/require-secure-header.ts"
65
+ import {
66
+ environment,
67
+ HttpProblems,
68
+ ZuploContext,
69
+ ZuploRequest,
70
+ } from "@zuplo/runtime";
71
+
72
+ export default async function policy(
73
+ request: ZuploRequest,
74
+ context: ZuploContext,
75
+ ) {
76
+ const headerValue = request.headers.get("secure-header");
77
+ if (!headerValue || headerValue !== environment.MY_SECRET_HEADER_VALUE) {
78
+ return HttpProblems.unauthorized(request, context);
79
+ }
80
+ return request;
81
+ }
82
+ ```
60
83
 
61
84
  ```json
62
85
  {
63
86
  "name": "allow-cloudfront-custom-header",
64
- "policyType": "require-header-inbound",
87
+ "policyType": "custom-code-inbound",
65
88
  "handler": {
66
- "export": "RequireHeaderInboundPolicy",
67
- "module": "$import(@zuplo/runtime)",
68
- "options": {
69
- "headerName": "secure-header",
70
- "allowedValues": ["$env(MY_SECRET_HEADER_VALUE)"]
71
- }
89
+ "export": "default",
90
+ "module": "$import(./modules/require-secure-header)"
72
91
  }
73
92
  }
74
93
  ```
@@ -27,19 +27,22 @@ your API Gateway. This is a good way to ensure that only Fastly can access your
27
27
  API Gateway. However, as Fastly is a multi-tenant service, this method isn't
28
28
  sufficient to protect unauthorized traffic from hitting your API Gateway.
29
29
 
30
- In Zuplo, you can utilize the IP Address Restriction policy to limit traffic to
31
- only the Fastly IP addresses. You don't need to provide the address list
32
- manually, instead you can utilize the built-in list as shown below.
30
+ In Zuplo, you can use the custom
31
+ [IP Restriction policy](../policies/ip-restriction-inbound.mdx) to limit traffic
32
+ to only the Fastly IP addresses. Copy the policy code from that page into a
33
+ module in your project (for example, `modules/ip-restriction-inbound.ts`), then
34
+ configure the policy with the address ranges from
35
+ [Fastly's public IP list](https://api.fastly.com/public-ip-list).
33
36
 
34
37
  ```json
35
38
  {
36
39
  "name": "allow-fastly-only",
37
- "policyType": "ip-address-restriction-inbound",
40
+ "policyType": "ip-restriction-inbound",
38
41
  "handler": {
39
- "export": "IPAddressRestrictionInbound",
40
- "module": "$import(@zuplo/runtime)",
42
+ "export": "default",
43
+ "module": "$import(./modules/ip-restriction-inbound)",
41
44
  "options": {
42
- "allowedIpAddresses": ["list:fastly"]
45
+ "allowedIpAddresses": ["151.101.0.0/16", "199.232.0.0/16"]
43
46
  }
44
47
  }
45
48
  }
@@ -124,16 +124,19 @@ zuplo deploy --project my-project --environment my-env-name
124
124
 
125
125
  ## Polling timeout
126
126
 
127
- By default, the deploy command will poll the status of the deployment every
128
- second for 150 seconds. For most deployments this is enough time for the build
129
- and deploy process to complete. However, if you have a large project, this may
130
- not be enough time. You can increase the timeout by setting the following
131
- environment variables.
132
-
133
- - `POLL_INTERVAL` - The interval in seconds between each poll. Default is 1
134
- second.
135
- - `MAX_POLL_RETRIES` - The maximum number of retries before the command times
136
- out. Default is 150.
127
+ By default, the deploy command polls the status of the deployment every second
128
+ for up to 250 attempts (a little over four minutes). For most deployments this
129
+ is enough time for the build and deploy process to complete. However, if you
130
+ have a large project, this may not be enough time. You can increase the timeout
131
+ by setting the following environment variables.
132
+
133
+ - `POLL_INTERVAL` - The interval in milliseconds between each poll. Default is
134
+ `1000` (1 second).
135
+ - `MAX_POLL_RETRIES` - The maximum number of polls before the command times
136
+ out. Default is `250`.
137
+
138
+ The following example polls every 5 seconds for up to 300 attempts (25
139
+ minutes).
137
140
 
138
141
  ```bash
139
142
  POLL_INTERVAL=5000 MAX_POLL_RETRIES=300 zuplo deploy
@@ -27,16 +27,19 @@ zuplo deploy --project my-project --environment my-env-name
27
27
 
28
28
  ## Polling timeout
29
29
 
30
- By default, the deploy command will poll the status of the deployment every
31
- second for 150 seconds. For most deployments this is enough time for the build
32
- and deploy process to complete. However, if you have a large project, this may
33
- not be enough time. You can increase the timeout by setting the following
34
- environment variables.
35
-
36
- - `POLL_INTERVAL` - The interval in seconds between each poll. Default is 1
37
- second.
38
- - `MAX_POLL_RETRIES` - The maximum number of retries before the command times
39
- out. Default is 150.
30
+ By default, the deploy command polls the status of the deployment every second
31
+ for up to 250 attempts (a little over four minutes). For most deployments this
32
+ is enough time for the build and deploy process to complete. However, if you
33
+ have a large project, this may not be enough time. You can increase the timeout
34
+ by setting the following environment variables.
35
+
36
+ - `POLL_INTERVAL` - The interval in milliseconds between each poll. Default is
37
+ `1000` (1 second).
38
+ - `MAX_POLL_RETRIES` - The maximum number of polls before the command times
39
+ out. Default is `250`.
40
+
41
+ The following example polls every 5 seconds for up to 300 attempts (25
42
+ minutes).
40
43
 
41
44
  ```bash
42
45
  POLL_INTERVAL=5000 MAX_POLL_RETRIES=300 zuplo deploy