Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions test/config/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ exports_files([
"server_proxy_proto.json",
"server_ssl.json",
"server_uds.json",
"tcp_proxy.json",
])

filegroup(
Expand Down
75 changes: 75 additions & 0 deletions test/config/integration/tcp_proxy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
{
"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",
"verify_certificate_hash": "75:1D:5F:48:82:7E:30:1D:06:33:EC:B2:88:E3:22:5F:D0:48:D8:F2:D4:F8:7F:A9:89:7F:7E:AF:8F:89:AB:D0",
"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 }}"}]
}]
}
}
20 changes: 20 additions & 0 deletions test/integration/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,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 @@ -214,6 +216,24 @@ envoy_cc_test(
],
)

envoy_cc_test(
name = "tcp_proxy_integration_test",
srcs = [
"tcp_proxy_integration_test.cc",
"tcp_proxy_integration_test.h",
],
data = [
"//test/config/integration:server_config_files",
"//test/config/integration:tcp_proxy.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
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": [ "istio:account_a.namespace_foo.cluster.local" ]
}
)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": [ "istio:account_a.namespace_foo.cluster.local" ]
}
)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
72 changes: 72 additions & 0 deletions test/integration/ssl_utility.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "test/integration/ssl_utility.h"

#include "common/json/json_loader.h"
#include "common/network/utility.h"
#include "common/ssl/context_config_impl.h"
#include "common/ssl/context_manager_impl.h"

#include "test/integration/server.h"
#include "test/test_common/environment.h"
#include "test/test_common/network_utility.h"

namespace Envoy {
namespace Ssl {

ClientContextPtr createClientSslContext(bool alpn, bool san, ContextManager& context_manager) {
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": [ "istio:account_a.namespace_foo.cluster.local" ]
}
)EOF";

std::string json_alpn_san = R"EOF(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const, etc. above

{
"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": [ "istio:account_a.namespace_foo.cluster.local" ]
}
)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);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@myidpt Can you rebase #1087 on this when it merges and generalize this utility function to allow reuse in your PR? If that works, we could reduce some of the boiler plate.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If so, I will need to change this function to support TLS (non-mTLS) case as well. In terms of refactoring, I think it's better we have this PR focusing on it (and probably we can do it better here :) ).

}

Network::Address::InstanceConstSharedPtr getSslAddress(Network::Address::IpVersion version,
int port) {
std::string url =

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a general preference, prefer const for any intermediate variable that is const.

"tcp://" + Network::Test::getLoopbackAddressUrlString(version) + ":" + std::to_string(port);
return Network::Utility::resolveUrl(url);
}

} // Ssl
} // Envoy
15 changes: 15 additions & 0 deletions test/integration/ssl_utility.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once

#include "envoy/network/address.h"
#include "envoy/ssl/context_manager.h"

namespace Envoy {
namespace Ssl {

ClientContextPtr createClientSslContext(bool alpn, bool san, ContextManager& context_manager);

Network::Address::InstanceConstSharedPtr getSslAddress(Network::Address::IpVersion version,
int port);

} // Ssl
} // Envoy
Loading