zuplo 6.73.19 → 6.73.20
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.
- package/docs/articles/local-development-troubleshooting.mdx +10 -0
- package/docs/articles/securing-backend-mtls.mdx +162 -14
- package/docs/cli/dev.mdx +44 -0
- package/docs/cli/dev.partial.mdx +47 -0
- package/docs/dev-portal/zudoku/configuration/authentication-azure-ad.md +17 -15
- package/docs/dev-portal/zudoku/configuration/authentication.md +22 -2
- package/docs/policies/_index.md +1 -1
- package/docs/policies/secret-masking-outbound/doc.md +53 -0
- package/docs/policies/secret-masking-outbound/intro.md +7 -0
- package/docs/policies/secret-masking-outbound/schema.json +6 -5
- package/docs/programmable-api/zuplo-json.mdx +8 -0
- package/package.json +4 -4
|
@@ -45,6 +45,16 @@ certificates, you can add the following script:
|
|
|
45
45
|
}
|
|
46
46
|
```
|
|
47
47
|
|
|
48
|
+
## mTLS client certificates don't load
|
|
49
|
+
|
|
50
|
+
On `managed-dedicated` and `self-hosted` projects, `zuplo dev` loads client
|
|
51
|
+
certificates from `.zuplo-local/mtls/<cert-name>/tls.crt` and `tls.key`, or from
|
|
52
|
+
the directory passed to `--mtls-certs`. If the startup output reports no loaded
|
|
53
|
+
certificates, check the warnings listed in
|
|
54
|
+
[Local certificates fail to load](./securing-backend-mtls.mdx#local-certificates-fail-to-load).
|
|
55
|
+
|
|
56
|
+
Local mTLS isn't available on `managed-edge` projects.
|
|
57
|
+
|
|
48
58
|
## "unknown format ... ignored" warnings
|
|
49
59
|
|
|
50
60
|
When the development server prints warnings like
|
|
@@ -71,7 +71,7 @@ project. You can upload multiple certificates, each with a unique name.
|
|
|
71
71
|
zuplo mtls-certificate create \
|
|
72
72
|
--cert cert.pem \
|
|
73
73
|
--key key.pem \
|
|
74
|
-
--name
|
|
74
|
+
--name my_backend_cert \
|
|
75
75
|
--account your-account \
|
|
76
76
|
--project your-project \
|
|
77
77
|
--environment-type development \
|
|
@@ -113,7 +113,7 @@ import { ZuploContext, ZuploRequest } from "@zuplo/runtime";
|
|
|
113
113
|
export default async function (request: ZuploRequest, context: ZuploContext) {
|
|
114
114
|
const response = await fetch("https://secure-backend.example.com/api", {
|
|
115
115
|
zuplo: {
|
|
116
|
-
mtlsCertificate: "
|
|
116
|
+
mtlsCertificate: "my_backend_cert",
|
|
117
117
|
},
|
|
118
118
|
});
|
|
119
119
|
|
|
@@ -132,7 +132,7 @@ that make outbound requests:
|
|
|
132
132
|
"module": "$import(@zuplo/runtime)",
|
|
133
133
|
"options": {
|
|
134
134
|
"baseUrl": "https://secure-backend.example.com",
|
|
135
|
-
"mtlsCertificate": "
|
|
135
|
+
"mtlsCertificate": "my_backend_cert"
|
|
136
136
|
}
|
|
137
137
|
}
|
|
138
138
|
```
|
|
@@ -145,13 +145,13 @@ For better flexibility across environments, store the certificate name as an
|
|
|
145
145
|
**Production environment:**
|
|
146
146
|
|
|
147
147
|
```text
|
|
148
|
-
BACKEND_MTLS_CERT=
|
|
148
|
+
BACKEND_MTLS_CERT=my_backend_prod_cert
|
|
149
149
|
```
|
|
150
150
|
|
|
151
151
|
**Staging environment:**
|
|
152
152
|
|
|
153
153
|
```text
|
|
154
|
-
BACKEND_MTLS_CERT=
|
|
154
|
+
BACKEND_MTLS_CERT=my_backend_staging_cert
|
|
155
155
|
```
|
|
156
156
|
|
|
157
157
|
Then reference it in your code:
|
|
@@ -195,13 +195,43 @@ zuplo mtls-certificate list \
|
|
|
195
195
|
--project your-project
|
|
196
196
|
```
|
|
197
197
|
|
|
198
|
+
Each entry includes the certificate ID, which the other commands take as
|
|
199
|
+
`--cert-id`.
|
|
200
|
+
|
|
201
|
+
### Inspecting a Certificate
|
|
202
|
+
|
|
203
|
+
To see the subject, issuer, validity dates, and enabled environment types for
|
|
204
|
+
one certificate:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
zuplo mtls-certificate describe \
|
|
208
|
+
--cert-id cert_abc123 \
|
|
209
|
+
--account your-account \
|
|
210
|
+
--project your-project
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### Changing Environment Types
|
|
214
|
+
|
|
215
|
+
To change which environment types can use a certificate, pass the complete set
|
|
216
|
+
of environment types you want enabled — the command replaces the existing set
|
|
217
|
+
rather than adding to it:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
zuplo mtls-certificate update \
|
|
221
|
+
--cert-id cert_abc123 \
|
|
222
|
+
--environment-type preview \
|
|
223
|
+
--environment-type production \
|
|
224
|
+
--account your-account \
|
|
225
|
+
--project your-project
|
|
226
|
+
```
|
|
227
|
+
|
|
198
228
|
### Deleting Certificates
|
|
199
229
|
|
|
200
230
|
To remove a certificate:
|
|
201
231
|
|
|
202
232
|
```bash
|
|
203
233
|
zuplo mtls-certificate delete \
|
|
204
|
-
--cert-id
|
|
234
|
+
--cert-id cert_abc123 \
|
|
205
235
|
--account your-account \
|
|
206
236
|
--project your-project
|
|
207
237
|
```
|
|
@@ -238,19 +268,112 @@ you rotate the certificate.
|
|
|
238
268
|
|
|
239
269
|
## Local Development
|
|
240
270
|
|
|
241
|
-
|
|
271
|
+
`zuplo dev` can present client certificates to your backend, so the same
|
|
272
|
+
`mtlsCertificate` code path you deploy also works on your machine. Support
|
|
273
|
+
depends on your project type, set by
|
|
274
|
+
[`projectType`](../programmable-api/zuplo-json.mdx#projecttype) in
|
|
275
|
+
`zuplo.jsonc`:
|
|
276
|
+
|
|
277
|
+
| `projectType` | Local mTLS support |
|
|
278
|
+
| ---------------------------------- | -------------------------------------------------------- |
|
|
279
|
+
| `managed-dedicated`, `self-hosted` | Supported — certificates load from your local filesystem |
|
|
280
|
+
| `managed-edge` | Not supported |
|
|
281
|
+
|
|
282
|
+
If `zuplo.jsonc` has no `projectType` field, run [`zuplo link`](../cli/link.mdx)
|
|
283
|
+
— it looks up the linked project and writes the matching type into the file.
|
|
284
|
+
Without that field, local development falls back to `managed-edge` and skips
|
|
285
|
+
mTLS, even when the project deploys to a dedicated environment.
|
|
286
|
+
|
|
287
|
+
On `managed-edge` projects, mTLS only works in deployed environments. Test mTLS
|
|
288
|
+
routes in a preview environment, point local runs at a backend endpoint that
|
|
289
|
+
doesn't require client certificates, or branch on
|
|
290
|
+
[`environment`](./environment-variables.mdx) to skip mTLS locally.
|
|
291
|
+
|
|
292
|
+
Certificates never leave your machine — the CLI reads them from disk and passes
|
|
293
|
+
them to the local runtime. It doesn't upload them to Zuplo or read the
|
|
294
|
+
certificates you uploaded with `zuplo mtls-certificate create`.
|
|
295
|
+
|
|
296
|
+
### Add certificates to your project
|
|
297
|
+
|
|
298
|
+
Place each certificate in its own subdirectory of `.zuplo-local/mtls`, named
|
|
299
|
+
after the certificate. The layout matches the one used for deployments:
|
|
300
|
+
|
|
301
|
+
```text
|
|
302
|
+
my-project/
|
|
303
|
+
├── .zuplo-local/
|
|
304
|
+
│ └── mtls/
|
|
305
|
+
│ └── my_backend_cert/
|
|
306
|
+
│ ├── tls.crt
|
|
307
|
+
│ └── tls.key
|
|
308
|
+
├── config/
|
|
309
|
+
├── modules/
|
|
310
|
+
└── zuplo.jsonc
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
The subdirectory name is the name your code references, so use the same name as
|
|
314
|
+
the certificate you uploaded to Zuplo. Then
|
|
315
|
+
`fetch(url, { zuplo: { mtlsCertificate: "my_backend_cert" } })` resolves locally
|
|
316
|
+
and in deployed environments without a code change.
|
|
317
|
+
|
|
318
|
+
Both files must be PEM-encoded, and `tls.key` must be unencrypted — the same
|
|
319
|
+
requirements as an uploaded certificate.
|
|
242
320
|
|
|
243
|
-
|
|
244
|
-
|
|
321
|
+
:::caution{title="Keep private keys out of Git"}
|
|
322
|
+
|
|
323
|
+
`.zuplo-local/` holds unencrypted private keys. Projects created with
|
|
324
|
+
`create-zuplo-api` gitignore it already. For older projects, add `.zuplo-local/`
|
|
325
|
+
to your `.gitignore` — `zuplo dev` prints a warning at startup when it isn't
|
|
326
|
+
covered.
|
|
245
327
|
|
|
246
328
|
:::
|
|
247
329
|
|
|
248
|
-
|
|
330
|
+
Start the server as usual:
|
|
249
331
|
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
332
|
+
```bash
|
|
333
|
+
npx zuplo dev
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
At startup the CLI reports what it loaded:
|
|
337
|
+
|
|
338
|
+
```text
|
|
339
|
+
Loaded 1 local mTLS client certificate(s) from /path/to/my-project/.zuplo-local/mtls: my_backend_cert. Reference by name via the mtlsCertificate option.
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Load certificates from another directory
|
|
343
|
+
|
|
344
|
+
To keep certificates outside the project — a shared team directory, or a path
|
|
345
|
+
your secret manager writes to — pass `--mtls-certs`:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
npx zuplo dev --mtls-certs ~/certs/zuplo-uat
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
The flag expects the same `<dir>/<cert-name>/tls.crt` layout and wins over
|
|
352
|
+
`.zuplo-local/mtls`. Unlike auto-detection, it fails fast: if the directory
|
|
353
|
+
doesn't exist or holds no valid certificate, the server doesn't start.
|
|
354
|
+
`--mtls-certificates-dir` is an alias for the same flag.
|
|
355
|
+
|
|
356
|
+
The CLI only looks in these two places, in order:
|
|
357
|
+
|
|
358
|
+
1. The directory passed to `--mtls-certs`
|
|
359
|
+
2. `<project>/.zuplo-local/mtls`
|
|
360
|
+
|
|
361
|
+
There is no fallback to a directory in your home folder, because client
|
|
362
|
+
certificates are scoped to a specific gateway.
|
|
363
|
+
|
|
364
|
+
### Choose the right certificate for local runs
|
|
365
|
+
|
|
366
|
+
The certificate you load locally is presented to whatever backend your route
|
|
367
|
+
calls. Use a certificate issued for a development or staging backend, and keep
|
|
368
|
+
production certificates off developer machines.
|
|
369
|
+
|
|
370
|
+
:::danger
|
|
371
|
+
|
|
372
|
+
Loading a production client certificate locally lets any code on your machine
|
|
373
|
+
authenticate to your production backend as the gateway. Treat these files like
|
|
374
|
+
any other production credential.
|
|
375
|
+
|
|
376
|
+
:::
|
|
254
377
|
|
|
255
378
|
## Troubleshooting
|
|
256
379
|
|
|
@@ -333,6 +456,31 @@ If requests fail to connect:
|
|
|
333
456
|
preview, production)
|
|
334
457
|
- Check that your backend's CA certificate is properly configured
|
|
335
458
|
|
|
459
|
+
### Local Certificates Fail to Load
|
|
460
|
+
|
|
461
|
+
If `zuplo dev` starts without reporting a loaded certificate, check the startup
|
|
462
|
+
output for one of these warnings:
|
|
463
|
+
|
|
464
|
+
- **"Local mTLS client certificates are only supported for managed-dedicated
|
|
465
|
+
projects"** — the project resolves to `managed-edge`. If `zuplo.jsonc` has no
|
|
466
|
+
`projectType` field, run [`zuplo link`](../cli/link.mdx) to add it and start
|
|
467
|
+
the server again. If the field says `managed-edge`, local mTLS isn't
|
|
468
|
+
available; see [Local Development](#local-development).
|
|
469
|
+
- **"Ignoring mTLS certificate directory … because it is missing `tls.key`"** —
|
|
470
|
+
a subdirectory has only one of the two files. Add the missing file — each
|
|
471
|
+
certificate directory needs both `tls.crt` and `tls.key`.
|
|
472
|
+
- **"Ignoring `--mtls-certs`: … are set in `.env` or `.env.zuplo`"** — a
|
|
473
|
+
previous manual setup left `__ZUPLO_MTLS_CLIENT_CERT_NAMES` or
|
|
474
|
+
`__ZUPLO_MTLS_CLIENT_CERT_BASE_DIR` in an env file. Those values take
|
|
475
|
+
precedence in the local runtime. Remove them from `.env` and `.env.zuplo` to
|
|
476
|
+
use `--mtls-certs` or `.zuplo-local/mtls`.
|
|
477
|
+
- **"Found local mTLS certificates directory … but it does not contain any valid
|
|
478
|
+
certificate entries"** — the certificates are loose files rather than in a
|
|
479
|
+
`<cert-name>/` subdirectory.
|
|
480
|
+
|
|
481
|
+
If no warning appears at all, confirm the directory is `.zuplo-local/mtls` (not
|
|
482
|
+
`.zuplo/mtls`) at the project root, next to `zuplo.jsonc`.
|
|
483
|
+
|
|
336
484
|
### Runtime Errors
|
|
337
485
|
|
|
338
486
|
If you see errors about missing certificates:
|
package/docs/cli/dev.mdx
CHANGED
|
@@ -116,6 +116,44 @@ sidebar_label: dev
|
|
|
116
116
|
usage="$0 dev [options]"
|
|
117
117
|
>
|
|
118
118
|
|
|
119
|
+
## Local mTLS client certificates
|
|
120
|
+
|
|
121
|
+
On `managed-dedicated` and `self-hosted` projects, `zuplo dev` presents client
|
|
122
|
+
certificates to your backend, so routes that set `mtlsCertificate` work locally
|
|
123
|
+
without a code change.
|
|
124
|
+
|
|
125
|
+
Put each certificate in its own subdirectory of `.zuplo-local/mtls`, named after
|
|
126
|
+
the certificate:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
.zuplo-local/mtls/my_backend_cert/tls.crt
|
|
130
|
+
.zuplo-local/mtls/my_backend_cert/tls.key
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
`zuplo dev` finds that directory automatically and logs the certificates it
|
|
134
|
+
loaded. To read certificates from somewhere else, pass `--mtls-certs`:
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
npx zuplo dev --mtls-certs ~/certs/zuplo-uat
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
The flag takes precedence over `.zuplo-local/mtls` and fails fast when the
|
|
141
|
+
directory is missing or holds no valid certificate.
|
|
142
|
+
|
|
143
|
+
`.zuplo-local/` contains unencrypted private keys. Projects created with
|
|
144
|
+
`create-zuplo-api` gitignore it already; for older projects, add
|
|
145
|
+
`.zuplo-local/` to your `.gitignore`. `zuplo dev` warns at startup when it
|
|
146
|
+
isn't covered.
|
|
147
|
+
|
|
148
|
+
The project type comes from `projectType` in `zuplo.jsonc`. If that field is
|
|
149
|
+
missing, run [`zuplo link`](./link.mdx) to have the CLI detect and write it —
|
|
150
|
+
otherwise local development falls back to `managed-edge` and skips mTLS.
|
|
151
|
+
|
|
152
|
+
On `managed-edge` projects, local mTLS isn't available and `--mtls-certs` is
|
|
153
|
+
ignored with a warning. For the full workflow, including certificate
|
|
154
|
+
requirements and troubleshooting, see
|
|
155
|
+
[Gateway to Origin mTLS Authentication](../articles/securing-backend-mtls.mdx#local-development).
|
|
156
|
+
|
|
119
157
|
</CliCommand>
|
|
120
158
|
|
|
121
159
|
## Global options
|
|
@@ -124,3 +162,9 @@ The following global options are available for all commands:
|
|
|
124
162
|
|
|
125
163
|
- [`--help`](./global-options.mdx#help)
|
|
126
164
|
- [`--api-key`](./global-options.mdx#api-key)
|
|
165
|
+
|
|
166
|
+
## Additional resources
|
|
167
|
+
|
|
168
|
+
- [Local Development Troubleshooting](../articles/local-development-troubleshooting.mdx)
|
|
169
|
+
- [Testing your API](../articles/testing.mdx)
|
|
170
|
+
- [Gateway to Origin mTLS Authentication](../articles/securing-backend-mtls.mdx)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
---
|
|
2
|
+
additional-resources:
|
|
3
|
+
- name: Local Development Troubleshooting
|
|
4
|
+
href: ../articles/local-development-troubleshooting.mdx
|
|
5
|
+
- name: Testing your API
|
|
6
|
+
href: ../articles/testing.mdx
|
|
7
|
+
- name: Gateway to Origin mTLS Authentication
|
|
8
|
+
href: ../articles/securing-backend-mtls.mdx
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Local mTLS client certificates
|
|
12
|
+
|
|
13
|
+
On `managed-dedicated` and `self-hosted` projects, `zuplo dev` presents client
|
|
14
|
+
certificates to your backend, so routes that set `mtlsCertificate` work locally
|
|
15
|
+
without a code change.
|
|
16
|
+
|
|
17
|
+
Put each certificate in its own subdirectory of `.zuplo-local/mtls`, named after
|
|
18
|
+
the certificate:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
.zuplo-local/mtls/my_backend_cert/tls.crt
|
|
22
|
+
.zuplo-local/mtls/my_backend_cert/tls.key
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
`zuplo dev` finds that directory automatically and logs the certificates it
|
|
26
|
+
loaded. To read certificates from somewhere else, pass `--mtls-certs`:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx zuplo dev --mtls-certs ~/certs/zuplo-uat
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The flag takes precedence over `.zuplo-local/mtls` and fails fast when the
|
|
33
|
+
directory is missing or holds no valid certificate.
|
|
34
|
+
|
|
35
|
+
`.zuplo-local/` contains unencrypted private keys. Projects created with
|
|
36
|
+
`create-zuplo-api` gitignore it already; for older projects, add
|
|
37
|
+
`.zuplo-local/` to your `.gitignore`. `zuplo dev` warns at startup when it
|
|
38
|
+
isn't covered.
|
|
39
|
+
|
|
40
|
+
The project type comes from `projectType` in `zuplo.jsonc`. If that field is
|
|
41
|
+
missing, run [`zuplo link`](./link.mdx) to have the CLI detect and write it —
|
|
42
|
+
otherwise local development falls back to `managed-edge` and skips mTLS.
|
|
43
|
+
|
|
44
|
+
On `managed-edge` projects, local mTLS isn't available and `--mtls-certs` is
|
|
45
|
+
ignored with a warning. For the full workflow, including certificate
|
|
46
|
+
requirements and troubleshooting, see
|
|
47
|
+
[Gateway to Origin mTLS Authentication](../articles/securing-backend-mtls.mdx#local-development).
|
|
@@ -72,9 +72,9 @@ to integrate Azure AD with your Dev Portal documentation site.
|
|
|
72
72
|
export default {
|
|
73
73
|
// ... other configuration
|
|
74
74
|
authentication: {
|
|
75
|
-
type: "
|
|
75
|
+
type: "entra",
|
|
76
76
|
clientId: "<your-application-client-id>",
|
|
77
|
-
|
|
77
|
+
tenantId: "<your-tenant-id>",
|
|
78
78
|
scopes: ["openid", "profile", "email"], // Optional: customize scopes
|
|
79
79
|
},
|
|
80
80
|
// ... other configuration
|
|
@@ -91,20 +91,21 @@ For single tenant (organization-only access):
|
|
|
91
91
|
|
|
92
92
|
```typescript
|
|
93
93
|
authentication: {
|
|
94
|
-
type: "
|
|
94
|
+
type: "entra",
|
|
95
95
|
clientId: "<your-application-client-id>",
|
|
96
|
-
|
|
96
|
+
tenantId: "<your-tenant-id>",
|
|
97
97
|
scopes: ["openid", "profile", "email"],
|
|
98
98
|
}
|
|
99
99
|
```
|
|
100
100
|
|
|
101
|
-
For multitenant (any Azure AD organization):
|
|
101
|
+
For multitenant (any Azure AD organization), use `tenantId: "common"` or `"organizations"` — this is
|
|
102
|
+
also the default if `tenantId` is omitted:
|
|
102
103
|
|
|
103
104
|
```typescript
|
|
104
105
|
authentication: {
|
|
105
|
-
type: "
|
|
106
|
+
type: "entra",
|
|
106
107
|
clientId: "<your-application-client-id>",
|
|
107
|
-
|
|
108
|
+
tenantId: "common",
|
|
108
109
|
scopes: ["openid", "profile", "email"],
|
|
109
110
|
}
|
|
110
111
|
```
|
|
@@ -115,9 +116,9 @@ Request additional Microsoft Graph API scopes:
|
|
|
115
116
|
|
|
116
117
|
```typescript
|
|
117
118
|
authentication: {
|
|
118
|
-
type: "
|
|
119
|
+
type: "entra",
|
|
119
120
|
clientId: "<your-application-client-id>",
|
|
120
|
-
|
|
121
|
+
tenantId: "<your-tenant-id>",
|
|
121
122
|
scopes: [
|
|
122
123
|
"openid",
|
|
123
124
|
"profile",
|
|
@@ -136,7 +137,7 @@ Protect specific documentation routes using the `protectedRoutes` configuration:
|
|
|
136
137
|
{
|
|
137
138
|
// ... other configuration
|
|
138
139
|
authentication: {
|
|
139
|
-
type: "
|
|
140
|
+
type: "entra",
|
|
140
141
|
// ... Azure AD config
|
|
141
142
|
},
|
|
142
143
|
protectedRoutes: [
|
|
@@ -217,16 +218,17 @@ Azure AD provides rich user profile data through OpenID Connect:
|
|
|
217
218
|
2. **Redirect URI Mismatch**: The redirect URI must exactly match one configured in Azure AD,
|
|
218
219
|
including protocol and path.
|
|
219
220
|
|
|
220
|
-
3. **Tenant Access Issues**: For single-tenant apps, ensure users are from the correct tenant
|
|
221
|
-
multi-tenant,
|
|
221
|
+
3. **Tenant Access Issues**: For single-tenant apps, ensure users are from the correct tenant and
|
|
222
|
+
`tenantId` is set to that tenant's GUID. For multi-tenant, use `tenantId: "common"` or
|
|
223
|
+
`"organizations"`.
|
|
222
224
|
|
|
223
225
|
4. **Missing User Information**: Check that required API permissions are granted and admin consent
|
|
224
226
|
is provided if needed.
|
|
225
227
|
|
|
226
|
-
5. **Token Validation Errors**: Ensure your
|
|
227
|
-
|
|
228
|
+
5. **Token Validation Errors**: Ensure your `tenantId` is correct. If you use a CIAM tenant
|
|
229
|
+
(`*.ciamlogin.com`), set the `issuer` option to override the default issuer instead.
|
|
228
230
|
|
|
229
|
-
6. **Authentication Not Working**: Verify your
|
|
231
|
+
6. **Authentication Not Working**: Verify your `tenantId` and client ID are correct, and that your
|
|
230
232
|
app registration is configured as a Single-page application (SPA) with the correct redirect URIs.
|
|
231
233
|
|
|
232
234
|
## Security Best Practices
|
|
@@ -15,8 +15,8 @@ authentication provider you use.
|
|
|
15
15
|
|
|
16
16
|
## Authentication Providers
|
|
17
17
|
|
|
18
|
-
Dev Portal supports Clerk, Auth0, Supabase, Firebase, Azure B2C, and any OpenID
|
|
19
|
-
(including Okta, Keycloak, Authentik, and PingFederate).
|
|
18
|
+
Dev Portal supports Clerk, Auth0, Supabase, Firebase, Microsoft Entra ID, Azure B2C, and any OpenID
|
|
19
|
+
Connect provider (including Okta, Keycloak, Authentik, and PingFederate).
|
|
20
20
|
|
|
21
21
|
Not seeing your authentication provider? [Let us know](https://github.com/zuplo/zudoku/issues)
|
|
22
22
|
|
|
@@ -99,6 +99,26 @@ providing your own array of scopes.
|
|
|
99
99
|
For provider-specific guides (Okta, Keycloak, etc.), see the
|
|
100
100
|
[OpenID Connect setup page](./authentication-openid.md).
|
|
101
101
|
|
|
102
|
+
### Microsoft Entra ID
|
|
103
|
+
|
|
104
|
+
For Microsoft Entra ID (formerly Azure AD), you will need the `clientId` from your app registration
|
|
105
|
+
and your `tenantId`.
|
|
106
|
+
|
|
107
|
+
```typescript
|
|
108
|
+
{
|
|
109
|
+
// ...
|
|
110
|
+
authentication: {
|
|
111
|
+
type: "entra",
|
|
112
|
+
clientId: "<your-application-client-id>",
|
|
113
|
+
tenantId: "<your-tenant-id>", // Or "common" for multitenant. Defaults to "common".
|
|
114
|
+
},
|
|
115
|
+
// ...
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
For full setup instructions, see the
|
|
120
|
+
[Azure AD / Entra ID setup guide](./authentication-azure-ad.md).
|
|
121
|
+
|
|
102
122
|
### Firebase
|
|
103
123
|
|
|
104
124
|
For Firebase authentication, you will need your Firebase project configuration. You can find this in
|
package/docs/policies/_index.md
CHANGED
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
| request-validation-inbound | Request Validation | Validates incoming requests against your OpenAPI specification. Checks query parameters, path parameters, headers, and request body to ensure they match the defined schema before processing. | api-gateway |
|
|
84
84
|
| require-origin-inbound | Require Origin | Sets an allow-list for an origin header | api-gateway |
|
|
85
85
|
| require-user-claims-inbound | Require User Claims | Authorizes requests by validating claims on the authenticated user (`request.user`) against a configurable rule of `and`/`or` combinators and per-claim `eq`, `in`, and `startsWith` checks. Run it after any authentication policy that populates `request.user` — a JWT auth policy, API key auth, mTLS, and so on — to allow only specific callers (service accounts, OAuth clients, tenants, groups) without writing custom code. Every check fails closed: a missing or non-primitive claim never matches, comparisons are strict and type-sensitive, and requests without an authenticated user receive a 401 response. Denied requests receive a 403 response that does not echo claim values or expected values; the failing checks are written to the request log instead. Validation of the options runs lazily inside the policy constructor, which the runtime caches per policy name. Misconfigured options therefore fail on first use with a customer-facing `ConfigurationError` instead of failing at module load. | api-gateway |
|
|
86
|
-
| secret-masking-outbound | Secret Masking | Masks common secrets like Zuplo API keys, GitHub tokens, or SSH private key in the response body. | api-gateway |
|
|
86
|
+
| secret-masking-outbound | Secret Masking (deprecated) | Masks common secrets like Zuplo API keys, GitHub tokens, or SSH private key in the response body. | api-gateway |
|
|
87
87
|
| semantic-cache-inbound | Semantic Cache | Respond to matched incoming requests with semantically cached content The Semantic Cache Inbound policy caches responses based on semantic similarity of cache keys rather than exact matches. This allows for more flexible caching where similar requests can return cached responses even if the cache key is not exactly the same. The policy uses Large Language Model (LLM) embeddings to determine semantic similarity between cache keys based on a configurable similarity tolerance. Options: - semanticTolerance: The semantic similarity threshold for semantic cache matches (0-1, default: 0.2). Values closer to 0 require higher similarity. Can be overridden by custom functions. - expirationSecondsTtl: The timeout of the cache in seconds (default: 3600, 1 hour). Can be overridden by custom functions. - namespace: Optional namespace to isolate cache entries (default: "default"). Useful for multi-tenant scenarios or different cache contexts. - cacheBy: Determines how cache keys are generated: 'function' for custom logic or 'propertyPath' to extract from JSON body. | ai-gateway |
|
|
88
88
|
| set-body-inbound | Set Body | Sets the body of the request in the inbound pipeline - make sure to convert a GET/HEAD request to another method when using this policy. | api-gateway |
|
|
89
89
|
| set-headers-outbound | Set Headers | Adds or sets headers on the on the outgoing response. | api-gateway |
|
|
@@ -39,3 +39,56 @@ Apply this policy to outbound requests in your route configuration:
|
|
|
39
39
|
- Zuplo API keys (i.e. `zpka_xxx`)
|
|
40
40
|
- GitHub Tokens and Personal Access Tokens (i.e. `ghp_xxx`)
|
|
41
41
|
- Private key blocks (i.e. `BEGIN PRIVATE KEY` and `END PRIVATE KEY`)
|
|
42
|
+
|
|
43
|
+
## Migrating to Data Loss Prevention
|
|
44
|
+
|
|
45
|
+
The [Data Loss Prevention](/docs/policies/data-loss-prevention-outbound) policy
|
|
46
|
+
supersedes this one. Its `secret-zuplo`, `secret-github`, and
|
|
47
|
+
`secret-private-key` recognizers use the same patterns this policy does, so
|
|
48
|
+
selecting them reproduces the current behavior exactly:
|
|
49
|
+
|
|
50
|
+
```json
|
|
51
|
+
{
|
|
52
|
+
"policies": [
|
|
53
|
+
{
|
|
54
|
+
"name": "dlp-outbound",
|
|
55
|
+
"policyType": "data-loss-prevention-outbound",
|
|
56
|
+
"handler": {
|
|
57
|
+
"export": "DataLossPreventionOutboundPolicy",
|
|
58
|
+
"module": "$import(@zuplo/runtime)",
|
|
59
|
+
"options": {
|
|
60
|
+
"action": "mask",
|
|
61
|
+
"entities": ["secret-zuplo", "secret-github", "secret-private-key"],
|
|
62
|
+
"mask": "<SECRET MASKED>",
|
|
63
|
+
"customPatterns": [
|
|
64
|
+
{ "name": "key-value-pair", "pattern": "\\b(\\w+)=\\w+\\b" }
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Option mapping:
|
|
74
|
+
|
|
75
|
+
- `mask` becomes `mask`, which only applies when `action` is `mask`.
|
|
76
|
+
- `additionalPatterns` becomes `customPatterns`, where each entry takes a `name`
|
|
77
|
+
and a `pattern` plus optional `confidence` and `context` words.
|
|
78
|
+
|
|
79
|
+
Two behavior differences to be aware of when you migrate:
|
|
80
|
+
|
|
81
|
+
- Drop `entities` entirely to enable the whole built-in catalog — 60+
|
|
82
|
+
recognizers covering PII, payment and bank identifiers, national IDs, and API
|
|
83
|
+
keys for dozens of vendors — rather than only the three secret types this
|
|
84
|
+
policy handles.
|
|
85
|
+
- Data Loss Prevention only inspects text content types (JSON, XML,
|
|
86
|
+
form-encoded, `text/*`) and passes binary bodies through untouched, whereas
|
|
87
|
+
this policy reads every response body as text. Set `contentTypes` to override
|
|
88
|
+
the allow-list.
|
|
89
|
+
|
|
90
|
+
Use `action` to do more than mask: `block` replaces the response with a `422`
|
|
91
|
+
that lists only the detected entity names, and `log` records a warning and
|
|
92
|
+
returns the response unchanged. Pair it with
|
|
93
|
+
[Data Loss Prevention - Inbound](/docs/policies/data-loss-prevention-inbound) to
|
|
94
|
+
scan incoming requests as well.
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
> **Deprecated:** Use the
|
|
2
|
+
> [Data Loss Prevention](/docs/policies/data-loss-prevention-outbound) policy
|
|
3
|
+
> instead. It detects everything this policy does plus 60+ more entity types,
|
|
4
|
+
> and can block or log a response rather than only masking it. This policy will
|
|
5
|
+
> continue to work but will be removed in a future version of Zuplo. See
|
|
6
|
+
> [Migrating to Data Loss Prevention](#migrating-to-data-loss-prevention) below.
|
|
7
|
+
|
|
1
8
|
The Secret Masking policy searches for and masks common secrets and replaces
|
|
2
9
|
them with a placeholder. Secrets that are automatically masked include:
|
|
3
10
|
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"$id": "https://cdn.zuplo.com/policies/runtime/schemas/secret-masking-outbound.json",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"title": "Secret Masking",
|
|
6
|
-
"isDeprecated":
|
|
6
|
+
"isDeprecated": true,
|
|
7
7
|
"isPaidAddOn": false,
|
|
8
8
|
"isEnterprise": false,
|
|
9
9
|
"isInternal": false,
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"requiresAI": false,
|
|
13
13
|
"products": ["api-gateway"],
|
|
14
14
|
"description": "Masks common secrets like Zuplo API keys, GitHub tokens, or SSH private key in the response body.",
|
|
15
|
-
"deprecatedMessage": "",
|
|
15
|
+
"deprecatedMessage": "Use the [Data Loss Prevention](https://zuplo.com/docs/policies/data-loss-prevention-outbound) policy instead. It detects the same Zuplo API keys, GitHub tokens, and private key blocks via its `secret-zuplo`, `secret-github`, and `secret-private-key` recognizers, plus 60+ more built-in entities, and can block or log a response rather than only masking it. This policy will continue to work but will be removed in a future version of Zuplo.",
|
|
16
16
|
"required": ["handler"],
|
|
17
17
|
"properties": {
|
|
18
18
|
"handler": {
|
|
@@ -31,19 +31,20 @@
|
|
|
31
31
|
"options": {
|
|
32
32
|
"title": "SecretMaskingOutboundPolicyOptions",
|
|
33
33
|
"type": "object",
|
|
34
|
-
"description": "The options for the secret masking policy.",
|
|
34
|
+
"description": "The options for the secret masking policy. Deprecated - use the Data Loss Prevention outbound policy instead.",
|
|
35
35
|
"additionalProperties": false,
|
|
36
36
|
"required": [],
|
|
37
|
+
"deprecated": true,
|
|
37
38
|
"properties": {
|
|
38
39
|
"mask": {
|
|
39
40
|
"type": "string",
|
|
40
|
-
"description": "The string to replace detected secrets with.",
|
|
41
|
+
"description": "The string to replace detected secrets with. Equivalent to the Data Loss Prevention policy's `mask` option.",
|
|
41
42
|
"examples": ["[REDACTED]"],
|
|
42
43
|
"default": "[REDACTED]"
|
|
43
44
|
},
|
|
44
45
|
"additionalPatterns": {
|
|
45
46
|
"type": "array",
|
|
46
|
-
"description": "Extra regex patterns for secrets to mask.",
|
|
47
|
+
"description": "Extra regex patterns for secrets to mask. Replaced by the Data Loss Prevention policy's `customPatterns` option, which also accepts a name, confidence, and context words per pattern.",
|
|
47
48
|
"items": {
|
|
48
49
|
"type": "string"
|
|
49
50
|
}
|
|
@@ -64,6 +64,14 @@ deployed. This configuration defaults to `managed-edge`.
|
|
|
64
64
|
}
|
|
65
65
|
```
|
|
66
66
|
|
|
67
|
+
When the field is absent, [`zuplo link`](../cli/link.mdx) looks up the linked
|
|
68
|
+
project and writes the matching `projectType` into your `zuplo.jsonc`, so the
|
|
69
|
+
local runtime matches the deployed one. The CLI only adds the field — it never
|
|
70
|
+
changes a `projectType` you already set, and it leaves your comments and
|
|
71
|
+
formatting intact. If it can't confirm the type (for example, when it can't
|
|
72
|
+
reach the Zuplo API), it leaves the file alone and local development falls back
|
|
73
|
+
to `managed-edge`.
|
|
74
|
+
|
|
67
75
|
## `allowDuplicateRoutes`
|
|
68
76
|
|
|
69
77
|
Allow duplicate routes (same method and path) to be defined. This isn't
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zuplo",
|
|
3
|
-
"version": "6.73.
|
|
3
|
+
"version": "6.73.20",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The programmable API Gateway",
|
|
6
6
|
"author": "Zuplo, Inc.",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"zuplo": "zuplo.js"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@zuplo/cli": "6.73.
|
|
23
|
-
"@zuplo/core": "6.73.
|
|
24
|
-
"@zuplo/runtime": "6.73.
|
|
22
|
+
"@zuplo/cli": "6.73.20",
|
|
23
|
+
"@zuplo/core": "6.73.20",
|
|
24
|
+
"@zuplo/runtime": "6.73.20",
|
|
25
25
|
"@zuplo/test": "1.4.0"
|
|
26
26
|
}
|
|
27
27
|
}
|