diff --git a/README.md b/README.md index cb7e5ef..947d94d 100644 --- a/README.md +++ b/README.md @@ -7,11 +7,12 @@ Inspired by [robszumski/k8s-service-proxy](https://github.com/robszumski/k8s-ser ## Configuration -Every proxy rule consist of three env variables: +Every proxy rule consist of three or four env variables: + `RULE_1_MODE`: <mode> + `RULE_1_PATTERN`: <regex pattern> (see [nginx regex names](http://nginx.org/en/docs/http/server_names.html#regex_names)) + `RULE_1_TARGET`: <target with usage of pattern variables> ++ `RULE_1_TARGET_HOST_HEADER`: <(Optional) modified host header, defaults to TARGET> Example: @@ -23,6 +24,7 @@ RULE_1_TARGET: 'https://$service.ab.example.com' RULE_2_MODE: 'HTTP' RULE_2_PATTERN: '(?.+).xy.127-0-0-1.nip.io' RULE_2_TARGET: 'https://$service.xy.example.com' +RULE_2_TARGET_HOST_HEADER: '$service.modified-host.example.com' ``` This creates two rules. @@ -31,7 +33,8 @@ The following example requests will get the shown proxy actions: + `http://hello.ab.127-0-0-1.nip.io` will proxy pass to `https://hello.ab.example.com` + `http://world.xy.127-0-0-1.nip.io` will proxy pass to - `https://world.xy.example.com` + `https://world.xy.example.com` + but send the host header `world.modified-host.example.com` > Currently only mode HTTP is implemented diff --git a/script/createConfigs.sh b/script/createConfigs.sh index 5ffe34b..706ed39 100755 --- a/script/createConfigs.sh +++ b/script/createConfigs.sh @@ -18,8 +18,9 @@ do eval mode='$RULE_'$ruleName'_MODE' eval pattern='$RULE_'$ruleName'_PATTERN' eval target='$RULE_'$ruleName'_TARGET' + eval targetHostHeader='$RULE_'$ruleName'_TARGET_HOST_HEADER' - echo "Configuring rule $ruleName, mode: $mode, pattern: $pattern, target: $target" + echo "Configuring rule $ruleName, mode: $mode, pattern: $pattern, target: $target, targetHostHeader: $targetHostHeader" if [[ "$mode" == "TLSPASS" ]]; then echo "MODE TLSPASS is not yet implemented" @@ -43,7 +44,11 @@ do file="/data/configs/http/http-$ruleName.conf" cp /data/templates/HTTP.conf $file sed -i "s|PATTERN|$pattern|g" $file - sed -i "s|TARGET|$target|g" $file + sed -i "s|TARGET_HOST_ADDRESS|$target|g" $file + if [ -z "$targetHostHeader" ]; then + targetHostHeader="\$proxy_host" + fi + sed -i "s|TARGET_HOST_HEADER|$targetHostHeader|g" $file sed -i "s|DNS_RESOLVER|$DNS_RESOLVER|g" $file fi diff --git a/templates/HTTP.conf b/templates/HTTP.conf index a53c44c..7033d4c 100644 --- a/templates/HTTP.conf +++ b/templates/HTTP.conf @@ -4,9 +4,10 @@ server { location / { resolver DNS_RESOLVER; - proxy_pass TARGET; + proxy_pass TARGET_HOST_ADDRESS; + proxy_set_header Host TARGET_HOST_HEADER; - # Replace TARGET in 303 redirects with current hostname and port (from clients request) - proxy_redirect TARGET $scheme://$http_host; + # Replace TARGET_HOST_ADDRESS in 303 redirects with current hostname and port (from clients request) + proxy_redirect TARGET_HOST_ADDRESS $scheme://$http_host; } } diff --git a/test/pom.xml b/test/pom.xml index 10472cd..587886f 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -30,7 +30,7 @@ org.testcontainers testcontainers - 1.14.2 + 1.15.2 test diff --git a/test/src/test/java/de/kekru/patternproxy/test/IntegrationTest.java b/test/src/test/java/de/kekru/patternproxy/test/IntegrationTest.java index 966dc25..114d6f7 100644 --- a/test/src/test/java/de/kekru/patternproxy/test/IntegrationTest.java +++ b/test/src/test/java/de/kekru/patternproxy/test/IntegrationTest.java @@ -5,6 +5,10 @@ import static org.mockserver.model.HttpRequest.request; import static org.mockserver.model.HttpResponse.response; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + import org.junit.Test; import org.mockserver.client.MockServerClient; import org.mockserver.model.MediaType; @@ -89,12 +93,52 @@ public void testRedirectReaplacesWithClientsRequestHostHeader() { } } + @Test + public void testUsingDifferentHostHeaders() { + Map additionalEnv = new HashMap<>(); + additionalEnv.put("RULE_1_TARGET_HOST_HEADER", "something-strange-$service-that-does-not-resolve"); + try ( + Network network = createNetwork(); + GenericContainer mockServerContainer = createMockServer(network); + GenericContainer patternProxyContainer = createPatternProxy(network, additionalEnv); + ) { + mockServerContainer.start(); + patternProxyContainer.start(); + patternProxyMappedPort = patternProxyContainer.getMappedPort(80); + mockServerMappedPort = mockServerContainer.getMappedPort(1090); + patternProxyContainer.followOutput(new Slf4jLogConsumer(LOG_PATTERN_PROXY)); + + + mockServerClient = new MockServerClient("localhost", mockServerMappedPort); + mockServerClient + .when(request() + .withMethod("GET") + .withHeader("Host", "something-strange-abc-that-does-not-resolve") + .withPath("/something")) + .respond(response() + .withStatusCode(200) + .withContentType(MediaType.JSON_UTF_8) + .withBody("{ \"message\": \"It Works, requested was something-strange-abc-that-does-not-resolve\" }")); + + given() + .when() + .redirects().follow(false) + .get("http://abc.pp.127-0-0-1.nip.io:" + patternProxyMappedPort + "/something") + .then() + .body("message", equalTo("It Works, requested was something-strange-abc-that-does-not-resolve")); + } + } + private Network createNetwork() { return Network.newNetwork(); } private GenericContainer createPatternProxy(Network network) { + return createPatternProxy(network, Collections.emptyMap()); + } + + private GenericContainer createPatternProxy(Network network, Map additionalEnv) { GenericContainer container = new GenericContainer("kekru/pattern-proxy:temp-for-unittests") .withNetwork(network) @@ -102,6 +146,7 @@ private GenericContainer createPatternProxy(Network network) { .withEnv("RULE_1_PATTERN", "(?.+).pp.127-0-0-1.nip.io") .withEnv("RULE_1_TARGET", "http://$service.mock-server:1090") .withEnv("DNS_RESOLVER", "127.0.0.11") // Internal Docker Network Resolver + .withEnv(additionalEnv) ; return container; }