Repository navigation
Add opt-in SSRF guard for interceptor URLs - #2159
avneetbansal-aws wants to merge 1 commit into
Conversation
Execute() built an outbound request from an operator-supplied interceptor URL (clientConfig.url) with no host validation, so an interceptor could be pointed at cloud metadata endpoints such as 169.254.169.254, loopback, or internal services, and the EventListener would dispatch the request from its own network context. This resolves the interceptor URL host and rejects loopback, link-local, private, and unspecified addresses when the new interceptors.block-private-interceptor-urls feature flag is enabled. The flag is off by default to preserve backwards compatibility, and hosts in the existing github.enterprise-host-allowlist are exempt so legitimate in-cluster interceptor URLs on private ranges stay reachable. The design mirrors the existing enterprise-host-allowlist hardening. Signed-off-by: avneetbansal-aws <[email protected]>
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
|
|
|
/kind bug |
|
@avneetbansal-aws: The label(s) DetailsIn response to this:
Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
Changes
Fixes #2023
interceptors.Execute()built its outbound request directly from an operator-supplied interceptor URL (clientConfig.urlon aClusterInterceptor,Interceptor, orNamespacedInterceptor) without validating the host. A cluster user who can define an interceptor could therefore point it at a cloud metadata endpoint such as169.254.169.254, at loopback, or at any internal RFC1918 service, and the EventListener would issue that request from its own network context and forward the fullInterceptorRequestpayload. This is a server-side request forgery (SSRF) vector.This change adds an opt-in guard. A new
URLValidatorin theinterceptorspackage resolves the interceptor URL host and rejects any resolved address that is loopback, link-local (which covers the169.254.0.0/16metadata range), private, or unspecified.Execute()now takes an optional validator and runs the check before dispatching, so existing callers are unaffected.The guard is gated behind a new feature flag
interceptors.block-private-interceptor-urlsin thefeature-flags-triggersConfigMap, defaulting tofalseso behaviour is unchanged on upgrade. It reuses the existinggithub.enterprise-host-allowlistentries (inconfig-triggers-core-interceptors) as an escape hatch, so legitimate in-cluster interceptor URLs that resolve to private addresses stay reachable when an operator turns the guard on. The design intentionally mirrors the existing enterprise-host allowlist hardening already in the repo.One known limitation worth calling out: the check resolves the host and then a fresh connection is dialed, so there is a validate-then-reconnect (TOCTOU) window. Pinning the dialed IP via
net.Dialer.Controlwould close that gap and is a reasonable follow-up; this PR keeps the scope to the pre-dispatch check, the flag, and the allowlist.Submitter Checklist
docs/install.mdand theconfig/config-feature-flags.yamlmanifest)URLValidator, the newExecutepath, and the feature flag)/kind bugon the PR.Release Notes