Skip to content

Commit

Permalink
Adding a test of TCP with TLS termination (test-only change) (envoypr…
Browse files Browse the repository at this point in the history
  • Loading branch information
alyssawilk authored and mattklein123 committed Jul 5, 2017
1 parent b555e24 commit d961183
Show file tree
Hide file tree
Showing 14 changed files with 456 additions and 86 deletions.
1 change: 1 addition & 0 deletions test/config/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ exports_files([
"server_ssl.json",
"server_uds.json",
"server_xfcc.json",
"tcp_proxy.json",
])

filegroup(
Expand Down
74 changes: 74 additions & 0 deletions test/config/integration/tcp_proxy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
{
"listeners": [
{
"address": "tcp://{{ ip_loopback_address }}:0",
"filters": [
{ "type": "read", "name":
"tcp_proxy",
"config": {
"stat_prefix": "test_tcp",
"route_config": {
"routes": [
{
"cluster": "cluster_1"
}
]
}
}
}
]
},
{
"address": "tcp://{{ ip_loopback_address }}:0",
"ssl_context": {
"ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem",
"cert_chain_file": "{{ test_rundir }}/test/config/integration/certs/servercert.pem",
"private_key_file": "{{ test_rundir }}/test/config/integration/certs/serverkey.pem",
"alpn_protocols": "h2,http/1.1",
"alt_alpn_protocols": "http/1.1"
},
"filters": [
{ "type": "read", "name": "tcp_proxy",
"config": {
"stat_prefix": "test_tcp_sans_tls",
"route_config": {
"routes": [
{
"cluster": "cluster_1"
}
]
}
}
},
{ "type": "read", "name": "client_ssl_auth",
"config": {
"auth_api_cluster": "ssl_auth",
"stat_prefix": "ssl_stats",
"refresh_delay_ms": 600000,
"ip_white_list": [ "127.0.0.1/32", "::1/64"]
}
}
]
}],
"admin": { "access_log_path": "/dev/null", "address": "tcp://{{ ip_loopback_address }}:0" },
"statsd_udp_ip_address": "{{ ip_loopback_address }}:8125",

"cluster_manager": {
"clusters": [
{
"name": "cluster_1",
"connect_timeout_ms": 5000,
"type": "static",
"lb_type": "round_robin",
"hosts": [{"url": "tcp://{{ ip_loopback_address }}:{{ upstream_0 }}"}]
},
{
"name": "ssl_auth",
"connect_timeout_ms": 5000,
"type": "strict_dns",
"lb_type": "round_robin",
"dns_lookup_family": "{{ dns_lookup_family }}",
"hosts": [{"url": "tcp://localhost:{{ upstream_1 }}"}]
}]
}
}
30 changes: 25 additions & 5 deletions test/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,14 @@ envoy_cc_test_library(
"fake_upstream.cc",
"integration.cc",
"server.cc",
"ssl_utility.cc",
"utility.cc",
],
hdrs = [
"fake_upstream.h",
"integration.h",
"server.h",
"ssl_utility.h",
"utility.h",
],
data = ["//test/common/runtime:filesystem_test_data"],
Expand Down Expand Up @@ -235,14 +237,14 @@ envoy_cc_test(
)

envoy_cc_test(
name = "xfcc_integration_test",
name = "tcp_proxy_integration_test",
srcs = [
"ssl_integration_test.h",
"xfcc_integration_test.cc",
"xfcc_integration_test.h",
"tcp_proxy_integration_test.cc",
"tcp_proxy_integration_test.h",
],
data = [
"//test/config/integration:server_xfcc.json",
"//test/config/integration:server_config_files",
"//test/config/integration:tcp_proxy.json",
"//test/config/integration/certs",
],
deps = [
Expand All @@ -256,6 +258,24 @@ envoy_cc_test(
],
)

envoy_cc_test(
name = "xfcc_integration_test",
srcs = [
"ssl_integration_test.h",
"xfcc_integration_test.cc",
"xfcc_integration_test.h",
],
data = [
"//test/config/integration:server_xfcc.json",
"//test/config/integration/certs",
],
deps = [
":integration_lib",
"//source/common/http:header_map_lib",
"//test/test_common:utility_lib",
],
)

envoy_cc_test(
name = "uds_integration_test",
srcs = [
Expand Down
20 changes: 5 additions & 15 deletions test/integration/integration.cc
Original file line number Diff line number Diff line change
Expand Up @@ -178,22 +178,23 @@ void IntegrationCodecClient::ConnectionCallbacks::onEvent(uint32_t events) {

IntegrationTcpClient::IntegrationTcpClient(Event::Dispatcher& dispatcher, uint32_t port,
Network::Address::IpVersion version)
: callbacks_(new ConnectionCallbacks(*this)) {
: payload_reader_(new WaitForPayloadReader(dispatcher)),
callbacks_(new ConnectionCallbacks(*this)) {
connection_ = dispatcher.createClientConnection(Network::Utility::resolveUrl(
fmt::format("tcp://{}:{}", Network::Test::getLoopbackAddressUrlString(version), port)));
connection_->addConnectionCallbacks(*callbacks_);
connection_->addReadFilter(callbacks_);
connection_->addReadFilter(payload_reader_);
connection_->connect();
}

void IntegrationTcpClient::close() { connection_->close(Network::ConnectionCloseType::NoFlush); }

void IntegrationTcpClient::waitForData(const std::string& data) {
if (data_.find(data) == 0) {
if (payload_reader_->data().find(data) == 0) {
return;
}

data_to_wait_for_ = data;
payload_reader_->set_data_to_wait_for(data);
connection_->dispatcher().run(Event::Dispatcher::RunType::Block);
}

Expand All @@ -209,17 +210,6 @@ void IntegrationTcpClient::write(const std::string& data) {
// NOTE: We should run blocking until all the body data is flushed.
}

Network::FilterStatus IntegrationTcpClient::ConnectionCallbacks::onData(Buffer::Instance& data) {
parent_.data_.append(TestUtility::bufferToString(data));
data.drain(data.length());
if (!parent_.data_to_wait_for_.empty() && parent_.data_.find(parent_.data_to_wait_for_) == 0) {
parent_.data_to_wait_for_.clear();
parent_.connection_->dispatcher().exit();
}

return Network::FilterStatus::StopIteration;
}

void IntegrationTcpClient::ConnectionCallbacks::onEvent(uint32_t events) {
if (events == Network::ConnectionEvent::RemoteClose) {
parent_.disconnected_ = true;
Expand Down
12 changes: 4 additions & 8 deletions test/integration/integration.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

#include "test/integration/fake_upstream.h"
#include "test/integration/server.h"
#include "test/integration/utility.h"
#include "test/test_common/environment.h"
#include "test/test_common/printers.h"

Expand Down Expand Up @@ -119,30 +120,25 @@ class IntegrationTcpClient {
Network::Address::IpVersion version);

void close();
const std::string& data() { return data_; }
void waitForData(const std::string& data);
void waitForDisconnect();
void write(const std::string& data);
const std::string& data() { return payload_reader_->data(); }

private:
struct ConnectionCallbacks : public Network::ConnectionCallbacks,
public Network::ReadFilterBaseImpl {
struct ConnectionCallbacks : public Network::ConnectionCallbacks {
ConnectionCallbacks(IntegrationTcpClient& parent) : parent_(parent) {}

// Network::ConnectionCallbacks
void onEvent(uint32_t events) override;

// Network::ReadFilter
Network::FilterStatus onData(Buffer::Instance& data) override;

IntegrationTcpClient& parent_;
};

std::shared_ptr<WaitForPayloadReader> payload_reader_;
std::shared_ptr<ConnectionCallbacks> callbacks_;
Network::ClientConnectionPtr connection_;
bool disconnected_{};
std::string data_;
std::string data_to_wait_for_;
};

typedef std::unique_ptr<IntegrationTcpClient> IntegrationTcpClientPtr;
Expand Down
41 changes: 40 additions & 1 deletion test/integration/server.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,45 @@ class TestComponentFactory : public ComponentFactory {

namespace Stats {

/**
* This is a wrapper for Scopes for the TestIsolatedStoreImpl to ensure new scopes do
* not interact with the store without grabbing the lock from TestIsolatedStoreImpl.
*/
class TestScopeWrapper : public Scope {
public:
TestScopeWrapper(std::mutex& lock, ScopePtr wrapped_scope)
: lock_(lock), wrapped_scope_(std::move(wrapped_scope)) {}

void deliverHistogramToSinks(const std::string& name, uint64_t value) override {
std::unique_lock<std::mutex> lock(lock_);
wrapped_scope_->deliverHistogramToSinks(name, value);
}

void deliverTimingToSinks(const std::string& name, std::chrono::milliseconds ms) override {
std::unique_lock<std::mutex> lock(lock_);
wrapped_scope_->deliverTimingToSinks(name, ms);
}

Counter& counter(const std::string& name) override {
std::unique_lock<std::mutex> lock(lock_);
return wrapped_scope_->counter(name);
}

Gauge& gauge(const std::string& name) override {
std::unique_lock<std::mutex> lock(lock_);
return wrapped_scope_->gauge(name);
}

Timer& timer(const std::string& name) override {
std::unique_lock<std::mutex> lock(lock_);
return wrapped_scope_->timer(name);
}

private:
std::mutex& lock_;
ScopePtr wrapped_scope_;
};

/**
* This is a variant of the isolated store that has locking across all operations so that it can
* be used during the integration tests.
Expand Down Expand Up @@ -111,7 +150,7 @@ class TestIsolatedStoreImpl : public StoreRoot {
}
ScopePtr createScope(const std::string& name) override {
std::unique_lock<std::mutex> lock(lock_);
return store_.createScope(name);
return ScopePtr{new TestScopeWrapper(lock_, store_.createScope(name))};
}

// Stats::StoreRoot
Expand Down
62 changes: 6 additions & 56 deletions test/integration/ssl_integration_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "common/ssl/context_config_impl.h"
#include "common/ssl/context_manager_impl.h"

#include "test/integration/ssl_utility.h"
#include "test/test_common/network_utility.h"

#include "gmock/gmock.h"
Expand Down Expand Up @@ -36,10 +37,10 @@ void SslIntegrationTest::SetUp() {
version_),
version_);
registerTestServerPorts({"http"});
client_ssl_ctx_plain_ = createClientSslContext(false, false);
client_ssl_ctx_alpn_ = createClientSslContext(true, false);
client_ssl_ctx_san_ = createClientSslContext(false, true);
client_ssl_ctx_alpn_san_ = createClientSslContext(true, true);
client_ssl_ctx_plain_ = createClientSslContext(false, false, *context_manager_);
client_ssl_ctx_alpn_ = createClientSslContext(true, false, *context_manager_);
client_ssl_ctx_san_ = createClientSslContext(false, true, *context_manager_);
client_ssl_ctx_alpn_san_ = createClientSslContext(true, true, *context_manager_);
}

void SslIntegrationTest::TearDown() {
Expand Down Expand Up @@ -68,59 +69,8 @@ ServerContextPtr SslIntegrationTest::createUpstreamSslContext() {
return context_manager_->createSslServerContext(*upstream_stats_store, cfg);
}

ClientContextPtr SslIntegrationTest::createClientSslContext(bool alpn, bool san) {
std::string json_plain = R"EOF(
{
"ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem",
"cert_chain_file": "{{ test_rundir }}/test/config/integration/certs/clientcert.pem",
"private_key_file": "{{ test_rundir }}/test/config/integration/certs/clientkey.pem"
}
)EOF";

std::string json_alpn = R"EOF(
{
"ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem",
"cert_chain_file": "{{ test_rundir }}/test/config/integration/certs/clientcert.pem",
"private_key_file": "{{ test_rundir }}/test/config/integration/certs/clientkey.pem",
"alpn_protocols": "h2,http/1.1"
}
)EOF";

std::string json_san = R"EOF(
{
"ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem",
"cert_chain_file": "{{ test_rundir }}/test/config/integration/certs/clientcert.pem",
"private_key_file": "{{ test_rundir }}/test/config/integration/certs/clientkey.pem",
"verify_subject_alt_name": [ "spiffe://lyft.com/backend-team" ]
}
)EOF";

std::string json_alpn_san = R"EOF(
{
"ca_cert_file": "{{ test_rundir }}/test/config/integration/certs/cacert.pem",
"cert_chain_file": "{{ test_rundir }}/test/config/integration/certs/clientcert.pem",
"private_key_file": "{{ test_rundir }}/test/config/integration/certs/clientkey.pem",
"alpn_protocols": "h2,http/1.1",
"verify_subject_alt_name": [ "spiffe://lyft.com/backend-team" ]
}
)EOF";

std::string target;
if (alpn) {
target = san ? json_alpn_san : json_alpn;
} else {
target = san ? json_san : json_plain;
}
Json::ObjectSharedPtr loader = TestEnvironment::jsonLoadFromString(target);
ContextConfigImpl cfg(*loader);
static auto* client_stats_store = new Stats::TestIsolatedStoreImpl();
return context_manager_->createSslClientContext(*client_stats_store, cfg);
}

Network::ClientConnectionPtr SslIntegrationTest::makeSslClientConnection(bool alpn, bool san) {
Network::Address::InstanceConstSharedPtr address =
Network::Utility::resolveUrl("tcp://" + Network::Test::getLoopbackAddressUrlString(version_) +
":" + std::to_string(lookupPort("http")));
Network::Address::InstanceConstSharedPtr address = getSslAddress(version_, lookupPort("http"));
if (alpn) {
return dispatcher_->createSslClientConnection(
san ? *client_ssl_ctx_alpn_san_ : *client_ssl_ctx_alpn_, address);
Expand Down
1 change: 0 additions & 1 deletion test/integration/ssl_integration_test.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ class SslIntegrationTest : public BaseIntegrationTest,

Network::ClientConnectionPtr makeSslClientConnection(bool alpn, bool san);
ServerContextPtr createUpstreamSslContext();
ClientContextPtr createClientSslContext(bool alpn, bool san);
void checkStats();

private:
Expand Down
Loading

0 comments on commit d961183

Please sign in to comment.