Outbound connections
The Outbound connections policy lets you decide which addresses and URLs your es-python programs may connect to. It stops server-side request forgery (SSRF), where untrusted input steers your program into calling an internal service or a cloud metadata address, and it can also act as an allowlist for every connection a program makes. This page explains the settings, the rule format and what you see when a connection is stopped.
What it does
When a policy is set, es-python checks each outbound connection against your rules before it is made. A rule allows or denies a destination; the first rule that matches decides, and when none matches the default applies. A denied connection fails with a permission error inside your program, and the dashboard records an event.
With no policy set, nothing changes: es-python behaves exactly as it does without this feature. The control is in two places: on each product's Filters page for es-python (your account policy), and in a machine's Configure window (that machine's own policy).
Settings
| Setting | Choices | Built-in default |
|---|---|---|
| Check | Untrusted destinations only, or Every connection | Untrusted destinations only |
| When no rule matches | Allow or Deny | Allow |
| On a violation | Block or Report only | Block |
Untrusted destinations only applies the rules to a connection whose host or URL came from a watched source, such as a network request. This is the SSRF case, and it leaves the connections your own code chooses alone, so it is safe to turn on. It works with the taint sources you have switched on; network input is the one that matters for SSRF.
Every connection applies the rules to every outbound connection, like a firewall for the program. Pair it with Report only first: you see every connection your list would stop, without stopping any, and switch to Block once the list is right.
Account and machine
Your account policy applies to every es-python machine. A machine can add its own rules and override any setting. The machine's rules are checked first, then the account's, so a machine rule can make an exception to an account rule. A setting left on Account default follows the account.
Rule targets
| Target | Example | Matches |
|---|---|---|
* |
* |
every destination |
| IP address | 10.0.0.5, ::1 |
that address |
| IP range | 10.0.0.0/8, fd00::/8 |
every address in the range |
| Host name | api.stripe.com |
that name |
| Any subdomain | *.amazonaws.com |
every name under it, not the name itself |
@internal |
@internal |
private, loopback and link-local addresses |
@metadata |
@metadata |
cloud instance metadata addresses and names |
| URL prefix | https://api.stripe.com/v1/ |
requests to that host whose path starts with that prefix |
Add :port to narrow a host, address or range to one port: db.internal:5432, 10.0.0.0/8:443. For an IPv6 address with a port, use brackets: [fd00::/8]:443.
Address and range rules are checked against the address the program actually connects to, after the name is looked up. So @internal also stops a public-looking name that points at an internal address, and an address written in an unusual form such as 2130706433 or 0x7f000001.
URL rules are checked by the common HTTP client libraries (urllib, requests, urllib3, httpx and aiohttp). For any other connection, an Allow URL rule allows its host and port, and a Deny URL rule blocks its host and port only when it names the whole site (a path of /). A Deny rule for one path, such as https://example.com/private/, blocks requests to that path and leaves the rest of the site reachable.
Order
Rules are checked top to bottom and the first match wins. Use the arrows to reorder them. A common pattern is a few Allow rules for the services you call, then Deny *; or Deny @internal and @metadata with the default left on Allow.
What you see
A stopped connection appears in your es-python events as egress blocked, with the destination in the detail line. Under Report only the event is egress violation and the connection goes ahead. An event caused by untrusted input is graded High; one from an Every connection policy, where your own code chose the destination, is graded Medium.
Changes reach a running machine within about 30 seconds.
Limits
- Up to 128 rules for your account and 128 for each machine.
- A connection opened outside the program's own network calls, such as by a separate command it runs, is not checked. Nor are connections made by libraries that open their own sockets natively, such as uvloop, pycurl and grpcio; URL rules still apply to httpx and aiohttp running on uvloop.
- When your program goes through an HTTP proxy, address rules see the proxy. With Every connection, allow the proxy's address, and use URL rules for the real destinations.
- Untrusted destinations only can only see input from the sources you have switched on.