Fixes #238 document RemoteAddressResolvers (#239)

document RemoteAddressResolvers

Fixes gh-238
This commit is contained in:
Andrew Fitzgerald
2018-04-06 14:27:43 -04:00
committed by Spencer Gibb
parent ed032f8d17
commit b6d9205265
2 changed files with 65 additions and 3 deletions

View File

@@ -225,7 +225,7 @@ This route would match if the request contained a `foo` query parameter whose va
=== RemoteAddr Route Predicate Factory
The RemoteAddr Route Predicate Factory takes a list (min size 1) of CIDR-notation (IPv4 or IPv6) strings, e.g. `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask.
The RemoteAddr Route Predicate Factory takes a list (min size 1) of CIDR-notation (IPv4 or IPv6) strings, e.g. `192.168.0.1/16` (where `192.168.0.1` is an IP address and `16` is a subnet mask).
.application.yml
[source,yaml]
@@ -242,7 +242,60 @@ spring:
This route would match if the remote address of the request was, for example, `192.168.1.10`.
==== Modifying the way remote addresses are resolved
By default the RemoteAddr Route Predicate Factory uses the remote address from the incoming request.
This may not match the actual client IP address if Spring Cloud Gateway sits behind a proxy layer.
You can customize the way that the remote address is resolved by setting a custom `RemoteAddressResolver`.
Spring Cloud Gateway comes with one non-default remote address resolver which is based off of the https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-For[X-Forwarded-For header], `XForwardedRemoteAddressResolver`.
`XForwardedRemoteAddressResolver` has two static constructor methods which take different approaches to security:
`XForwardedRemoteAddressResolver::trustAllXForwardedRemoteAddressResolver` returns a `RemoteAddressResolver` which always takes the first IP address found in the `X-Forwarded-For` header.
This approach is vulnerable to spoofing, as a malicious client could set an initial value for the `X-Forwarded-For` which would be accepted by the resolver.
`XForwardedRemoteAddressResolver::maxTrustedIndexXForwardedRemoteAddressResolver` takes an index which correlates to the number of trusted infrastructure running in front of Spring Cloud Gateway.
If Spring Cloud Gateway is, for example only accessible via HAProxy, then a value of 1 should be used.
If two hops of trusted infrastructure are required before Spring Cloud Gateway is accessible, then a value of 2 should be used.
Given the following header value:
[source]
X-Forwarded-For: 0.0.0.1, 0.0.0.2, 0.0.0.3
The `maxTrustedIndex` values below will yield the following remote addresses.
[options="header"]
|===
|`maxTrustedIndex` | result
|[`Integer.MIN_VALUE`,0] | (invalid, `IllegalArgumentException` during initialization)
|1 | 0.0.0.3
|2 | 0.0.0.2
|3 | 0.0.0.1
|[4, `Integer.MAX_VALUE`] | 0.0.0.1
|===
[[gateway-route-filters]]
Using Java config:
GatewayConfig.java
[source,java]
----
RemoteAddressResolver resolver = XForwardedRemoteAddressResolver
.maxTrustedIndexXForwardedRemoteAddressResolver(1);
...
.route("direct-route",
r -> r.remoteAddr("10.1.1.1", "10.10.1.1/24")
.uri("https://downstream1")
.route("proxied-route",
r -> r.remoteAddr(resolver, "10.10.1.1", "10.10.1.1/24")
.uri("https://downstream2")
)
----
== GatewayFilter Factories
Route filters allow the modification of the incoming HTTP request or outgoing HTTP response in some manner. Route filters are scoped to a particular route. Spring Cloud Gateway includes many built-in GatewayFilter Factories.

View File

@@ -31,6 +31,7 @@ import org.springframework.cloud.gateway.handler.predicate.QueryRoutePredicateFa
import org.springframework.cloud.gateway.handler.predicate.RemoteAddrRoutePredicateFactory;
import org.springframework.cloud.gateway.handler.predicate.WeightRoutePredicateFactory;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.cloud.gateway.support.ipresolver.RemoteAddressResolver;
import org.springframework.http.HttpMethod;
import org.springframework.web.server.ServerWebExchange;
@@ -114,8 +115,16 @@ public class PredicateSpec extends UriSpec {
}
public BooleanSpec remoteAddr(String... addrs) {
return predicate(getBean(RemoteAddrRoutePredicateFactory.class)
.apply(c -> c.setSources(addrs)));
return remoteAddr(null, addrs);
}
public BooleanSpec remoteAddr(RemoteAddressResolver resolver, String... addrs) {
return predicate(getBean(RemoteAddrRoutePredicateFactory.class).apply(c -> {
c.setSources(addrs);
if (resolver != null) {
c.setRemoteAddressResolver(resolver);
}
}));
}
public BooleanSpec weight(String group, int weight) {