Skip to main content
An Outpost gives Genesis a path into your network, so it is built to reach only what you allow and nothing else. Three layers decide what Genesis can reach, and the last one runs on your side.

Who can do what

To let a role route connections through an Outpost, click Edit on its card on Config -> Outposts and check the role under Who can route connections through it. Admins always can. Every grant and every routing change is audited. The route layer applies when routing is set or changed. Using a connection someone already routed follows the normal connection permissions for people and agents.

Routed hosts inside Genesis

Genesis reaches a routed host through a listener for the Outpost’s tunnel, on a loopback address in 127.77.0.0/16, and makes the host’s name resolve to that address in the Genesis server. That is how routed connections work without driver changes, TLS certificate checks against the real host name included. Connections routed through the Outpost are the intended way to reach a routed host. The parts of Genesis that agents drive directly hold no Outpost grant, and Genesis refuses them routed hosts where they make their requests:
  • Agent web tools (fetching a URL, API calls, webhooks, logo downloads, and the redirects they follow) are refused a routed host name and a tunnel address. The error names the Outpost and says to use a connection to the system instead.
  • Bulk downloads are refused a routed host name, a tunnel address, and any name that resolves to a tunnel address, redirects included.
  • The agent browser does not load a page, resource or WebSocket from a routed host name, a tunnel address, or a name that resolves to one. A redirect from another site is not checked.
  • Python run by agents (execute_python_code) cannot open a socket to a tunnel address, or to a name that resolves to one.
  • On a Databricks App, the processes Genesis starts for agents (MCP servers, coding-agent CLIs, dashboards) start without the host-name resolver, so routed names do not resolve in them. The Twin lineage server keeps it: it scans the connections it is given, routed ones included.
Name resolution alone does not decide who reaches a routed host: on self-hosted Genesis and on Snowflake, routed names are written to /etc/hosts, so they resolve for every process in the container, and a process that opens its own sockets can dial a tunnel address directly. Agent web tools do not look a name up, so a public name that points into 127.77.0.0/16 is not caught by them. The tunnel listeners themselves are guarded, as described next.

Who can use a tunnel listener

Genesis’s tunnel worker, the Genesis process that holds the tunnel listeners, checks every connection to a tunnel listener before it forwards anything to the Outpost. It asks the operating system’s kernel which account opened the connection and, where it needs to, which processes hold it:
  • Snowflake, Docker and Kubernetes. Genesis runs as root, and the code agents run (Python, flow steps, coding tools) runs as the restricted cortex_sandbox account. The tunnel worker forwards a connection only from a socket root owns. A connection from cortex_sandbox, or from any other account, is refused.
  • Databricks App. Genesis and its code sandbox share one account, and the sandbox runs agent code in its own user namespace. The tunnel worker forwards a connection only when every process holding it is in Genesis’s own user namespace. A connection held by a sandboxed process, or by no process the worker can see, is refused.
Genesis’s own processes are admitted: the server and its workers, Twin lineage scans and dbt runs. Anything the worker cannot decide is refused. A Databricks App that runs with a fixed instance count runs in a container that rewrites the source address of loopback traffic; the worker recognizes that rewrite and still identifies the connecting process. When the worker starts, it checks that it can identify a connection of its own, and it does not start if it cannot (Genesis’s log then has an admission_failed line with the reason). Each connection costs one kernel lookup; on a Databricks App, connections that arrive together also share one scan of the process table. When more than 256 connections are waiting to be checked, a new one is refused (busy). A refused connection is closed before anything reaches the Outpost. Genesis’s log records it at WARNING as an outpost tunnel worker line whose event is admission_refused and whose text reads admission: refused a connection to <listener> from <peer> (uid <n>): <reason>: <detail>, at most once a minute for the same listener, account and reason. The worker’s start line ("event":"started", also at WARNING) names the admission mode: uid, userns, or off. The check is controlled by outpost.enforce_tunnel_admission. Turning it off forwards every connection to a tunnel listener. A change takes effect within about 15 seconds and restarts the tunnel worker, which drops open tunnel connections; Outposts reconnect on their own. If the check cannot work where Genesis runs, the tunnel worker does not start and its log says why.

What the check does not cover

The check tells Genesis’s own processes apart from sandboxed ones; it cannot tell which code runs inside a Genesis process. Agent-driven work that runs in Genesis’s own account, outside the sandbox, is admitted like the rest of Genesis:
  • Snowflake, Docker and Kubernetes: MCP servers Genesis starts, agent git operations, the sqlite3 command line and the Chromium browser run as root. Skill shell steps, dashboard rendering, the Spark worker and local Talend jobs run as cortex_sandbox, so their connections to a tunnel listener are refused.
  • Databricks App: MCP servers Genesis starts outside the sandbox, the Chromium browser, and coding agents an administrator has turned on.
Only hosts that are already routed can be reached through a tunnel listener, and the Outpost adds no authentication of its own: a destination asks for credentials only if it is configured to. Keep ALLOWED_DESTINATIONS to the exact host:port entries you intend Genesis to reach.

What the Outpost enforces

