zuplo 6.72.3 → 6.72.7
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/analytics/access-and-entitlements.md +27 -34
- package/docs/analytics/overview.md +7 -6
- package/docs/analytics/reference/url-parameters.md +2 -10
- package/docs/analytics/shared-controls.md +3 -10
- package/docs/analytics/tabs/agents.md +3 -3
- package/docs/analytics/tabs/requests.md +2 -4
- package/docs/articles/connect-to-aws-alb-with-mtls.mdx +89 -13
- package/docs/articles/graphql-security.mdx +2 -1
- package/docs/articles/graphql.mdx +8 -0
- package/docs/articles/opentelemetry.mdx +7 -5
- package/docs/articles/securing-backend-mtls.mdx +92 -3
- package/docs/articles/troubleshooting-slow-responses.mdx +4 -3
- package/docs/articles/troubleshooting.md +3 -1
- package/docs/policies/_index.md +2 -0
- package/docs/policies/clerk-jwt-auth-inbound/schema.json +3 -3
- package/docs/policies/mcp-auth0-oauth-inbound/schema.json +8 -5
- package/docs/policies/mcp-clerk-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-cognito-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-entra-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-google-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-keycloak-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-logto-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-oauth-inbound/schema.json +8 -5
- package/docs/policies/mcp-okta-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-onelogin-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-ping-oauth-inbound/schema.json +78 -0
- package/docs/policies/mcp-token-exchange-inbound/doc.md +72 -4
- package/docs/policies/mcp-token-exchange-inbound/intro.md +5 -4
- package/docs/policies/mcp-token-exchange-inbound/schema.json +277 -2
- package/docs/policies/mcp-workos-oauth-inbound/schema.json +78 -0
- package/docs/policies/open-id-jwt-auth-inbound/schema.json +3 -3
- package/docs/policies/propel-auth-jwt-inbound/schema.json +3 -3
- package/docs/policies/upstream-aws-federated-auth-inbound/doc.md +78 -0
- package/docs/policies/upstream-aws-federated-auth-inbound/intro.md +20 -0
- package/docs/policies/upstream-aws-federated-auth-inbound/schema.json +98 -0
- package/docs/policies/upstream-aws-service-auth-inbound/doc.md +89 -0
- package/docs/policies/upstream-aws-service-auth-inbound/intro.md +19 -0
- package/docs/policies/upstream-aws-service-auth-inbound/schema.json +113 -0
- package/docs/policies/upstream-azure-ad-service-auth-inbound/schema.json +4 -4
- package/docs/policies/upstream-gcp-federated-auth-inbound/doc.md +2 -2
- package/docs/policies/upstream-gcp-federated-auth-inbound/schema.json +4 -4
- package/docs/policies/upstream-gcp-service-auth-inbound/doc.md +3 -3
- package/docs/policies/upstream-gcp-service-auth-inbound/schema.json +3 -3
- package/docs/policies/upstream-zuplo-jwt-auth-inbound/schema.json +19 -0
- package/package.json +4 -4
|
@@ -7,56 +7,49 @@ sidebar_label: "Access & Entitlements"
|
|
|
7
7
|
|
|
8
8
|
- Confirm whether your account can see analytics.
|
|
9
9
|
- Find out how many days of history you have access to.
|
|
10
|
-
- Understand the trial banner
|
|
10
|
+
- Understand the trial banner.
|
|
11
11
|
|
|
12
|
-
##
|
|
12
|
+
## Availability
|
|
13
13
|
|
|
14
|
-
Analytics
|
|
15
|
-
|
|
14
|
+
Analytics is included on every plan. Your plan determines how much history you
|
|
15
|
+
can query — see [Data retention](#data-retention). If the Analytics page shows
|
|
16
|
+
an upsell view with a **Contact Sales** call-to-action instead of charts, your
|
|
17
|
+
account has analytics disabled — contact your Zuplo account team.
|
|
16
18
|
|
|
17
19
|
## Free trial
|
|
18
20
|
|
|
19
|
-
|
|
21
|
+
Every new account gets an automatic 14-day observability trial. During the
|
|
22
|
+
trial:
|
|
20
23
|
|
|
21
|
-
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
- You get longer history windows for analytics, logs, and traces than your plan
|
|
25
|
+
includes. Accounts on self-serve plans get the Builder/Business windows (7
|
|
26
|
+
days of analytics, 1 day of logs and traces); Enterprise trial accounts get
|
|
27
|
+
the Enterprise windows. See [Data retention](#data-retention).
|
|
28
|
+
- A banner appears across the top of the Observability tabs: "You're on a 14-day
|
|
29
|
+
trial of Zuplo Observability — {N} days left", with a **Contact sales** link.
|
|
26
30
|
|
|
27
|
-
|
|
28
|
-
continue to use the previous experience.
|
|
31
|
+
When the trial ends, your plan's own history windows apply.
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
The trial banner notes that the charts may look sparse if your account hasn't
|
|
33
|
-
yet generated much traffic. Use **View demo →** to see what a fully populated
|
|
34
|
-
dashboard looks like.
|
|
33
|
+
## Data retention
|
|
35
34
|
|
|
36
|
-
|
|
35
|
+
Each account has history windows for analytics, logs, and traces. The windows
|
|
36
|
+
depend on your plan:
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
| Plan | Analytics history | Log & trace history |
|
|
39
|
+
| ------------------ | ----------------- | ------------------- |
|
|
40
|
+
| Free | 1 day | Live (15 minutes) |
|
|
41
|
+
| Builder / Business | 7 days | 1 day |
|
|
42
|
+
| Enterprise | 30 days | 3 days |
|
|
39
43
|
|
|
40
|
-
|
|
41
|
-
controls:
|
|
44
|
+
The analytics window controls:
|
|
42
45
|
|
|
43
46
|
- How far back you can scroll using the time-range picker.
|
|
44
47
|
- Which presets in the picker are available. Presets longer than your window are
|
|
45
|
-
locked
|
|
48
|
+
locked and show an **Upgrade** badge; hover one for details.
|
|
46
49
|
- The maximum start and end values when you pick a custom range.
|
|
47
50
|
|
|
48
|
-
If you need a longer window, contact your Zuplo account team
|
|
49
|
-
|
|
50
|
-
## Demo mode
|
|
51
|
-
|
|
52
|
-
Append `?demo=true` to the Analytics URL, or click **View demo →** in the trial
|
|
53
|
-
banner, to switch into demo mode. In demo mode:
|
|
54
|
-
|
|
55
|
-
- Charts and tables are populated with synthetic sample data.
|
|
56
|
-
- A persistent banner reads: "You're viewing the Analytics demo with sample
|
|
57
|
-
data. Your real analytics aren't shown here."
|
|
58
|
-
|
|
59
|
-
Remove the `demo` parameter from the URL to return to your real data.
|
|
51
|
+
If you need a longer window, contact your Zuplo account team — custom retention
|
|
52
|
+
is available on Enterprise plans.
|
|
60
53
|
|
|
61
54
|
## Scope: account vs project
|
|
62
55
|
|
|
@@ -32,7 +32,7 @@ Analytics lives in the **Observability** tab of the Zuplo Portal, alongside
|
|
|
32
32
|
## What's in this section
|
|
33
33
|
|
|
34
34
|
- [Access and entitlements](./access-and-entitlements.md): plans, free trial,
|
|
35
|
-
|
|
35
|
+
retention.
|
|
36
36
|
- [Shared controls](./shared-controls.md): time range, filters, environment
|
|
37
37
|
selector, banners, URL state.
|
|
38
38
|
- Sections:
|
|
@@ -56,12 +56,13 @@ You'll see a subset of sections depending on your plan and project setup:
|
|
|
56
56
|
|
|
57
57
|
| Section | When it appears |
|
|
58
58
|
| --------- | ---------------------------------------------------------- |
|
|
59
|
-
| Requests | All accounts
|
|
59
|
+
| Requests | All accounts. |
|
|
60
60
|
| Origins | The project uses managed-edge origins. |
|
|
61
|
-
| Consumers | All accounts
|
|
62
|
-
| Agents | All accounts
|
|
61
|
+
| Consumers | All accounts. |
|
|
62
|
+
| Agents | All accounts. |
|
|
63
63
|
| MCP | The project type is **standard** and the project uses MCP. |
|
|
64
64
|
| GraphQL | The project proxies a GraphQL API. |
|
|
65
65
|
|
|
66
|
-
If you don't see Analytics at all, your
|
|
67
|
-
|
|
66
|
+
Analytics is included on every plan. If you don't see Analytics at all, your
|
|
67
|
+
account may have it disabled — see
|
|
68
|
+
[Access and entitlements](./access-and-entitlements.md).
|
|
@@ -8,7 +8,7 @@ view.
|
|
|
8
8
|
|
|
9
9
|
## When to use this
|
|
10
10
|
|
|
11
|
-
- Build a permalink to a specific time window
|
|
11
|
+
- Build a permalink to a specific time window or filter set.
|
|
12
12
|
- Embed an Analytics link in a runbook, postmortem, or dashboard.
|
|
13
13
|
- Understand what each query parameter does.
|
|
14
14
|
|
|
@@ -16,11 +16,9 @@ view.
|
|
|
16
16
|
|
|
17
17
|
| Parameter | Example | Effect |
|
|
18
18
|
| -------------- | ------------------------------------------------------ | ----------------------------------------------------------------------------------------- |
|
|
19
|
-
| `time` | `?time=7d` | Apply a preset. Values: `1h`, `6h`, `24h`, `3d`, `7d`, `14d`, `28d`, `60d`, `90d`.
|
|
19
|
+
| `time` | `?time=7d` | Apply a preset. Values: `1h`, `6h`, `24h`, `3d`, `7d`, `14d`, `28d`, `30d`, `60d`, `90d`. |
|
|
20
20
|
| `start`, `end` | `?start=2026-05-01T00:00:00Z&end=2026-05-15T00:00:00Z` | Custom range as ISO-8601 datetimes. Overrides `time` when both are present. |
|
|
21
21
|
| `filter` | `?filter=httpStatus:class:5xx` | Add a filter as `<field>:<matchmode>:<value>`. Repeat the parameter for multiple filters. |
|
|
22
|
-
| `demo` | `?demo=true` | Demo mode (sample data instead of your real analytics). |
|
|
23
|
-
| `preview` | `?preview=1` | Legacy preview mode. |
|
|
24
22
|
|
|
25
23
|
## Match modes for `filter`
|
|
26
24
|
|
|
@@ -48,12 +46,6 @@ Custom range with two filters:
|
|
|
48
46
|
?start=2026-05-01T00:00:00Z&end=2026-05-08T00:00:00Z&filter=country:equals:US&filter=httpMethod:equals:POST
|
|
49
47
|
```
|
|
50
48
|
|
|
51
|
-
Open the demo:
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
?demo=true
|
|
55
|
-
```
|
|
56
|
-
|
|
57
49
|
## Sharing
|
|
58
50
|
|
|
59
51
|
The recipient sees the same view, provided they have access to the project or
|
|
@@ -18,7 +18,7 @@ State persists to the URL so you can share or bookmark any view.
|
|
|
18
18
|
The time range picker controls every chart, table, and KPI in the active
|
|
19
19
|
section.
|
|
20
20
|
|
|
21
|
-
**Presets.** Last 1h, 6h, 24h, 3d, 7d, 14d, 28d, 60d, 90d.
|
|
21
|
+
**Presets.** Last 1h, 6h, 24h, 3d, 7d, 14d, 28d, 30d, 60d, 90d.
|
|
22
22
|
|
|
23
23
|
**Custom range.** Use the datetime-local inputs for **Start** and **End**. Both
|
|
24
24
|
fields are clamped to your account's retention window.
|
|
@@ -80,8 +80,6 @@ There's no separate share button.
|
|
|
80
80
|
| `time` | `?time=7d` | Apply a preset. |
|
|
81
81
|
| `start`, `end` | `?start=2026-05-01T00:00:00Z&end=2026-05-15T00:00:00Z` | Custom range. Overrides `time`. |
|
|
82
82
|
| `filter` | `?filter=httpStatus:class:5xx` | Add a filter. Repeat the parameter for multiple values. |
|
|
83
|
-
| `demo` | `?demo=true` | Demo mode (sample data). |
|
|
84
|
-
| `preview` | `?preview=1` | Legacy preview mode. |
|
|
85
83
|
|
|
86
84
|
See [URL parameters](./reference/url-parameters.md) for the full reference.
|
|
87
85
|
|
|
@@ -94,13 +92,8 @@ a refetch.
|
|
|
94
92
|
|
|
95
93
|
## Banners
|
|
96
94
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
1. **Preview banner**: when `preview=1` is set. Indicates legacy preview mode.
|
|
100
|
-
2. **Demo banner**: when `demo=true` is set. Reminds you sample data is shown
|
|
101
|
-
instead of your real analytics.
|
|
102
|
-
3. **Trial banner**: for new accounts with analytics. Shows days remaining and
|
|
103
|
-
offers **View demo →** and **Contact Sales**.
|
|
95
|
+
During the 14-day observability trial, a banner appears at the top of the page
|
|
96
|
+
showing the days remaining, with a **Contact sales** link.
|
|
104
97
|
|
|
105
98
|
## Loading and empty states
|
|
106
99
|
|
|
@@ -74,9 +74,9 @@ The filter bar applies. `originHost` is not applicable here. See
|
|
|
74
74
|
## Troubleshooting
|
|
75
75
|
|
|
76
76
|
**The Agents section is empty.** Either no classified agents called your gateway
|
|
77
|
-
in the window, or your
|
|
78
|
-
|
|
79
|
-
|
|
77
|
+
in the window, or your
|
|
78
|
+
[retention window](../access-and-entitlements.md#data-retention) doesn't yet
|
|
79
|
+
include any agent traffic.
|
|
80
80
|
|
|
81
81
|
**I see a known agent in my logs but not here.** The classifier is conservative;
|
|
82
82
|
it labels traffic that clearly matches a known agent fingerprint. Generic SDK
|
|
@@ -91,7 +91,5 @@ not include any geolocated requests.
|
|
|
91
91
|
that breakdown. Top-10 plus 50 covers up to 60 distinct values; beyond that,
|
|
92
92
|
narrow the time range or add a filter.
|
|
93
93
|
|
|
94
|
-
**My charts look sparse.**
|
|
95
|
-
|
|
96
|
-
populated dashboard looks like. See
|
|
97
|
-
[Access and entitlements](../access-and-entitlements.md).
|
|
94
|
+
**My charts look sparse.** New accounts may not have generated much traffic yet.
|
|
95
|
+
Charts fill in as requests flow through your gateway.
|
|
@@ -20,9 +20,9 @@ present an X.509 certificate that chains to a Certificate Authority (CA) in the
|
|
|
20
20
|
ALB's trust store. Zuplo presents that client certificate on each outbound
|
|
21
21
|
request, and the ALB rejects anything that can't.
|
|
22
22
|
|
|
23
|
-
This guide covers
|
|
24
|
-
|
|
25
|
-
|
|
23
|
+
This guide covers uploading a client certificate to Zuplo and presenting it on
|
|
24
|
+
requests to the ALB. It does **not** cover configuring the ALB itself — for
|
|
25
|
+
that, follow the AWS documentation linked in
|
|
26
26
|
[Configure the ALB](#1-configure-the-alb).
|
|
27
27
|
|
|
28
28
|
## How it works
|
|
@@ -64,10 +64,13 @@ For background on the gateway-to-origin direction in general, see
|
|
|
64
64
|
|
|
65
65
|
Before you begin, you need:
|
|
66
66
|
|
|
67
|
-
- A client certificate
|
|
68
|
-
|
|
67
|
+
- A PEM-encoded client certificate (`client-cert.pem`), matching private key
|
|
68
|
+
(`client-key.pem`), and public CA certificate or bundle (`client-ca.pem`). The
|
|
69
|
+
same CA must be in the ALB's trust store.
|
|
69
70
|
- An AWS Application Load Balancer with an HTTPS listener you can configure for
|
|
70
71
|
mTLS.
|
|
72
|
+
- The AWS CLI installed and authenticated with permission to inspect the ALB's
|
|
73
|
+
listener and trust store.
|
|
71
74
|
- The [Zuplo CLI](../cli/overview.mdx) installed and authenticated.
|
|
72
75
|
|
|
73
76
|
## 1/ Configure the ALB
|
|
@@ -93,7 +96,79 @@ edge.
|
|
|
93
96
|
|
|
94
97
|
:::
|
|
95
98
|
|
|
96
|
-
## 2/
|
|
99
|
+
## 2/ Validate the certificate and ALB trust
|
|
100
|
+
|
|
101
|
+
Confirm that the listener uses verify mode and capture its trust store ARN:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
aws elbv2 describe-listeners \
|
|
105
|
+
--listener-arns <HTTPS_LISTENER_ARN> \
|
|
106
|
+
--query 'Listeners[0].MutualAuthentication' \
|
|
107
|
+
--output json
|
|
108
|
+
|
|
109
|
+
TRUST_STORE_ARN=$(aws elbv2 describe-listeners \
|
|
110
|
+
--listener-arns <HTTPS_LISTENER_ARN> \
|
|
111
|
+
--query 'Listeners[0].MutualAuthentication.TrustStoreArn' \
|
|
112
|
+
--output text)
|
|
113
|
+
|
|
114
|
+
aws elbv2 describe-trust-stores \
|
|
115
|
+
--trust-store-arns "$TRUST_STORE_ARN" \
|
|
116
|
+
--query 'TrustStores[0].{Name:Name,Status:Status,CACertificates:NumberOfCaCertificates}' \
|
|
117
|
+
--output table
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
The listener mode should be `verify`, and the trust store status should be
|
|
121
|
+
`ACTIVE`.
|
|
122
|
+
|
|
123
|
+
Inspect the client certificate and verify its path against the CA certificate:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
openssl x509 \
|
|
127
|
+
-in client-cert.pem \
|
|
128
|
+
-noout \
|
|
129
|
+
-subject \
|
|
130
|
+
-issuer \
|
|
131
|
+
-dates \
|
|
132
|
+
-purpose
|
|
133
|
+
|
|
134
|
+
openssl verify \
|
|
135
|
+
-verbose \
|
|
136
|
+
-purpose sslclient \
|
|
137
|
+
-x509_strict \
|
|
138
|
+
-show_chain \
|
|
139
|
+
-CAfile client-ca.pem \
|
|
140
|
+
client-cert.pem
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
`SSL client` should report `Yes`, and verification should return
|
|
144
|
+
`client-cert.pem: OK`. Also confirm that the certificate and private key match:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
CERT_KEY_HASH=$(openssl x509 -in client-cert.pem -noout -pubkey | openssl sha256)
|
|
148
|
+
PRIVATE_KEY_HASH=$(openssl pkey -in client-key.pem -pubout | openssl sha256)
|
|
149
|
+
|
|
150
|
+
test "$CERT_KEY_HASH" = "$PRIVATE_KEY_HASH" &&
|
|
151
|
+
echo "Certificate and private key match" ||
|
|
152
|
+
echo "ERROR: Certificate and private key do not match"
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
For the strongest offline check, run `openssl verify` with the exact CA bundle
|
|
156
|
+
uploaded to the ALB trust store instead of `client-ca.pem`.
|
|
157
|
+
|
|
158
|
+
If the ALB is reachable, test the TLS handshake directly:
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
curl --verbose \
|
|
162
|
+
--cert client-cert.pem \
|
|
163
|
+
--key client-key.pem \
|
|
164
|
+
"https://<ALB_HOSTNAME>/<TEST_PATH>"
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Use a hostname covered by the ALB's server certificate. Any HTTP response,
|
|
168
|
+
including a `401`, `403`, or `404`, shows that the TLS handshake completed; a
|
|
169
|
+
client certificate failure occurs before an HTTP response is produced.
|
|
170
|
+
|
|
171
|
+
## 3/ Upload your client certificate to Zuplo
|
|
97
172
|
|
|
98
173
|
Use the Zuplo CLI to upload the client certificate and private key to your
|
|
99
174
|
project. The CA that issued this certificate must already be in the ALB's trust
|
|
@@ -119,7 +194,7 @@ when you create the certificate.
|
|
|
119
194
|
|
|
120
195
|
:::
|
|
121
196
|
|
|
122
|
-
##
|
|
197
|
+
## 4/ Present the certificate on requests to the ALB
|
|
123
198
|
|
|
124
199
|
Reference the uploaded certificate by name when the gateway forwards requests to
|
|
125
200
|
the ALB. Use the ALB's DNS name (or a custom domain pointed at it) as the
|
|
@@ -162,7 +237,7 @@ export default async function (request: ZuploRequest, context: ZuploContext) {
|
|
|
162
237
|
}
|
|
163
238
|
```
|
|
164
239
|
|
|
165
|
-
##
|
|
240
|
+
## 5/ Use environment variables across environments
|
|
166
241
|
|
|
167
242
|
To use a different certificate per environment, store the certificate name in an
|
|
168
243
|
[environment variable](./environment-variables.mdx) and reference it with the
|
|
@@ -226,11 +301,12 @@ received — usually a TLS handshake problem. Confirm that:
|
|
|
226
301
|
|
|
227
302
|
### The ALB rejects the certificate
|
|
228
303
|
|
|
229
|
-
If the handshake
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
304
|
+
If the TLS handshake fails, re-check the ALB trust store and confirm the
|
|
305
|
+
listener is in **verify** mode, not passthrough. If your client certificate is
|
|
306
|
+
issued by an intermediate CA, make sure the trust store contains the CA chain
|
|
307
|
+
required to validate the certificate. ALB connection logs can identify errors
|
|
308
|
+
such as `ClientCertUntrusted`, `ClientCertPurposeInvalid`, `ClientCertExpired`,
|
|
309
|
+
or `ClientCertNotYetValid`.
|
|
234
310
|
|
|
235
311
|
### No certificate appears to be sent
|
|
236
312
|
|
|
@@ -180,7 +180,8 @@ outbound filter policy goes in the `outbound` array:
|
|
|
180
180
|
## Example repository
|
|
181
181
|
|
|
182
182
|
For a complete, runnable setup, see the
|
|
183
|
-
[GraphQL API with Zuplo example repository](https://github.com/zuplo/
|
|
183
|
+
[GraphQL API with Zuplo example repository](https://github.com/zuplo-samples/graphql).
|
|
184
|
+
You can [deploy it to your own account in one click](./graphql.mdx).
|
|
184
185
|
|
|
185
186
|
## Next steps
|
|
186
187
|
|
|
@@ -12,6 +12,14 @@ Zuplo has rich support for GraphQL. Pass your requests through the gateway,
|
|
|
12
12
|
attach policies, track operations with analytics, and publish documentation for
|
|
13
13
|
your schema in the Dev Portal. This guide walks you through setting it up.
|
|
14
14
|
|
|
15
|
+
<ZupIt repoUrl="https://github.com/zuplo-samples/graphql">
|
|
16
|
+
|
|
17
|
+
Want to see it working first? This example proxies a public GraphQL API with
|
|
18
|
+
edge caching, query depth limiting, and analytics already wired up — deploy it
|
|
19
|
+
to your own Zuplo account in one click.
|
|
20
|
+
|
|
21
|
+
</ZupIt>
|
|
22
|
+
|
|
15
23
|
:::tip{title="TL;DR"}
|
|
16
24
|
|
|
17
25
|
- [ ] Proxy your GraphQL endpoint through a POST `/graphql` route with the URL
|
|
@@ -7,10 +7,9 @@ Zuplo ships with an OpenTelemetry plugin (`@zuplo/otel`) that instruments your
|
|
|
7
7
|
API and exports traces and logs in OpenTelemetry format. The quickest way to use
|
|
8
8
|
it is Zuplo's built-in tracing: add the plugin and your traces are stored by
|
|
9
9
|
Zuplo and shown in the portal's **Observability** tab, with no collector to run
|
|
10
|
-
or backend to host.
|
|
11
|
-
both at
|
|
12
|
-
|
|
13
|
-
<EnterpriseFeature name="OpenTelemetry" />
|
|
10
|
+
or backend to host. Built-in tracing is available on every plan. You can also
|
|
11
|
+
export to your own OpenTelemetry backend (an Enterprise feature), or to both at
|
|
12
|
+
once.
|
|
14
13
|
|
|
15
14
|
## Tracing
|
|
16
15
|
|
|
@@ -68,7 +67,8 @@ Deploy your project and open the **Observability** tab to see traces.
|
|
|
68
67
|
Each trace is tagged with the account, project, deployment, and environment it
|
|
69
68
|
ran in, plus the request ID (the `zp-rid` value) that also appears on your
|
|
70
69
|
[logs](#logging), so you can move between a request's logs and its trace. How
|
|
71
|
-
long traces are kept depends on your plan
|
|
70
|
+
long traces are kept depends on your plan — see
|
|
71
|
+
[data retention](../analytics/access-and-entitlements.md#data-retention).
|
|
72
72
|
|
|
73
73
|
:::note
|
|
74
74
|
|
|
@@ -81,6 +81,8 @@ still run.
|
|
|
81
81
|
|
|
82
82
|
### Export to Your Own Backend
|
|
83
83
|
|
|
84
|
+
<EnterpriseFeature name="Exporting to your own OpenTelemetry backend" />
|
|
85
|
+
|
|
84
86
|
To send traces to an OpenTelemetry service such as
|
|
85
87
|
[Honeycomb](https://honeycomb.io), [Middleware](https://middleware.io/),
|
|
86
88
|
[Dynatrace](https://dynatrace.com), [Jaeger](https://www.jaegertracing.io/), or
|
|
@@ -30,11 +30,38 @@ gateways, and Zuplo can verify it's connecting to the correct backend service.
|
|
|
30
30
|
|
|
31
31
|
Before you begin, you need:
|
|
32
32
|
|
|
33
|
-
- A client certificate and private key generated from a
|
|
34
|
-
(CA) that your backend trusts
|
|
33
|
+
- A PEM-encoded client certificate and matching private key generated from a
|
|
34
|
+
Certificate Authority (CA) that your backend trusts
|
|
35
35
|
- Your backend service configured to require and validate client certificates
|
|
36
36
|
- The Zuplo CLI installed (see [CLI documentation](../cli/overview.mdx))
|
|
37
37
|
|
|
38
|
+
## Client certificate requirements
|
|
39
|
+
|
|
40
|
+
The certificate uploaded to Zuplo is the client, or leaf, certificate that the
|
|
41
|
+
gateway presents to your backend. It should have the following properties:
|
|
42
|
+
|
|
43
|
+
- X.509 version 3
|
|
44
|
+
- `Basic Constraints: critical, CA:FALSE`
|
|
45
|
+
- `Key Usage: critical, Digital Signature`
|
|
46
|
+
- `Extended Key Usage: TLS Web Client Authentication` (`clientAuth`)
|
|
47
|
+
- An RSA key between 2048 and 8192 bits, or an ECDSA key using P-256, P-384, or
|
|
48
|
+
P-521
|
|
49
|
+
- A SHA-256 or stronger signature
|
|
50
|
+
- A subject that uniquely identifies the gateway credential
|
|
51
|
+
- A validity period appropriate for your certificate rotation policy
|
|
52
|
+
|
|
53
|
+
The issuing CA certificate must be X.509 version 3 with
|
|
54
|
+
`Basic Constraints: critical, CA:TRUE` and a key usage that includes
|
|
55
|
+
`Certificate Sign` and `CRL Sign`. Your backend's trust store must contain the
|
|
56
|
+
CA certificates needed to build a path from the client certificate to a trusted
|
|
57
|
+
root. When the trusted CA directly signs the client certificate, you do not need
|
|
58
|
+
a client certificate-chain bundle. If an intermediate CA signs it, follow your
|
|
59
|
+
backend's requirements for presenting and trusting the intermediate chain.
|
|
60
|
+
|
|
61
|
+
The private key must match the public key in the client certificate. Keep it
|
|
62
|
+
secret and limit access to it. The key must be unencrypted when uploaded to
|
|
63
|
+
Zuplo so the gateway can use it without a passphrase.
|
|
64
|
+
|
|
38
65
|
## 1/ Upload Your Certificate
|
|
39
66
|
|
|
40
67
|
Use the Zuplo CLI to upload your client certificate and private key to your
|
|
@@ -229,10 +256,72 @@ For local development, consider:
|
|
|
229
256
|
|
|
230
257
|
### Certificate Validation Errors
|
|
231
258
|
|
|
232
|
-
|
|
259
|
+
Inspect the certificate and confirm its subject, issuer, validity, and client
|
|
260
|
+
authentication purpose:
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
openssl x509 \
|
|
264
|
+
-in client.crt \
|
|
265
|
+
-noout \
|
|
266
|
+
-subject \
|
|
267
|
+
-issuer \
|
|
268
|
+
-serial \
|
|
269
|
+
-dates \
|
|
270
|
+
-purpose
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
`SSL client` should report `Yes`. To inspect all extensions, run
|
|
274
|
+
`openssl x509 -in client.crt -noout -text` and confirm the certificate reports
|
|
275
|
+
`CA:FALSE`, `Digital Signature`, and `TLS Web Client Authentication`.
|
|
276
|
+
|
|
277
|
+
Check that the certificate will remain valid for at least seven days:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
openssl x509 -in client.crt -noout -checkend 604800
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Validate the certificate path against the same CA bundle your backend trusts:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
openssl verify \
|
|
287
|
+
-verbose \
|
|
288
|
+
-purpose sslclient \
|
|
289
|
+
-x509_strict \
|
|
290
|
+
-show_chain \
|
|
291
|
+
-CAfile backend-client-ca-bundle.pem \
|
|
292
|
+
client.crt
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The expected result is `client.crt: OK`. Common errors include:
|
|
296
|
+
|
|
297
|
+
- `unable to get local issuer certificate`: The issuing CA or an intermediate CA
|
|
298
|
+
is missing from the backend's trust bundle.
|
|
299
|
+
- `unsupported certificate purpose`: The client certificate is missing the
|
|
300
|
+
`clientAuth` extended key usage.
|
|
301
|
+
- `certificate has expired`: The client certificate is outside its validity
|
|
302
|
+
period.
|
|
303
|
+
- `invalid CA certificate`: An issuing certificate is missing valid CA
|
|
304
|
+
extensions.
|
|
305
|
+
- `key usage does not include certificate signing`: An issuing CA does not have
|
|
306
|
+
the `keyCertSign` key usage.
|
|
307
|
+
|
|
308
|
+
Confirm that the certificate and private key contain the same public key:
|
|
309
|
+
|
|
310
|
+
```bash
|
|
311
|
+
CERT_KEY_HASH=$(openssl x509 -in client.crt -noout -pubkey | openssl sha256)
|
|
312
|
+
PRIVATE_KEY_HASH=$(openssl pkey -in client.key -pubout | openssl sha256)
|
|
313
|
+
|
|
314
|
+
test "$CERT_KEY_HASH" = "$PRIVATE_KEY_HASH" &&
|
|
315
|
+
echo "Certificate and private key match" ||
|
|
316
|
+
echo "ERROR: Certificate and private key do not match"
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
If your backend still rejects the certificate, verify:
|
|
233
320
|
|
|
234
321
|
- The certificate is signed by a CA that your backend trusts
|
|
235
322
|
- The certificate hasn't expired
|
|
323
|
+
- The certificate has the required key usage and extended key usage
|
|
324
|
+
- The certificate and private key match
|
|
236
325
|
- The certificate name in your code matches the uploaded certificate name
|
|
237
326
|
|
|
238
327
|
### Connection Failures
|
|
@@ -240,9 +240,10 @@ For the most detailed view of where time is spent in your request pipeline,
|
|
|
240
240
|
enable [OpenTelemetry tracing](./opentelemetry.mdx). The OpenTelemetry plugin
|
|
241
241
|
automatically instruments your API and provides span-level timing for each stage
|
|
242
242
|
of the request lifecycle — including inbound policies, the handler, outbound
|
|
243
|
-
policies, and any subrequests made via `fetch` in custom code.
|
|
244
|
-
|
|
245
|
-
|
|
243
|
+
policies, and any subrequests made via `fetch` in custom code. Built-in tracing
|
|
244
|
+
is available on every plan; see
|
|
245
|
+
[data retention](../analytics/access-and-entitlements.md#data-retention) for how
|
|
246
|
+
much trace history you can query.
|
|
246
247
|
|
|
247
248
|
With tracing enabled, you can see exactly how long each policy and handler takes
|
|
248
249
|
to execute, making it straightforward to identify which component is adding
|
|
@@ -179,7 +179,9 @@ const response = await fetch("https://api.example.com/data", {
|
|
|
179
179
|
The Zuplo Portal provides real-time log viewing for deployed environments. Open
|
|
180
180
|
the **Observability** tab in your project — the **Logs** view opens by default —
|
|
181
181
|
then use the **Environment** filter to select the deployed environment and see
|
|
182
|
-
live request logs and any messages logged with `context.log`.
|
|
182
|
+
live request logs and any messages logged with `context.log`. How far back you
|
|
183
|
+
can search depends on your plan — see
|
|
184
|
+
[Access and entitlements](../analytics/access-and-entitlements.md#data-retention).
|
|
183
185
|
|
|
184
186
|
### Using context.log
|
|
185
187
|
|
package/docs/policies/_index.md
CHANGED
|
@@ -104,6 +104,8 @@
|
|
|
104
104
|
| traffic-splitting-inbound | Traffic Splitting | Splits traffic randomly across a set of weighted base paths. On each request one base path is selected (weighted by `weight`) and written to the request custom context at `customOutputProperty`. Reference it from a later URL Rewrite `rewritePattern` or URL Forward `baseUrl`, e.g. `${context.custom.trafficSplitting.basePath}`. | api-gateway |
|
|
105
105
|
| transform-body-inbound | Transform Request Body | Transform the body of an incoming request. | api-gateway |
|
|
106
106
|
| transform-body-outbound | Transform Response Body | Transform the body of an outgoing response. | api-gateway |
|
|
107
|
+
| upstream-aws-federated-auth-inbound | Upstream AWS Federated Auth | Resolves AWS credentials with STS AssumeRoleWithWebIdentity using Zuplo's ambient OIDC identity — no AWS keys are stored anywhere. The role's trust policy must trust the Zuplo OIDC identity provider. Resolved credentials are registered on the request context for the AWS Lambda handler and custom code to sign upstream requests with `AwsClient.fromContext`. This policy does not itself sign or forward the request. | api-gateway |
|
|
108
|
+
| upstream-aws-service-auth-inbound | Upstream AWS Service Auth | Resolves AWS credentials from static access keys (optionally exchanged for an IAM role's temporary credentials via STS AssumeRole) and registers them on the request context. The AWS Lambda handler and custom code read them with `AwsClient.fromContext` to sign upstream requests. This policy does not itself sign or forward the request. | api-gateway |
|
|
107
109
|
| upstream-azure-ad-service-auth-inbound | Upstream Azure AD Service Auth | Uses Azure Active Directory to add an Authorization header to the request in order to authenticate requests using Azure identity. | api-gateway |
|
|
108
110
|
| upstream-firebase-admin-auth-inbound | Upstream Firebase Admin Auth | Creates a Firebase Admin token and attaches it to the outgoing request. Useful when calling Firebase services as an administrator. | api-gateway |
|
|
109
111
|
| upstream-firebase-user-auth-inbound | Upstream Firebase User Auth | Creates a Firebase custom user token and attaches it to the outgoing request. Useful when calling Firebase services as user. | api-gateway |
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
},
|
|
43
43
|
"frontendApiUrl": {
|
|
44
44
|
"type": "string",
|
|
45
|
-
"examples": ["https://
|
|
46
|
-
"description": "Your Clerk
|
|
45
|
+
"examples": ["https://verb-noun-00.clerk.accounts.dev"],
|
|
46
|
+
"description": "Your Clerk Frontend API URL, i.e. `https://verb-noun-00.clerk.accounts.dev`. Can be found in the Clerk portal: https://dashboard.clerk.com/last-active?path=api-keys."
|
|
47
47
|
},
|
|
48
48
|
"oAuthResourceMetadataEnabled": {
|
|
49
49
|
"type": "boolean",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"module": "$import(@zuplo/runtime)",
|
|
60
60
|
"options": {
|
|
61
61
|
"allowUnauthenticatedRequests": false,
|
|
62
|
-
"frontendApiUrl": "https://
|
|
62
|
+
"frontendApiUrl": "https://verb-noun-00.clerk.accounts.dev",
|
|
63
63
|
"oAuthResourceMetadataEnabled": false
|
|
64
64
|
}
|
|
65
65
|
}
|
|
@@ -100,7 +100,7 @@
|
|
|
100
100
|
{
|
|
101
101
|
"type": "object",
|
|
102
102
|
"additionalProperties": false,
|
|
103
|
-
"required": ["enabled"
|
|
103
|
+
"required": ["enabled"],
|
|
104
104
|
"properties": {
|
|
105
105
|
"enabled": {
|
|
106
106
|
"const": true,
|
|
@@ -109,21 +109,24 @@
|
|
|
109
109
|
"trustedIssuers": {
|
|
110
110
|
"type": "array",
|
|
111
111
|
"minItems": 1,
|
|
112
|
-
"description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata.",
|
|
112
|
+
"description": "Trusted ID-JAG issuers. These values are never published in OAuth metadata. Omit to trust this policy's browser-login IdP.",
|
|
113
113
|
"items": {
|
|
114
114
|
"type": "object",
|
|
115
115
|
"additionalProperties": false,
|
|
116
|
-
"
|
|
116
|
+
"dependentRequired": {
|
|
117
|
+
"issuer": ["jwksUrl"],
|
|
118
|
+
"jwksUrl": ["issuer"]
|
|
119
|
+
},
|
|
117
120
|
"properties": {
|
|
118
121
|
"issuer": {
|
|
119
122
|
"type": "string",
|
|
120
123
|
"format": "uri",
|
|
121
|
-
"description": "Exact issuer URL expected in the ID-JAG iss claim."
|
|
124
|
+
"description": "Exact issuer URL expected in the ID-JAG iss claim. Provide together with jwksUrl, or omit both to default to this policy's browser-login IdP."
|
|
122
125
|
},
|
|
123
126
|
"jwksUrl": {
|
|
124
127
|
"type": "string",
|
|
125
128
|
"format": "uri",
|
|
126
|
-
"description": "JWKS URL used to verify ID-JAG signatures from this issuer."
|
|
129
|
+
"description": "JWKS URL used to verify ID-JAG signatures from this issuer. Provide together with issuer, or omit both to default to this policy's browser-login IdP."
|
|
127
130
|
},
|
|
128
131
|
"expectedClientIds": {
|
|
129
132
|
"type": "array",
|