From 1939596cf56b7b0bd914665437363c8e32b07ca7 Mon Sep 17 00:00:00 2001 From: Kuat Yessenov Date: Mon, 30 Sep 2019 13:10:01 -0700 Subject: [PATCH] add upstream tls info Signed-off-by: Kuat Yessenov --- include/istio/control/http/report_data.h | 6 ++++ include/istio/control/tcp/report_data.h | 5 ++++ include/istio/utils/attribute_names.h | 2 ++ src/envoy/http/mixer/report_data.h | 8 ++++++ src/envoy/tcp/mixer/filter.cc | 11 ++++++++ src/envoy/tcp/mixer/filter.h | 2 ++ src/envoy/utils/utils.cc | 5 ++++ src/envoy/utils/utils.h | 5 +++- src/istio/control/http/attributes_builder.cc | 8 ++++++ .../control/http/attributes_builder_test.cc | 22 +++++++++++++++ src/istio/control/http/mock_report_data.h | 2 ++ .../control/http/request_handler_impl_test.cc | 11 ++++++++ src/istio/control/tcp/attributes_builder.cc | 9 ++++++ .../control/tcp/attributes_builder_test.cc | 28 +++++++++++++++++++ src/istio/control/tcp/mock_report_data.h | 2 ++ .../control/tcp/request_handler_impl_test.cc | 7 +++++ src/istio/utils/attribute_names.cc | 2 ++ 17 files changed, 134 insertions(+), 1 deletion(-) diff --git a/include/istio/control/http/report_data.h b/include/istio/control/http/report_data.h index dac9998a77e..a6fc864a8fa 100644 --- a/include/istio/control/http/report_data.h +++ b/include/istio/control/http/report_data.h @@ -74,6 +74,12 @@ class ReportData { // Useful for logging info generated by custom codecs. virtual const ::google::protobuf::Map &GetDynamicFilterState() const = 0; + + // Get upstream mTLS status. + virtual bool IsUpstreamMutualTLS() const = 0; + + // Get upstream failure reason. + virtual const std::string &GetUpstreamFailureReason() const = 0; }; } // namespace http diff --git a/include/istio/control/tcp/report_data.h b/include/istio/control/tcp/report_data.h index 91a6b7241c0..8b0fc27bdbb 100644 --- a/include/istio/control/tcp/report_data.h +++ b/include/istio/control/tcp/report_data.h @@ -58,6 +58,11 @@ class ReportData { virtual const ::google::protobuf::Map<::std::string, ::google::protobuf::Struct> &GetDynamicFilterState() const = 0; + + // Get upstream mTLS status. + virtual bool IsUpstreamMutualTLS() const = 0; + + virtual const std::string &GetUpstreamFailureReason() const = 0; }; } // namespace tcp diff --git a/include/istio/utils/attribute_names.h b/include/istio/utils/attribute_names.h index 5c6f4b249c9..a9f793f7aee 100644 --- a/include/istio/utils/attribute_names.h +++ b/include/istio/utils/attribute_names.h @@ -81,6 +81,8 @@ struct AttributeName { static const char kConnectionId[]; // Record TCP connection status: open, continue, close static const char kConnectionEvent[]; + static const char kUpstreamMtls[]; + static const char kUpstreamFailureReason[]; // Context attributes static const char kContextProtocol[]; diff --git a/src/envoy/http/mixer/report_data.h b/src/envoy/http/mixer/report_data.h index 84b18f2468e..8a0d4a164a1 100644 --- a/src/envoy/http/mixer/report_data.h +++ b/src/envoy/http/mixer/report_data.h @@ -175,6 +175,14 @@ class ReportData : public ::istio::control::http::ReportData, &GetDynamicFilterState() const override { return info_.dynamicMetadata().filter_metadata(); } + + bool IsUpstreamMutualTLS() const override { + return Utils::IsUpstreamMutualTLS(info_); + } + + const std::string &GetUpstreamFailureReason() const override { + return info_.upstreamTransportFailureReason(); + } }; } // namespace Mixer diff --git a/src/envoy/tcp/mixer/filter.cc b/src/envoy/tcp/mixer/filter.cc index 34d7a1ac8f5..cdf651f3a88 100644 --- a/src/envoy/tcp/mixer/filter.cc +++ b/src/envoy/tcp/mixer/filter.cc @@ -247,6 +247,17 @@ std::string Filter::GetConnectionId() const { return uuid_connection_id; } +bool Filter::IsUpstreamMutualTLS() const { + return Utils::IsUpstreamMutualTLS( + filter_callbacks_->connection().streamInfo()); +} + +const std::string &Filter::GetUpstreamFailureReason() const { + return filter_callbacks_->connection() + .streamInfo() + .upstreamTransportFailureReason(); +} + void Filter::OnReportTimer() { handler_->Report(this, ConnectionEvent::CONTINUE); clearCachedFilterMetadata(); diff --git a/src/envoy/tcp/mixer/filter.h b/src/envoy/tcp/mixer/filter.h index cf59f1cdb88..f15ed56a46f 100644 --- a/src/envoy/tcp/mixer/filter.h +++ b/src/envoy/tcp/mixer/filter.h @@ -65,6 +65,8 @@ class Filter : public Network::Filter, void GetReportInfo( ::istio::control::tcp::ReportData::ReportInfo *data) const override; std::string GetConnectionId() const override; + bool IsUpstreamMutualTLS() const override; + const std::string &GetUpstreamFailureReason() const override; void cacheFilterMetadata( const ::google::protobuf::Map diff --git a/src/envoy/utils/utils.cc b/src/envoy/utils/utils.cc index 7b0f4192817..6d45fafb4fb 100644 --- a/src/envoy/utils/utils.cc +++ b/src/envoy/utils/utils.cc @@ -178,6 +178,11 @@ bool IsMutualTLS(const Network::Connection* connection) { connection->ssl()->peerCertificatePresented(); } +bool IsUpstreamMutualTLS(const StreamInfo::StreamInfo& stream_info) { + const auto ssl = stream_info.upstreamSslConnection(); + return ssl != nullptr && ssl->peerCertificatePresented(); +} + bool GetRequestedServerName(const Network::Connection* connection, std::string* name) { if (connection && !connection->requestedServerName().empty()) { diff --git a/src/envoy/utils/utils.h b/src/envoy/utils/utils.h index 7b11056cc39..21fa69760fb 100644 --- a/src/envoy/utils/utils.h +++ b/src/envoy/utils/utils.h @@ -52,9 +52,12 @@ bool GetPrincipal(const Network::Connection* connection, bool peer, bool GetTrustDomain(const Network::Connection* connection, bool peer, std::string* trust_domain); -// Returns true if connection is mutual TLS enabled. +// Returns true if downstream connection is mutual TLS enabled. bool IsMutualTLS(const Network::Connection* connection); +// Returns true if upstream connection is mutual TLS enabled. +bool IsUpstreamMutualTLS(const StreamInfo::StreamInfo& stream_info); + // Get requested server name, SNI in case of TLS bool GetRequestedServerName(const Network::Connection* connection, std::string* name); diff --git a/src/istio/control/http/attributes_builder.cc b/src/istio/control/http/attributes_builder.cc index 8c3fc539a06..66da09d6e75 100644 --- a/src/istio/control/http/attributes_builder.cc +++ b/src/istio/control/http/attributes_builder.cc @@ -280,6 +280,14 @@ void AttributesBuilder::ExtractReportAttributes( } builder.FlattenMapOfStringToStruct(report_data->GetDynamicFilterState()); + + builder.AddBool(utils::AttributeName::kUpstreamMtls, + report_data->IsUpstreamMutualTLS()); + const std::string &failure_reason = report_data->GetUpstreamFailureReason(); + if (!failure_reason.empty()) { + builder.AddString(utils::AttributeName::kUpstreamFailureReason, + failure_reason); + } } } // namespace http diff --git a/src/istio/control/http/attributes_builder_test.cc b/src/istio/control/http/attributes_builder_test.cc index d447542ce78..e1f1b401b39 100644 --- a/src/istio/control/http/attributes_builder_test.cc +++ b/src/istio/control/http/attributes_builder_test.cc @@ -438,6 +438,18 @@ attributes { } } } +attributes { + key: "upstream.mtls" + value { + bool_value: false + } +} +attributes { + key: "upstream.failure_reason" + value { + string_value: "wrong cert" + } +} )"; constexpr char kAuthenticationResultStruct[] = R"( @@ -809,6 +821,11 @@ TEST(AttributesBuilderTest, TestReportAttributes) { })); EXPECT_CALL(mock_data, GetDynamicFilterState()) .WillOnce(ReturnRef(filter_metadata)); + EXPECT_CALL(mock_data, IsUpstreamMutualTLS()) + .WillOnce(testing::Return(false)); + std::string failure_reason = "wrong cert"; + EXPECT_CALL(mock_data, GetUpstreamFailureReason()) + .WillOnce(ReturnRef(failure_reason)); istio::mixer::v1::Attributes attributes; AttributesBuilder builder(&attributes); @@ -889,6 +906,11 @@ TEST(AttributesBuilderTest, TestReportAttributesWithDestIP) { })); EXPECT_CALL(mock_data, GetDynamicFilterState()) .WillOnce(ReturnRef(filter_metadata)); + EXPECT_CALL(mock_data, IsUpstreamMutualTLS()) + .WillOnce(testing::Return(false)); + std::string failure_reason = "wrong cert"; + EXPECT_CALL(mock_data, GetUpstreamFailureReason()) + .WillOnce(ReturnRef(failure_reason)); istio::mixer::v1::Attributes attributes; SetDestinationIp(&attributes, "1.2.3.4"); diff --git a/src/istio/control/http/mock_report_data.h b/src/istio/control/http/mock_report_data.h index 2b2b0fddc1d..6bff6004c0a 100644 --- a/src/istio/control/http/mock_report_data.h +++ b/src/istio/control/http/mock_report_data.h @@ -38,6 +38,8 @@ class MockReportData : public ReportData { GetDynamicFilterState, const ::google::protobuf::Map &()); + MOCK_CONST_METHOD0(IsUpstreamMutualTLS, bool()); + MOCK_CONST_METHOD0(GetUpstreamFailureReason, const std::string &()); }; } // namespace http diff --git a/src/istio/control/http/request_handler_impl_test.cc b/src/istio/control/http/request_handler_impl_test.cc index 93be24a8723..6ebb995cd6a 100644 --- a/src/istio/control/http/request_handler_impl_test.cc +++ b/src/istio/control/http/request_handler_impl_test.cc @@ -395,6 +395,13 @@ TEST_F(RequestHandlerImplTest, TestHandlerReport) { EXPECT_CALL(mock_report, GetDynamicFilterState()) .Times(1) .WillOnce(ReturnRef(filter_metadata)); + EXPECT_CALL(mock_report, IsUpstreamMutualTLS()) + .Times(1) + .WillOnce(testing::Return(true)); + const std::string empty; + EXPECT_CALL(mock_report, GetUpstreamFailureReason()) + .Times(1) + .WillOnce(ReturnRef(empty)); // Report should be called. EXPECT_CALL(*mock_client_, Report(_)).Times(1); @@ -414,6 +421,8 @@ TEST_F(RequestHandlerImplTest, TestHandlerDisabledReport) { EXPECT_CALL(mock_report, GetResponseHeaders()).Times(0); EXPECT_CALL(mock_report, GetReportInfo(_)).Times(0); EXPECT_CALL(mock_report, GetDynamicFilterState()).Times(0); + EXPECT_CALL(mock_report, IsUpstreamMutualTLS()).Times(0); + EXPECT_CALL(mock_report, GetUpstreamFailureReason()).Times(0); // Report should NOT be called. EXPECT_CALL(*mock_client_, Report(_)).Times(0); @@ -452,6 +461,8 @@ TEST_F(RequestHandlerImplTest, TestEmptyConfig) { EXPECT_CALL(mock_report, GetResponseHeaders()).Times(0); EXPECT_CALL(mock_report, GetReportInfo(_)).Times(0); EXPECT_CALL(mock_report, GetDynamicFilterState()).Times(0); + EXPECT_CALL(mock_report, IsUpstreamMutualTLS()).Times(0); + EXPECT_CALL(mock_report, GetUpstreamFailureReason()).Times(0); // Report should NOT be called. EXPECT_CALL(*mock_client_, Report(_)).Times(0); diff --git a/src/istio/control/tcp/attributes_builder.cc b/src/istio/control/tcp/attributes_builder.cc index 782d0bdf6d1..35c9856f11d 100644 --- a/src/istio/control/tcp/attributes_builder.cc +++ b/src/istio/control/tcp/attributes_builder.cc @@ -137,6 +137,15 @@ void AttributesBuilder::ExtractReportAttributes( builder.AddTimestamp(utils::AttributeName::kContextTime, std::chrono::system_clock::now()); + + builder.AddBool(utils::AttributeName::kUpstreamMtls, + report_data->IsUpstreamMutualTLS()); + + const std::string &failure_reason = report_data->GetUpstreamFailureReason(); + if (!failure_reason.empty()) { + builder.AddString(utils::AttributeName::kUpstreamFailureReason, + failure_reason); + } } } // namespace tcp diff --git a/src/istio/control/tcp/attributes_builder_test.cc b/src/istio/control/tcp/attributes_builder_test.cc index 5c9c4ab9119..796c265ba74 100644 --- a/src/istio/control/tcp/attributes_builder_test.cc +++ b/src/istio/control/tcp/attributes_builder_test.cc @@ -178,6 +178,12 @@ attributes { } } } +attributes { + key: "upstream.mtls" + value { + bool_value: true + } +} )"; const char kReportAttributes[] = R"( @@ -271,6 +277,12 @@ attributes { } } } +attributes { + key: "upstream.mtls" + value { + bool_value: true + } +} )"; const char kDeltaOneReportAttributes[] = R"( @@ -344,6 +356,12 @@ attributes { } } } +attributes { + key: "upstream.mtls" + value { + bool_value: true + } +} )"; const char kDeltaTwoReportAttributes[] = R"( @@ -417,6 +435,12 @@ attributes { } } } +attributes { + key: "upstream.mtls" + value { + bool_value: true + } +} )"; void ClearContextTime(istio::mixer::v1::Attributes *attributes) { @@ -526,6 +550,10 @@ TEST(AttributesBuilderTest, TestReportAttributes) { info->send_bytes = 678; info->duration = std::chrono::nanoseconds(4); })); + EXPECT_CALL(mock_data, IsUpstreamMutualTLS()).WillRepeatedly(Return(true)); + const std::string failure_reason; + EXPECT_CALL(mock_data, GetUpstreamFailureReason()) + .WillRepeatedly(ReturnRef(failure_reason)); istio::mixer::v1::Attributes attributes; AttributesBuilder builder(&attributes); diff --git a/src/istio/control/tcp/mock_report_data.h b/src/istio/control/tcp/mock_report_data.h index 85c749ff360..41087e1ea88 100644 --- a/src/istio/control/tcp/mock_report_data.h +++ b/src/istio/control/tcp/mock_report_data.h @@ -33,6 +33,8 @@ class MockReportData : public ReportData { const ::google::protobuf::Map &()); MOCK_CONST_METHOD1(GetReportInfo, void(ReportInfo *info)); + MOCK_CONST_METHOD0(IsUpstreamMutualTLS, bool()); + MOCK_CONST_METHOD0(GetUpstreamFailureReason, const std::string &()); }; } // namespace tcp diff --git a/src/istio/control/tcp/request_handler_impl_test.cc b/src/istio/control/tcp/request_handler_impl_test.cc index 4656a1a78b6..7d77d15c2f1 100644 --- a/src/istio/control/tcp/request_handler_impl_test.cc +++ b/src/istio/control/tcp/request_handler_impl_test.cc @@ -151,6 +151,13 @@ TEST_F(RequestHandlerImplTest, TestHandlerReport) { EXPECT_CALL(mock_data, GetDynamicFilterState()) .Times(1) .WillOnce(ReturnRef(filter_metadata)); + EXPECT_CALL(mock_data, IsUpstreamMutualTLS()) + .Times(1) + .WillOnce(testing::Return(true)); + const std::string empty; + EXPECT_CALL(mock_data, GetUpstreamFailureReason()) + .Times(1) + .WillOnce(ReturnRef(empty)); // Report should be called. EXPECT_CALL(*mock_client_, Report(_)).Times(1); diff --git a/src/istio/utils/attribute_names.cc b/src/istio/utils/attribute_names.cc index 31c3fc9c542..4263d4416b0 100644 --- a/src/istio/utils/attribute_names.cc +++ b/src/istio/utils/attribute_names.cc @@ -75,6 +75,8 @@ const char AttributeName::kConnectionDuration[] = "connection.duration"; const char AttributeName::kConnectionMtls[] = "connection.mtls"; const char AttributeName::kConnectionRequestedServerName[] = "connection.requested_server_name"; +const char AttributeName::kUpstreamMtls[] = "upstream.mtls"; +const char AttributeName::kUpstreamFailureReason[] = "upstream.failure_reason"; // Downstream TCP connection id. const char AttributeName::kConnectionId[] = "connection.id";