The Outpost checks every connection at the moment it opens it, default-deny:
  • Only allowed destinations. A route is held only if its destination is inside ALLOWED_DESTINATIONS. Destinations outside it are reported to Genesis as refused.
  • Only the route’s own destination. Each route can reach exactly one host:port. A request on that route for any other host or port is rejected before anything is looked up or dialed.
  • Cloud metadata and link-local addresses are always blocked, even if listed in ALLOWED_DESTINATIONS: 169.254.0.0/16 (the AWS, Azure, GCP and OCI instance metadata services and container credential endpoints), fe80::/10, the AWS IPv6 metadata addresses, Alibaba’s 100.100.100.200, Azure’s 168.63.129.16, 0.0.0.0/8, unspecified and multicast addresses, and names such as metadata.google.internal. The Outpost checks the name and every address it resolves to, then connects to the checked address itself, so DNS cannot answer differently at connect time. This applies to what Genesis asks the Outpost to reach; the Outpost’s own sign-in to your secret store (which may read the instance metadata service for its managed identity or service account) is not a route and keeps working.
  • No general proxy. The tunnel carries only TCP connections that Genesis opens toward a route the Outpost itself declared. Genesis cannot name any other destination, and the protocol has no way for the Outpost to open a connection toward Genesis or into it. There is no SOCKS, UDP or forward mode.
  • No command execution. The Outpost answers a small set of typed requests (health, routes, route checks, secret reads). It runs no commands and no code from Genesis.
  • Bounded. At most 256 concurrent connections per route; see Tunnel limits for the limits Genesis applies.
Route checks from the Outposts page and from Eve go through the same checks.

How the Outpost signs in

The Outpost connects out over HTTPS (port 443) and must sign in before a tunnel exists. You open no inbound port. It signs in twice, and both must succeed:
  1. At the platform’s front door, with its own platform identity, before the connection reaches Genesis:
    • Databricks App: the Outpost’s own service principal with CAN USE on the Genesis App and nothing else. The Outpost mints a short-lived token before every connection.
    • Self-hosted Genesis: none required; the tunnel key below authenticates it. Your ingress may add its own controls.
    • Snowflake Native App (release 1.19.97 or later): a dedicated Snowflake service user with a key pair and no password. Its role holds only the APP_OUTPOST_TUNNEL application role, which allows nothing but connecting to the tunnel endpoint. The generated SQL also pins the user to your Outpost’s egress IP with a network policy, so a copied key does not work from elsewhere. The private key is generated where the Outpost runs and never leaves your network.
  2. Inside the tunnel, with its own tunnel key. The connection is one WebSocket to /outpost-tunnel using the Genesis-native tunnel protocol, genesis-outpost.v1. Genesis sends a fresh random challenge; the Outpost answers with a proof made with its key over that challenge, its own random challenge and its slot; Genesis checks it, then answers with a proof of its own that the Outpost checks before it carries anything. The key itself never crosses the network, so a recorded sign-in cannot be replayed. Genesis refuses a sign-in that does not finish within 10 seconds.
Every Outpost has its own tunnel key (Outpost 0.7.0 or later). Genesis issues it, keeps it in its secret store and shows it once. The key signs in only that Outpost, and Genesis holds for it only listeners on that Outpost’s own loopback range (127.77.<slot>.x), never on a port Genesis itself serves: it cannot open another Outpost’s addresses, nor use the tunnel to reach anything inside Genesis. One session per Outpost is active at a time; a newer sign-in for the same slot ends the older one. Each answer from an Outpost to a control request also carries a proof made with that key over a fresh per-request challenge and the request, and Genesis does not use the answer without a valid proof. An Outpost that has not been issued a key cannot sign in, and Genesis sends it nothing. Each Outpost’s identity and key are its own, so you can rotate or revoke one without touching the others. See Rotate, revoke or remove.

Tunnel limits

Over its one WebSocket, each Outpost’s tunnel carries many connections at once as separate streams, each with its own flow control, so one large transfer does not hold up the others. Genesis applies these limits: A connection refused by one of these limits is closed at once; see Troubleshooting.

What Genesis stores

  • The Outpost definition: its name, slot, optional domain patterns and route grants.
  • Connections, as usual. A connection routed through an Outpost records which Outpost it uses.
  • References, not secret values, for credentials kept in your store. A connection stores outpost_acme-prod/genesis/postgres-prod#password, not the password. When Genesis connects, the Outpost reads the value from your secret store with its own identity and hands it to Genesis, which holds it in memory only, for a few minutes, and never writes it to its database. The Outpost reads only secrets whose names start with its ALLOWED_SECRET_PREFIX, and only when its secrets capability is on. It reads from the one store you configure (AWS Secrets Manager, Azure Key Vault or Google Secret Manager) under its own cloud identity, which needs read access only: secretsmanager:GetSecretValue, the Key Vault Secrets User role, or the Secret Manager Secret Accessor role. Scope that grant to the same prefix (genesis/ in AWS, genesis-- in Azure and Google) or to the individual secrets.
Genesis never holds the Outpost’s private key, service-principal secret or cloud credentials.

Audit

  • In Genesis: route grants and every change to what a connection routes through an Outpost are recorded in the Genesis audit log.
  • On the Outpost: every route change, connection admitted or refused, route check and secret read is written to the Outpost’s log as an audit record ("logger":"genesis_outpost.audit", JSON lines in production). Collect it with your usual log pipeline.

Recommendations for production

  • Run the Outpost on a VM, Docker or Kubernetes, not a laptop.
  • Keep ALLOWED_DESTINATIONS to the exact host:port entries Genesis needs.
  • Keep the Snowflake network-policy pin, and store the private key in a secret store or a Kubernetes Secret.
  • Run a separate Outpost per network or trust zone rather than one Outpost that can reach everything.
  • Grant routing to roles only on the Outposts they need.