Skip to content

Keeping request telemetry minimal

Goal: your data protection review asks for request telemetry that keeps only what you need to operate the service. You want Insights to keep working (status, latency, cache decisions, operations), without full client addresses, credentials or health-check noise.

Everything here is per service in gpilot.toml, and none of it changes how requests are served, cached or billed. Only what is stored changes.

The running example is shop-api, called by browsers in the EU and probed every few seconds by a Kubernetes liveness check.

  • A deployed service and its gpilot.toml.
gpilot.toml
[telemetry]
# Keep the network part of the address: 203.0.113.77 is stored as 203.0.113.0.
client_ip = "truncated"
# Store segment values as keyed pseudonyms (the default, stated so a review can see it).
vary_values = "pseudonymized"
# Leave the cluster's health probes out of Insights.
record = "!starts_with(header:user-agent, 'kube-probe/')"
# Which request headers are recorded. Replacing the list replaces the defaults,
# so the two credential rules come first.
[[telemetry.headers.request]]
name = "authorization"
action = "sanitize"
[[telemetry.headers.request]]
name = "cookie"
action = "sanitize"
[[telemetry.headers.request]]
name = "content-type"
action = "include"
[[telemetry.headers.request]]
name = "accept"
action = "include"
KeyStored
client_ip = "truncated"The address with its last IPv4 octet zeroed, or an IPv6 address cut to 48 bits. Country, region, city and the network data are kept; latitude, longitude and postal code are not. "none" stores no address and no region or city.
vary_values = "pseudonymized"Each vary rule’s value as hmac-sha256: and 16 hex digits, under a key of the service. Requests of one segment still group together.
recordOnly the requests the expression matches. A probe is still served and counted, just not recorded.
[[telemetry.headers.request]]authorization and cookie as keyed digests (the Bearer scheme and cookie names stay readable), content-type and accept as sent. Every other request header is not recorded. Compared with the default list, referer is left out.

Header rules cannot bring back the address client_ip leaves out. Unless client_ip = "full", no rule records gp-client-ip or a forwarding header that carries the client’s address or URL (forwarded, x-forwarded-*, x-real-ip, true-client-ip and the like), not even a catch-all rule. gp-shield-hop, which carries the address between edge locations, is never recorded.

The other three header lists (origin_request, response, client_response) keep their defaults, which already sanitize authorization, cookie, gp-signature and set-cookie. See [telemetry.headers].

Deploy with gpilot deploy, then send one request with a credential and one as the probe:

Terminal window
curl -sS -o /dev/null "https://$GRAPHPILOT_HOST/graphql" \
-H 'content-type: application/json' \
-H "authorization: Bearer $TOKEN" \
-H 'GP-Correlation-ID: privacy-check' \
-d '{"query":"query ProductPage { product(id: \"p01\") { id name } }"}'
curl -sS -o /dev/null "https://$GRAPHPILOT_HOST/graphql" -A 'kube-probe/1.31' \
-H 'content-type: application/json' -d '{"query":"{ __typename }"}'

Open the first request in Insights:

  • Client tab: the IP ends in .0 (shown in IPv6 notation, such as ::ffff:203.0.113.0), the country and city are there, and nothing finer.
  • Overview tab, Headers from the client: authorization reads Bearer hmac-sha256:… with a shield icon, and user-agent and referer are not listed at all.
  • Cache tab: each segment value is marked pseudonymized.

The probe request is not in the list, and the notice below the tabs names the record expression. Only my requests matches nothing on this service, because your full address is never stored; filter by the truncated address instead.

  • It applies from the next deployment. Requests recorded before keep what was stored then, until your plan’s retention deletes them. To remove them sooner, an Admin can reset the history.
  • A probe without a User-Agent is still recorded. The expression has no answer for a request that sent none, and record keeps undecided requests. To leave those out too, write header:user-agent && !starts_with(header:user-agent, 'kube-probe/').
  • vary_values = "clear" undoes the pseudonyms for every rule. It is service-wide, and the header sanitize rules do not cover segment values.
  • Your origin is a separate question. origin.forward_client_ip decides whether your origin receives the full address, independently of what telemetry stores.
  • Alerts and billing are unaffected. They count every request, recorded or not.

For what is recorded, where it is stored and how long, and what your origin receives, see privacy and personal data.