linkerd2/proxy-init/integration_test/iptables/http_test.go

217 lines
8.2 KiB
Go

package iptablestest
import (
"flag"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"os"
"strings"
"testing"
)
const (
ignoredContainerPort = "7070"
proxyContainerPort = "8080"
notTheProxyContainerPort = "9090"
)
func TestMain(m *testing.M) {
runTests := flag.Bool("integration-tests", false, "must be provided to run the integration tests")
flag.Parse()
if !*runTests {
fmt.Fprintln(os.Stderr, "integration tests not enabled: enable with -integration-tests")
os.Exit(0)
}
os.Exit(m.Run())
}
func TestPodWithNoRules(t *testing.T) {
t.Parallel()
podWithNoRulesIP := os.Getenv("POD_WITH_NO_RULES_IP")
svcName := "svc-pod-with-no-rules"
t.Run("succeeds connecting to pod directly through container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podWithNoRulesIP, proxyContainerPort)
})
t.Run("fails to connect to pod directly through any port that isn't the container's exposed port", func(t *testing.T) {
expectCannotConnectGetRequestTo(t, podWithNoRulesIP, "8088")
expectCannotConnectGetRequestTo(t, podWithNoRulesIP, "8888")
expectCannotConnectGetRequestTo(t, podWithNoRulesIP, "8988")
})
t.Run("succeeds connecting to pod via a service through container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, svcName, proxyContainerPort)
})
t.Run("fails to connect to pod via a service through any port that isn't the container's exposed port", func(t *testing.T) {
expectCannotConnectGetRequestTo(t, svcName, "8088")
expectCannotConnectGetRequestTo(t, svcName, "8888")
expectCannotConnectGetRequestTo(t, svcName, "8988")
})
}
func TestPodRedirectsAllPorts(t *testing.T) {
t.Parallel()
podRedirectsAllPortsIP := os.Getenv("POD_REDIRECTS_ALL_PORTS_IP")
svcName := "svc-pod-redirects-all-ports"
t.Run("succeeds connecting to pod directly through container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podRedirectsAllPortsIP, proxyContainerPort)
})
t.Run("succeeds connecting to pod directly through any port that isn't the container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podRedirectsAllPortsIP, "8088")
expectSuccessfulGetRequestTo(t, podRedirectsAllPortsIP, "8888")
expectSuccessfulGetRequestTo(t, podRedirectsAllPortsIP, "8988")
})
t.Run("succeeds connecting to pod via a service through container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, svcName, proxyContainerPort)
})
t.Run("fails to connect to pod via a service through any port that isn't the container's exposed port", func(t *testing.T) {
expectCannotConnectGetRequestTo(t, svcName, "8088")
expectCannotConnectGetRequestTo(t, svcName, "8888")
expectCannotConnectGetRequestTo(t, svcName, "8988")
})
}
func TestPodWithSomePortsRedirected(t *testing.T) {
t.Parallel()
podRedirectsSomePortsIP := os.Getenv("POD_REDIRECTS_WHITELISTED_IP")
t.Run("succeeds connecting to pod directly through container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podRedirectsSomePortsIP, proxyContainerPort)
})
t.Run("succeeds connecting to pod directly through ports configured to redirect", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podRedirectsSomePortsIP, "9090")
expectSuccessfulGetRequestTo(t, podRedirectsSomePortsIP, "9099")
})
t.Run("fails to connect to pod via through any port that isn't configured to redirect", func(t *testing.T) {
expectCannotConnectGetRequestTo(t, podRedirectsSomePortsIP, "8088")
expectCannotConnectGetRequestTo(t, podRedirectsSomePortsIP, "8888")
expectCannotConnectGetRequestTo(t, podRedirectsSomePortsIP, "8988")
})
}
func TestPodWithSomePortsIgnored(t *testing.T) {
t.Parallel()
podIgnoredSomePortsIP := os.Getenv("POD_DOEST_REDIRECT_BLACKLISTED_IP")
t.Run("succeeds connecting to pod directly through container's exposed port", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podIgnoredSomePortsIP, proxyContainerPort)
})
t.Run("succeeds connecting to pod directly through ports configured to redirect", func(t *testing.T) {
expectSuccessfulGetRequestTo(t, podIgnoredSomePortsIP, "9090")
expectSuccessfulGetRequestTo(t, podIgnoredSomePortsIP, "9099")
})
t.Run("doesnt redirect when through port that is ignored", func(t *testing.T) {
response := expectSuccessfulGetRequestTo(t, podIgnoredSomePortsIP, ignoredContainerPort)
if response == "proxy" {
t.Fatalf("Expected connection through ignored port to directly hit service, but hit [%s]", response)
}
if !strings.Contains(response, ignoredContainerPort) {
t.Fatalf("Expected to be able to connect to %s without redirects, but got back %s", ignoredContainerPort, response)
}
})
}
func TestPodMakesOutboundConnection(t *testing.T) {
t.Parallel()
podIgnoredSomePortsIP := os.Getenv("POD_DOEST_REDIRECT_BLACKLISTED_IP")
podWithNoRulesIP := os.Getenv("POD_WITH_NO_RULES_IP")
podWithNoRulesName := "pod-with-no-rules"
proxyPodName := "pod-doesnt-redirect-blacklisted"
proxyPodIP := podIgnoredSomePortsIP
t.Run("connecting to another pod from non-proxy container gets redirected to proxy", func(t *testing.T) {
portOfContainerToMAkeTheRequest := ignoredContainerPort
targetPodIP := podWithNoRulesIP
targetPort := ignoredContainerPort
response := makeCallFromContainerToAnother(t, proxyPodIP, portOfContainerToMAkeTheRequest, targetPodIP, targetPort)
expectedDownstreamResponse := fmt.Sprintf("me:[%s:%s]downstream:[proxy]", proxyPodName, portOfContainerToMAkeTheRequest)
if !strings.Contains(response, expectedDownstreamResponse) {
t.Fatalf("Expected response to be redirected to the proxy, expected %s but it was %s", expectedDownstreamResponse, response)
}
})
t.Run("connecting to another pod from proxy container does not get redirected to proxy", func(t *testing.T) {
targetPodName := podWithNoRulesName
targetPodIP := podWithNoRulesIP
response := makeCallFromContainerToAnother(t, proxyPodIP, proxyContainerPort, targetPodIP, notTheProxyContainerPort)
expectedDownstreamResponse := fmt.Sprintf("me:[proxy]downstream:[%s:%s]", targetPodName, notTheProxyContainerPort)
if !strings.Contains(response, expectedDownstreamResponse) {
t.Fatalf("Expected response not to be redirected to the proxy, expected %s but it was %s", expectedDownstreamResponse, response)
}
})
t.Run("connecting to loopback from non-proxy container does not get redirected to proxy", func(t *testing.T) {
response := makeCallFromContainerToAnother(t, proxyPodIP, ignoredContainerPort, "127.0.0.1", notTheProxyContainerPort)
expectedDownstreamResponse := fmt.Sprintf("me:[%s:%s]downstream:[%s:%s]", proxyPodName, ignoredContainerPort, proxyPodName, notTheProxyContainerPort)
if !strings.Contains(response, expectedDownstreamResponse) {
t.Fatalf("Expected response not to be redirected to the proxy, expected %s but it was %s", expectedDownstreamResponse, response)
}
})
}
func makeCallFromContainerToAnother(t *testing.T, fromPodNamed string, fromContainerAtPort string, podIWantToReachName string, containerPortIWantToReach string) string {
downstreamURL := fmt.Sprintf("http://%s:%s", podIWantToReachName, containerPortIWantToReach)
//Make request asking target to make a back-end request
targetURL := fmt.Sprintf("http://%s:%s/call?url=%s", fromPodNamed, fromContainerAtPort, url.QueryEscape(downstreamURL))
return expectSuccessfulGetRequestToURL(t, targetURL)
}
func expectCannotConnectGetRequestTo(t *testing.T, host string, port string) {
targetURL := fmt.Sprintf("http://%s:%s/", host, port)
fmt.Printf("Expecting failed GET to %s\n", targetURL)
resp, err := http.Get(targetURL)
if err == nil {
t.Fatalf("Expected error when connecting to %s, got:\n%+v", targetURL, resp)
}
}
func expectSuccessfulGetRequestTo(t *testing.T, host string, port string) string {
targetURL := fmt.Sprintf("http://%s:%s/", host, port)
return expectSuccessfulGetRequestToURL(t, targetURL)
}
func expectSuccessfulGetRequestToURL(t *testing.T, url string) string {
fmt.Printf("Expecting successful GET to %s\n", url)
resp, err := http.Get(url)
if err != nil {
t.Fatalf("failed to send HTTP GET to %s:\n%v", url, err)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("failed reading GET response from %s:\n%v", url, err)
}
response := string(body)
fmt.Printf("Response from %s: %s", url, response)
return response
}