A workload inside an Istio mesh calls an external HTTPS API at api.vendor.example.com. What does adding a ServiceEntry for that host change, and how does the mesh's outboundTrafficPolicy mode affect whether the call works at all?
answer
- the registry is what rules can name
- default passes unknown hosts through
- allowlist mode flips the default
- external host becomes a first-class destination
- the proxy can originate the TLS
basics
~20 sA ServiceEntry adds an external host to the mesh's service registry, so VirtualService and DestinationRule rules, timeouts, retries and proper telemetry apply to it. Whether the call works without one depends on outboundTrafficPolicy: ALLOW_ANY passes unknown hosts through, REGISTRY_ONLY blocks them.
solid answer
~50 sBy default the mesh's `outboundTrafficPolicy.mode` is **ALLOW_ANY**, so a call to an unregistered external host is passed through blindly — it works, but the sidecar treats it as opaque traffic: no per-destination routing, no timeouts or retries from a VirtualService, and telemetry lumped under a generic passthrough destination rather than the hostname. Switching the mesh to **REGISTRY_ONLY** turns that into an allowlist: anything not in the registry is dropped, so every intended external dependency needs a ServiceEntry and everything else is denied by default. A `ServiceEntry` with `hosts: [api.vendor.example.com]`, `location: MESH_EXTERNAL` and a `resolution` mode makes the host a first-class registry entry, and from that point normal Istio resources apply to it — a VirtualService can set a timeout, a DestinationRule can set connection-pool limits or originate TLS. That is the real value: external dependencies stop being a blind spot in both policy and metrics.
code
yaml · 30 linesapiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
name: vendor-api
namespace: payments
spec:
hosts:
- api.vendor.example.com
ports:
- number: 443
name: https
protocol: HTTPS
location: MESH_EXTERNAL
resolution: DNS
exportTo:
- "."
---
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: vendor-api
namespace: payments
spec:
hosts:
- api.vendor.example.com
http:
- timeout: 3s
route:
- destination:
host: api.vendor.example.comgo deeper
Know that a ServiceEntry adds an external hostname to the mesh's service registry, and that by default external calls already succeed without one.
Contrast the two outboundTrafficPolicy modes precisely, and list what registration buys: VirtualService timeouts and retries, DestinationRule limits and TLS origination, and telemetry attributed to the hostname.
Sequence a move to REGISTRY_ONLY safely — discover real external dependencies from telemetry first, register them, scope with exportTo, then flip — and say plainly where this stops being an egress control.
Decide whether external dependencies are inventoried by policy at all, who reviews new ServiceEntries, and how mesh-level allowlisting relates to the network-level egress controls that actually enforce it.
## What the registry is for Istio programs each sidecar from a **service registry** — in Kubernetes, primarily the Services it discovers in the cluster. Every routing and policy resource is expressed in terms of hosts in that registry. An external hostname is, by definition, not in it, which is why a plain outbound call to a third-party API sits outside everything the mesh normally gives you. ## The two outbound modes `meshConfig.outboundTrafficPolicy.mode` decides what happens to traffic for an unknown destination: - **`ALLOW_ANY`** (the default in a standard installation) — unknown destinations are forwarded as-is through a generic passthrough path. The call succeeds. It is also invisible: it is not attributed to the hostname in telemetry, no VirtualService or DestinationRule applies, and no policy constrains it. - **`REGISTRY_ONLY`** — unknown destinations are sent to a black-hole path and fail. Every external dependency must be declared, which turns the registry into an egress allowlist. The trade is straightforward and worth stating plainly in an interview: `ALLOW_ANY` never blocks a legitimate call and never tells you what is leaving; `REGISTRY_ONLY` gives you a reviewable inventory of external dependencies at the cost of breaking any call somebody forgot to declare. Teams that flip it usually run in `ALLOW_ANY` first with telemetry-driven discovery of what is actually being called, then flip once the ServiceEntries exist. ## What a ServiceEntry declares ```yaml apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: vendor-api spec: hosts: - api.vendor.example.com ports: - number: 443 name: https protocol: HTTPS location: MESH_EXTERNAL resolution: DNS ``` - `hosts` — the name(s) being added to the registry. - `ports` — the port number, a name, and crucially the **protocol**, which decides how much the proxy understands. `HTTP` gives you request-level features; `HTTPS` or `TLS` means the proxy sees an encrypted stream and can route on SNI but not on paths or headers. - `location` — `MESH_EXTERNAL` for third-party endpoints (no mesh identity expected), `MESH_INTERNAL` for workloads that are part of your mesh but not registered in this cluster, such as a VM. - `resolution` — `DNS` to resolve the hostname at request time, `STATIC` to use explicit `endpoints` you list, `NONE` for cases where the destination IP is used directly, and `DNS_ROUND_ROBIN` where you want a single resolved endpoint reused. ## What you gain once it is registered The host becomes addressable by every other Istio resource: - A **VirtualService** for that host can apply a `timeout` and a `retries` policy — so a slow vendor no longer holds your threads for as long as the vendor decides. - A **DestinationRule** for that host can apply `trafficPolicy.connectionPool` limits and `outlierDetection`, and can originate TLS: the application speaks plain HTTP to port 80 and the sidecar upgrades the connection to HTTPS with `tls: {mode: SIMPLE}`. That is a genuinely useful pattern, because it moves certificate handling out of every application. - **Telemetry** attributes the traffic to the hostname instead of a generic passthrough bucket, so "which vendors do we call, how often, and how slowly" becomes answerable. Note the interaction with the protocol you declared: TLS origination requires the proxy to be handling cleartext from the app. If the application already speaks HTTPS end-to-end, the sidecar can only see and act on the encrypted stream. ## Scoping A ServiceEntry, like a VirtualService and a DestinationRule, honours `exportTo`. Declared with `exportTo: ["."]` it exists only for its own namespace, which is how you let one team register a vendor dependency without adding that hostname to every proxy in the cluster. Under `REGISTRY_ONLY` that also means the allowlist is per-namespace rather than global, which is usually what you want. ## The common misreading A ServiceEntry is **not** a firewall rule and not a proxy configuration for the destination itself. It is a registry entry — a statement that this name exists and has these ports. Its blocking effect appears only in combination with `REGISTRY_ONLY`, and even then, a determined workload without a sidecar, or traffic that bypasses the proxy's interception, is not governed by it. Presenting it as egress security without those caveats is the answer that loses marks.
- How would you let applications speak plain HTTP while the connection to the vendor is still TLS?Register the host with an HTTP port in the ServiceEntry and add a DestinationRule with `trafficPolicy.tls.mode: SIMPLE` for it. The sidecar originates TLS on the way out, so certificate handling and cipher configuration live in the mesh rather than in every application. It only works while the app sends cleartext the proxy can act on.
- What does the protocol you declare on the ServiceEntry port actually change?How much the proxy can see. With `HTTP` it parses requests, so a VirtualService can match on paths and headers and telemetry records per-route data. With `HTTPS` or `TLS` it handles an opaque stream — routing by SNI at best, no path or header matching, and coarser metrics.
- Is a ServiceEntry with REGISTRY_ONLY a sufficient egress control?No. It is a registry entry whose blocking effect comes from the mesh mode, and it governs only traffic that actually goes through a sidecar. Workloads without injection, or traffic that escapes interception, are unaffected. Treat it as dependency inventory and policy attachment, with network-level egress control as the enforcement layer.
saying these in an interview costs you the question
- Calls a ServiceEntry a firewall or egress rule on its own
- Thinks external calls fail by default without one
- Expects path-based routing on a port declared as HTTPS
- Assumes the entry is cluster-wide regardless of exportTo
- Believes registering the host encrypts the traffic automatically