Skip to content

Configuring an Egress Gateway (Ambient Mode)

Alpha: this feature is in alpha. Values, generated resources, and package coverage may change between releases.

Big Bang can deploy a shared egress gateway that packages bind their outbound routes to: an ambient waypoint in the istio-egress namespace, deployed via the istio-egress-gateway package. This document assumes Istio ambient mode is already enabled (istio.ambient.enabled: true); the egress gateway requires it.

Using an egress gateway provides:

  • A single exit point for external traffic: package egress flows through one place instead of every pod reaching the Internet directly.
  • Default-deny egress authorization: the waypoint denies all traffic except what each route’s AuthorizationPolicy allows, enforcing per-host, per-source policy on mTLS workload identity, outside the client pod.
  • A registry replacement: ambient mode drops sidecar mode’s REGISTRY_ONLY guardrail; the waypoint restores (stronger) control over which external hosts are reachable. See Restrictive NetworkPolicies are still critical.
  • Centralized observability: egress traffic is visible in one waypoint’s Istio telemetry rather than scattered across namespaces.

Enabling

Enable the egress gateway:

istio:
  egressGateway:
    enabled: true

This flag enables: - istioEgressGateway package which creates the default egress-waypoint and istio-egress namespace - default egress routing through the egress-waypoint for all outbound routes configured by integrated packages

Complete example

Once the gateway is deployed, a package routes an external host through it by declaring an outbound route in its bb-common values. For supported Big Bang packages the umbrella configures the default egressGateway (see Default waypoint binding for packages):

routes:
  defaults:
    outbound:
      # configured by the umbrella for supported packages
      egressGateway: istio-egress/egress-waypoint
  outbound:
    external-host:
      enabled: true
      hosts:
        - external-host.com
      # ports default to HTTPS/443

From this route bb-common renders, in the package namespace: the ServiceEntry (external-host-external) labeled with the istio.io/use-waypoint labels, the AuthorizationPolicy (external-host-external-egress) targeting it and admitting only this package’s workloads, and a NetworkPolicy allowing HBONE egress to the waypoint.

flowchart TB
    subgraph pkg["package namespace"]
        direction TB
        pod["workload pod<br>(ztunnel-captured)"]
        se["ServiceEntry<br>hosts: external-host.com<br>istio.io/use-waypoint labels"]
        ap["AuthorizationPolicy<br>(targets the ServiceEntry)"]
    end
    subgraph egress["istio-egress namespace"]
        direction TB
        wp["egress-waypoint pod<br>(created by istiod from the Gateway)"]
        deny["AuthorizationPolicy default-deny<br>(targets the Gateway)"]
    end
    pod -- "HBONE :15008" --> wp
    wp -- ":443" --> ext["external-host.com"]
    se -. binds route to .-> wp
    ap -. enforced at .-> wp
    deny -. enforced at .-> wp

The ServiceEntry’s waypoint labels make ztunnel tunnel traffic for external-host.com over HBONE to the waypoint pod instead of sending it directly out; the waypoint evaluates the attached AuthorizationPolicies against its default-deny baseline and forwards the allowed traffic to the external host.

Restrictive NetworkPolicies are still critical

The waypoint only governs traffic that reaches it. Even with the egress gateway enabled, an overly permissive egress NetworkPolicy (an allow-anywhere rule, or a broad 443 → 0.0.0.0/0) leaves arbitrary external hosts reachable: any rule wide enough to reach the Internet is a path around the waypoint, and bypassed traffic never meets the default-deny baseline or the per-route AuthorizationPolicies provided by the egress waypoint.

Nothing in the mesh backstops this: sidecar mode’s REGISTRY_ONLY, which refused to route traffic to undeclared hosts, has no ambient equivalent; ztunnel passes unregistered destinations through untouched.

If your intent is to keep package egress scoped only to enumerated hosts you must ensure external traffic has no path except HBONE (15008) to the waypoint.

Configuring the default egress gateway

Default waypoint binding for packages

routes.defaults.outbound.egressGateway is the <namespace>/<name> waypoint reference the umbrella passes to packages; a package’s outbound routes bind to it unless a route sets its own egressGateway:

routes:
  defaults:
    outbound:
      egressGateway: istio-egress/egress-waypoint

The default matches the default waypoint deployed by the istio-egress-gateway package, so it normally does not need to be changed.

To override the Big Bang specified egress gateway set the binding explicitly in the package’s values, which win over the umbrella default:

<package>:
  values:
    routes:
      defaults:
        outbound:
          egressGateway: istio-egress/egress-waypoint

Only set an explicit binding when the waypoint already exists: Istio fails open, and a route bound to a missing waypoint egresses directly.

Waypoint sizing and behavior

Chart values pass through istioEgressGateway.values. The waypoint Deployment is generated by istiod, so sizing is expressed as strategic-merge patches under waypoint.config (supported keys: deployment, service, serviceAccount, horizontalPodAutoscaler, podDisruptionBudget; HPA and PDB are only created when set). The chart delivers these via the Gateway’s infrastructure.parametersRef; the upstream mechanism is described under Automated deployment in Istio’s Gateway API documentation. For example:

istioEgressGateway:
  enabled: true
  values:
    waypoint:
      config:
        deployment:
          spec:
            replicas: 2
            template:
              spec:
                containers:
                  - name: istio-proxy
                    resources:
                      requests:
                        cpu: 500m
                        memory: 512Mi
                      limits:
                        cpu: 500m
                        memory: 512Mi
        podDisruptionBudget:
          spec:
            minAvailable: 1

The waypoint is shared by every bound route across all packages (a single fate domain), so size it for the cluster’s aggregate egress traffic.

Other chart values: waypoint.name, waypoint.labels/annotations, waypoint.listeners.port, and defaultDeny.enabled (set false to drop the default-deny baseline, leaving the waypoint open to any bound traffic). See the package documentation for the full values reference.