Routing, Proxying, and Load Balancing
Routes
A Route defines how to access a service running behind Pomerium. This includes authentication (both for Pomerium and passed through to the service), rewrites, header management, load balancing, etc.
When first installing Pomerium Enterprise, users may want to import existing routes from the open-source Pomerium core. The Migrate Routes button accepts the open-source config.yaml
file and imports routes from it to Pomerium Enterprise.
From the main Routes page you can view and manage existing routes. From the table of routes you can:
- Filter visible routes
- Delete one or more routes
- Move routes between Namespaces
- Export one or more route definitions to a CSV file
- Create a JSON-formatted policy report on one or more selected routes
The sections below cover the options available when creating or editing a route.
General
The General tab defines the route path, both from the internet and to the internal service, and the policies attached. Note that policies enforced on a Namespace the route resides in will also be applied.
Name
This value is only visible in the Console UI.
From
From
is the externally accessible URL for the proxied request.
Specifying tcp+https
or udp+https
for the scheme enables TCP proxying or UDP proxying support for the route. You may map more than one port through the same hostname by specifying a different :port
in the URL.
Only secure schemes (https
, tcp+https
and udp+https
) are supported.
Metrics Name
Once a Route is created, the Metric Name field will populate. You can use this name to scrape the Prometheus service for metrics on this Route when making custom dashboards.
To
To
is the destination(s) of a proxied request. It can be an internal resource, or an external resource. Multiple upstream resources can be targeted by using a list instead of a single URL:
- from: https://example.com
to:
- https://a.example.com
- https://b.example.com
A load balancing weight may be associated with a particular upstream by appending ,[weight]
to the URL. The exact behavior depends on your lb_policy
setting. See Load Balancing for example configurations.
Should be tcp
if from
is tcp+https
or udp
if from
is udp+https
.
Be careful with trailing slash.
With rule:
- from: https://verify.corp.example.com
to: https://verify.pomerium.com/anything
Requests to https://verify.corp.example.com
will be forwarded to https://verify.pomerium.com/anything
, while requests to https://verify.corp.example.com/foo
will be forwarded to https://verify.pomerium.com/anythingfoo
.To make the request forwarded to https://httbin.org/anything/foo
, you can use double slashes in your request https://httbin.corp.example.com//foo
.
While the rule:
- from: https://verify.corp.example.com
to: https://verify.pomerium.com/anything/
All requests to https://verify.corp.example.com/*
will be forwarded to https://verify.pomerium.com/anything/*
. That means accessing to https://verify.corp.example.com
will be forwarded to https://verify.pomerium.com/anything/
. That said, if your application does not handle trailing slash, the request will end up with 404 not found.
Either redirect
or to
must be set.
Redirect
Redirect
is used to redirect incoming requests to a new URL. The redirect
field is an object with several possible options:
https_redirect
(boolean): the incoming scheme will be swapped with "https".scheme_redirect
(string): the incoming scheme will be swapped with the given value.host_redirect
(string): the incoming host will be swapped with the given value.port_redirect
(integer): the incoming port will be swapped with the given value.path_redirect
(string): the incoming path portion of the URL will be swapped with the given value.prefix_rewrite
(string): the incoming matched prefix will be swapped with the given value.response_code
(integer): the response code to use for the redirect. Defaults to 301.strip_query
(boolean): indicates that during redirection, the query portion of the URL will be removed. Defaults to false.
Either redirect
or to
must be set.
Pass Identity Headers
When enabled, this option will pass identity headers to upstream applications. These headers include:
- X-Pomerium-Jwt-Assertion
- X-Pomerium-Claim-*
Policies
Add or remove Policies to be applied to the Route. Note that Policies enforced in the Route's Namespace will be applied automatically.
See the Policy setting page to learn how to apply a PPL policy to a route.
For information and examples related to PPL, see Policy Language.
Enable Google Cloud Serverless Authentication
Enable sending a signed Authorization Header to upstream GCP services.
Requires setting Google Cloud Serverless Authentication Service Account or running Pomerium in an environment with a GCP service account present in default locations.
Matchers
Path
If set, the route will only match incoming requests with a path that is an exact match for the specified path.
Regex
If set, the route will only match incoming requests with a path that matches the specified regular expression. The supported syntax is the same as the Go regexp package which is based on re2.
Regex Rewrite Pattern
The pattern to match before rewriting, ex: ^/service/([^/]+)(/.*)$
.
Regex Rewrite Substitution
The substitution for your regex pattern, ex: \\2/instance/\\1
.
Prefix
If set, the route will only match incoming requests with a path that begins with the specified prefix.
Prefix Rewrite
If set, indicates that during forwarding, the matched prefix (or path) should be swapped with this value. For example, given this policy:
from: https://from.example.com
to: https://to.example.com
prefix: /admin
prefix_rewrite: /
A request to https://from.example.com/admin
would be forwarded to https://to.example.com/
.
Timeouts
Allow Websockets
If set, enables proxying of websocket connections.
Use with caution: websockets are long-lived connections, so global timeouts are not enforced (though the policy-specific timeout
is enforced). Allowing websocket connections to the proxy could result in abuse via DOS attacks.
Allow SPDY
If set, enables proxying of SPDY protocol upgrades.
Timeout
Policy timeout establishes the per-route timeout value. Cannot exceed global timeout values.
Idle Timeout
If you are proxying long-lived requests that employ streaming calls such as websockets or gRPC, set this to either a maximum value there may be no data exchange over a connection (recommended), or set it to unlimited (0s
). If idle_timeout
is specified, and timeout
is not explicitly set, then timeout
would be unlimited (0s
). You still may specify maximum lifetime of the connection using timeout
value (i.e. to 1 day).
Headers
Host Headers
The host
header can be preserved via the preserve_host_header
setting or customized via three mutually exclusive options:
-
preserve_host_header
will, when enabled, this option will pass the host header from the incoming request to the proxied host, instead of the destination hostname. It's an optional parameter of typebool
that defaults tofalse
.See ProxyPreserveHost.
-
host_rewrite
, which will rewrite the host to a new literal value. -
host_rewrite_header
, which will rewrite the host to match an incoming header value. -
host_path_regex_rewrite_pattern
&host_path_regex_rewrite_substitution
, which will rewrite the host according to a regex matching the path. For example with the following config:host_path_regex_rewrite_pattern: '^/(.+)/.+$'
host_path_regex_rewrite_substitution: \1Would rewrite the host header to
example.com
given the path/example.com/some/path
.
The 2nd, 3rd and 4th options correspond to the Envoy route action host related options, which can be found here.
Set Request Headers
Set Request Headers allows you to set static values for given request headers. This can be useful if you want to pass along additional information to downstream applications as headers, or set authentication header to the request. For example:
- from: https://verify.corp.example.com
to: https://verify.pomerium.com
policy:
- allow:
or:
- email:
is: user@example.com
set_request_headers:
# works auto-magically!
# https://verify.corp.example.com/basic-auth/root/hunter42
Authorization: Basic cm9vdDpodW50ZXI0Mg==
X-Your-favorite-authenticating-Proxy: 'Pomerium'
Neither :-prefixed
pseudo-headers nor the Host:
header may be modified via this mechanism. Those headers may instead be modified via mechanisms such as prefix_rewrite
, regex_rewrite
, and host_rewrite
.
Remove Request Headers
Remove Request Headers allows you to remove given request headers. This can be useful if you want to prevent privacy information from being passed to downstream applications. For example:
- from: https://verify.corp.example.com
to: https://verify.pomerium.com
policy:
- allow:
or:
- email:
is: user@example.com
remove_request_headers:
- X-Email
- X-Username
Rewrite Response Headers
Rewrite Response Headers allows you to modify response headers before they are returned to the client. The header
field will match the HTTP header name, and prefix
will be replaced with value
. For example, if the downstream server returns a header:
Location: http://localhost:8000/two/some/path/
And the policy has this config:
rewrite_response_headers:
- header: Location
prefix: http://localhost:8000/two/
value: http://frontend/one/
The browser would be redirected to: http://frontend/one/some/path/
. This is similar to nginx's proxy_redirect
option, but can be used for any header.
Load Balancer
Multiple Upstream Servers
You may specify multiple servers for your upstream application, and Pomerium would load balance user requests between them.
routes:
- from: https://myapp.localhost.pomerium.io
to:
- http://myapp-srv-1:8080
- http://myapp-srv-2:8080
In the presence of multiple upstream servers, make sure to specify either an active or passive health check, or both, to avoid requests being served to an unhealthy backend.
Active Health Checks
Active health checks issue periodic requests to each upstream to determine its health. See Health Checking for a comprehensive overview.
HTTP Example
routes:
- from: https://myapp.localhost.pomerium.io
to:
- http://myapp-srv-1:8080
- http://myapp-srv-2:8080
health_checks:
- timeout: 10s
interval: 60s
healthy_threshold: 1
unhealthy_threshold: 2
http_health_check:
path: '/'
TCP Example
routes:
- from: tcp+https://tcp-service.localhost.pomerium.io
to:
- tcp://tcp-1.local
- tcp://tcp-2.local
health_checks:
- timeout: 1s
interval: 5s
unhealthy_threshold: 3
healthy_threshold: 1
tcp_health_check:
send:
text: '50494E47' #PING
receive:
text: '504F4E47' #PONG
Passive Health Checks
Passive health check tries to deduce upstream server health based on recent observed responses. See Outlier Detection for comprehensive overview.
routes:
- from: https://myapp.localhost.pomerium.io
to:
- http://myapp-srv-1:8080
- http://myapp-srv-2:8080
outlier_detection: {}
Load Balancing Method
lb_policy
should be set to one of the values:
ROUND_ROBIN
(default)LEAST_REQUEST
and may be further configured usingleast_request_lb_config
RING_HASH
and may be further configured usingring_hash_lb_config
optionRANDOM
MAGLEV
and may be further configured usingmaglev_lb_config
option
Example
routes:
- from: https://myapp.localhost.pomerium.io
to:
- http://myapp-srv-1:8080
- http://myapp-srv-2:8080
- http://myapp-srv-3:8080
- http://myapp-srv-4:8080
- http://myapp-srv-5:8080
lb_policy: LEAST_REQUEST
least_request_lb_config:
choice_count: 2 # current envoy default
Load Balancing Weight
When a list of upstream URLs is specified in the to
field, you may append an optional load balancing weight parameter. The individual lb_policy
settings will take this weighting into account when making routing decisions.
Example
This configuration uses the default round_robin
load balancer policy but specifies different frequency of selection be applied to the upstream servers.
routes:
- from: https://myapp.localhost.pomerium.io
to:
- http://myapp-srv-1:8080,10
- http://myapp-srv-2:8080,20
- http://myapp-srv-3:8080,30
- http://myapp-srv-4:8080,20
- http://myapp-srv-5:8080,10
Route matching order
Pomerium matches routes in a specific order; an incoming request will be sent to the first route that matches.
Pomerium considers routes defined in a configuration file first, in the order in which they appear in the configuration file, followed by any routes defined in the Enterprise Console or by the Ingress Controller.
Routes from the Enterprise Console or Ingress Controller are sorted in the following order:
- Ascending by
host
- Descending by
path
- Descending by
regex
- Descending by
prefix
The example below defines two routes in a configuration file that both point to the same domain. The first route contains a prefix (api
).
If Pomerium receives a request to access https://a.example.com:8080
, Pomerium will first check https://a.example.com:8080/api
before matching the request with https://a.example.com:8080
.
- from: https://a.example.com:8080
to: http://example:8080
prefix: /api
allow_any_authenticated_user: true
- from: https://a.example.com:8080
to: http://example:8080
allow_any_authenticated_user: true
Further reading
Load Balancing Policy
In presence of multiple upstream servers, defines load balancing strategy between them.
See Envoy documentation for more details.
ROUND_ROBIN
(default)LEAST_REQUEST
and may be further configured usingleast_request_lb_config
RING_HASH
and may be further configured usingring_hash_lb_config
optionRANDOM
MAGLEV
and may be further configured usingmaglev_lb_config
option
Some policy types support additional configuration.
Certificates
Certificates are the x509 public-key and private-key used to establish secure HTTP and gRPC connections. Any combination of the above can be used together, and are additive. You can also use any of these settings in conjunction with Autocert
to get OCSP stapling.
Certificates loaded into Pomerium from these config values are used to attempt secure connections between end users and services, between Pomerium services, and to upstream endpoints.
For example, if specifying multiple certificates at once:
certificates:
- cert: '$HOME/.acme.sh/authenticate.example.com_ecc/fullchain.cer'
key: '$HOME/.acme.sh/authenticate.example.com_ecc/authenticate.example.com.key'
- cert: '$HOME/.acme.sh/verify.example.com_ecc/fullchain.cer'
key: '$HOME/.acme.sh/verify.example.com_ecc/verify.example.com.key'
- cert: '$HOME/.acme.sh/prometheus.example.com_ecc/fullchain.cer'
key: '$HOME/.acme.sh/prometheus.example.com_ecc/prometheus.example.com.key'
Or to set a single certificate and key covering multiple domains and/or a wildcard subdomain:
certificate_file: '$HOME/.acme.sh/*.example.com/fullchain.crt'
certificate_key: '$HOME/.acme.sh/*.example.com/*.example.com.key'
Note: Pomerium will check your system's trust/key store for valid certificates first. If your certificate solution imports into the system store, you don't need to also specify them with these configuration keys.