Configure multi-hop sessions for Boundary Enterprise
Enterprise
This feature requires Boundary Enterprise.
For Boundary Enterprise, you can configure ingress, intermediate, and egress workers to take advantage of multi-hop worker capabilities.
This page details a three-worker chain. The ingress worker connects to the controllers, the intermediate worker connects to the ingress worker, and the egress worker connects to the intermediate worker and reaches the target.
Note that "ingress," "intermediate," and "egress" are general ways to describe how the respective worker interacts with resources. A worker can serve more than one of those roles at a time. Refer to Multi-hop sessions for more information.
Requirements
Before you configure a multi-hop chain, you must have:
- A running Boundary Enterprise control plane.
- Three hosts with the Boundary binary installed, one in each network. Refer to Install Boundary.
- The following network paths:
- The ingress worker reaches the controllers on port
9201, and clients reach the ingress worker on port9202. - The intermediate worker reaches the ingress worker on port
9202. - The egress worker reaches the intermediate worker on port
9202, and reaches the target host.
- The ingress worker reaches the controllers on port
You do not need inbound network rules between the network boundaries. Each worker connects outbound to its upstream, and Boundary uses that connection in both directions.
Configure the workers
Create a configuration file on each host.
The files differ in three places: the initial_upstreams value, the tags, and the KMS key that encrypts the worker's credentials.
The examples use the worker-led registration method. To use a different method, refer to Register workers.
Ingress worker configuration
The ingress worker points initial_upstreams at the controller load balancer address.
Create the ingress-worker.hcl file with the relevant configuration information:
/etc/boundary.d/ingress-worker.hcl
# disable memory from being swapped to disk
disable_mlock = true
# listener denoting this is a worker proxy
listener "tcp" {
address = "0.0.0.0:9202"
purpose = "proxy"
}
# worker block for configuring the specifics of the
# worker service
worker {
public_addr = "<worker_public_addr>"
initial_upstreams = ["<controller_lb_address>:9201"]
auth_storage_path = "/var/lib/boundary"
tags {
type = ["worker1", "upstream"]
}
}
# Events (logging) configuration. This
# configures logging for ALL events to both
# stderr and a file at /var/log/boundary/<boundary_use>.log
events {
audit_enabled = true
sysevents_enabled = true
observations_enable = true
sink "stderr" {
name = "all-events"
description = "All events sent to stderr"
event_types = ["*"]
format = "cloudevents-json"
}
sink {
name = "file-sink"
description = "All events sent to a file"
event_types = ["*"]
format = "cloudevents-json"
file {
path = "/var/log/boundary"
file_name = "ingress-worker.log"
}
audit_config {
audit_filter_overrides {
sensitive = "redact"
secret = "redact"
}
}
}
}
# kms block for encrypting the authentication PKI material
kms "awskms" {
purpose = "worker-auth-storage"
region = "us-east-1"
kms_key_id = "19ec80b0-dfdd-4d97-8164-c6examplekey3"
endpoint = "https://vpce-0e1bb1852241f8cc6-pzi0do8n.kms.us-east-1.vpce.amazonaws.com"
}
Intermediate worker configuration
The intermediate worker points initial_upstreams at the ingress worker on port 9202.
Create the intermediate-worker.hcl file with the relevant configuration information:
/etc/boundary.d/intermediate-worker.hcl
# disable memory from being swapped to disk
disable_mlock = true
# listener denoting this is a worker proxy
listener "tcp" {
address = "0.0.0.0:9202"
purpose = "proxy"
}
# worker block for configuring the specifics of the
# worker service
worker {
public_addr = "<worker_public_addr>"
initial_upstreams = ["<ingress_worker_address>:9202"]
auth_storage_path = "/var/lib/boundary"
tags {
type = ["worker2", "intermediate"]
}
}
# Events (logging) configuration. This
# configures logging for ALL events to both
# stderr and a file at /var/log/boundary/<boundary_use>.log
events {
audit_enabled = true
sysevents_enabled = true
observations_enable = true
sink "stderr" {
name = "all-events"
description = "All events sent to stderr"
event_types = ["*"]
format = "cloudevents-json"
}
sink {
name = "file-sink"
description = "All events sent to a file"
event_types = ["*"]
format = "cloudevents-json"
file {
path = "/var/log/boundary"
file_name = "intermediate-worker.log"
}
audit_config {
audit_filter_overrides {
sensitive = "redact"
secret = "redact"
}
}
}
}
# kms block for encrypting the authentication PKI material
kms "awskms" {
purpose = "worker-auth-storage"
region = "us-east-1"
kms_key_id = "19ec80b0-dfdd-4d97-8164-c6examplekey4"
endpoint = "https://vpce-0e1bb1852241f8cc6-pzi0do8n.kms.us-east-1.vpce.amazonaws.com"
}
Egress worker configuration
The egress worker points initial_upstreams at the intermediate worker on port 9202.
Create the egress-worker.hcl file with the relevant configuration information:
/etc/boundary.d/egress-worker.hcl
# disable memory from being swapped to disk
disable_mlock = true
# listener denoting this is a worker proxy
listener "tcp" {
address = "0.0.0.0:9202"
purpose = "proxy"
}
# worker block for configuring the specifics of the
# worker service
worker {
public_addr = "<worker_public_addr>"
initial_upstreams = ["<intermediate_worker_address>:9202"]
auth_storage_path = "/var/lib/boundary"
tags {
type = ["worker3", "egress"]
}
}
# Events (logging) configuration. This
# configures logging for ALL events to both
# stderr and a file at /var/log/boundary/<boundary_use>.log
events {
audit_enabled = true
sysevents_enabled = true
observations_enable = true
sink "stderr" {
name = "all-events"
description = "All events sent to stderr"
event_types = ["*"]
format = "cloudevents-json"
}
sink {
name = "file-sink"
description = "All events sent to a file"
event_types = ["*"]
format = "cloudevents-json"
file {
path = "/var/log/boundary"
file_name = "egress-worker.log"
}
audit_config {
audit_filter_overrides {
sensitive = "redact"
secret = "redact"
}
}
}
}
# kms block for encrypting the authentication PKI material
kms "awskms" {
purpose = "worker-auth-storage"
region = "us-east-1"
kms_key_id = "19ec80b0-dfdd-4d97-8164-c6examplekey5"
endpoint = "https://vpce-0e1bb1852241f8cc6-pzi0do8n.kms.us-east-1.vpce.amazonaws.com"
}
Refer to the list below for explanations of the parameters used in the example above:
disable mlock (bool: false)- Disables the server from executing themlocksyscall, which prevents memory from being swapped to the disk. Disablingmlockis fine for local development and testing. However, it is not recommended for production unless the systems running Boundary use only encrypted swap or do not use swap at all. Boundary only supports memory locking on UNIX-like systems that supportmlock()syscall like Linux and FreeBSD.On Linux, to give the Boundary executable the ability to use
mlocksyscall without running the process as root, run the following command:sudo setcap cap_ipc_lock=+ep $(readlink -f $(which boundary))If you use a Linux distribution with a modern version of systemd, you can add the following directive to the "[Service]" configuration section:
LimitMEMLOCK=infinitylistener- Configures the listeners on which Boundary serves traffic (API cluster and proxy).worker- Configures the worker. If present,boundary serverstarts a worker subprocess.events- Configures event-specific parameters.The example events configuration above is exhaustive and writes all events to both
stderrand a file. This configuration may or may not work for your organization's logging solution.kms- Configures KMS blocks for various purposes.Refer to the links below for configuration information for the different cloud KMS blocks:
Refer to the documentation for additional top-level configuration options and additional worker-specific options.
Start and register the workers
Start the workers in order from the top of the chain down. A downstream worker cannot connect until its upstream is running and authorized.
Complete the following steps for each worker, beginning with the ingress worker:
Start the worker on its host:
$ boundary server -config=/etc/boundary.d/ingress-worker.hclRefer to Start and verify a worker to run the worker under systemd or in a container.
Copy the Worker Auth Registration Request value from the startup output. You can also read it from the
auth_request_tokenfile in the worker'sauth_storage_pathdirectory.Register the worker with a controller:
$ boundary workers create worker-led -worker-generated-auth-token=$WORKER_TOKENRepeat these steps for the intermediate worker, and then for the egress worker.
Downstream workers register through their upstream worker. The intermediate and egress workers do not need network access to the control plane.
Verify the chain
Use the Directly Connected Downstream Workers field to confirm the shape of the chain.
Read the ingress worker:
$ boundary workers read -id w_UJ3Qq63Jx0
The output lists the intermediate worker as its downstream:
Worker information:
Active Connection Count: 0
Address: 10.0.0.10:9202
ID: w_UJ3Qq63Jx0
Last Status Time: 2026-08-07 19:45:22.616245 +0000 UTC
Local Storage State: not configured
Release Version: Boundary v1.0.0+ent
Type: pki
Version: 1
Tags:
Configuration:
type: ["worker1" "ingress"]
Directly Connected Downstream Workers:
w_GHBqIeHMyR
Read the intermediate worker, and confirm that it lists the egress worker as its downstream. The egress worker sits at the end of the chain, so it has no downstream workers.
Route target traffic through the chain
Worker filters control which workers Boundary uses for a session. Set an ingress filter to choose where the client connects, and an egress filter to choose which worker reaches the target.
Boundary chooses the path between the ingress and egress workers automatically. You do not filter on intermediate workers.
Log in to Boundary.
Select the org, and then select the project that contains the target.
Select Targets, and then select the target.
Select the Workers tab.
Beside Ingress workers, click Add Worker Filter, and enter a filter that matches the ingress worker's tags:
"ingress" in "/tags/type"Click Save.
Beside Egress workers, click Add Worker Filter, and enter a filter that matches the egress worker's tags:
"egress" in "/tags/type"Click Save.
The button reads Add Worker Filter when the target has no filter for that role, and Edit Worker Filter when a filter already exists.
Refer to Configure a worker filter for more filter examples.
Test the connection
Connect to the target to confirm that the session traverses the chain:
$ boundary connect -target-id ttcp_uPVxp2NGiD
Boundary returns the local proxy details:
Proxy listening information:
Address: 127.0.0.1
Connection Limit: -1
Expiration: Fri, 07 Aug 2026 21:46:08 MDT
Port: 52234
Protocol: tcp
Session ID: s_phGLOoaB7v
If the session fails because no workers match the filter, refer to Troubleshoot workers.
Next steps
After you configure the chain, you can:
- Authenticate downstream workers using a separate KMS trust domain.
- Verify SSH host identity on the egress worker.
- Manage workers to reload configuration or drain sessions.