Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
Added the ``connection.peer_certificate_valid`` CEL attribute, a bool indicating whether the
downstream peer certificate was presented and validated. In optional mTLS setups using
``trust_chain_verification: ACCEPT_UNTRUSTED``, a certificate may be presented without being
validated.
3 changes: 2 additions & 1 deletion docs/root/intro/arch_overview/advanced/attributes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ RBAC):
destination.address, string, Downstream connection local address
destination.port, int, Downstream connection local port
connection.id, uint, Downstream connection ID
connection.mtls, bool, Indicates whether TLS is applied to the downstream connection and the peer ceritificate is presented
connection.mtls, bool, Indicates whether TLS is applied to the downstream connection and the peer certificate is presented
connection.requested_server_name, string, Requested server name in the downstream TLS connection
connection.tls_version, string, TLS version of the downstream TLS connection
connection.subject_local_certificate, string, The subject field of the local certificate in the downstream TLS connection
Expand All @@ -124,6 +124,7 @@ RBAC):
connection.uri_san_peer_certificate, string, The first URI entry in the SAN field of the peer certificate in the downstream TLS connection
connection.sha256_peer_certificate_digest, string, SHA256 digest of the peer certificate in the downstream TLS connection if present
connection.peer_certificate, string, PEM-encoded peer certificate in the downstream TLS connection if present
connection.peer_certificate_valid, bool, Indicates whether the peer certificate in the downstream TLS connection was presented and validated
connection.transport_failure_reason, string, The transport failure reason e.g. certificate validation failed

The following additional attributes are available upon the downstream connection termination:
Expand Down
8 changes: 8 additions & 0 deletions source/extensions/filters/common/expr/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -315,6 +315,14 @@ const ConnectionLookupValues& ConnectionLookupValues::get() {
.sslConnection()
->peerCertificatePresented());
}},
{PeerCertificateValid,
[](const ConnectionWrapper& wrapper) -> absl::optional<CelValue> {
return CelValue::CreateBool(
wrapper.info_.downstreamAddressProvider().sslConnection() != nullptr &&
wrapper.info_.downstreamAddressProvider()
.sslConnection()
->peerCertificateValidated());
}},
{RequestedServerName,
[](const ConnectionWrapper& wrapper) -> absl::optional<CelValue> {
return CelValue::CreateStringView(
Expand Down
1 change: 1 addition & 0 deletions source/extensions/filters/common/expr/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ constexpr absl::string_view DNSSanLocalCertificate = "dns_san_local_certificate"
constexpr absl::string_view DNSSanPeerCertificate = "dns_san_peer_certificate";
constexpr absl::string_view SHA256PeerCertificateDigest = "sha256_peer_certificate_digest";
constexpr absl::string_view PeerCertificate = "peer_certificate";
constexpr absl::string_view PeerCertificateValid = "peer_certificate_valid";
constexpr absl::string_view DownstreamTransportFailureReason = "transport_failure_reason";

// Source properties
Expand Down
34 changes: 34 additions & 0 deletions test/extensions/filters/common/expr/context_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,32 @@ TEST(Context, ConnectionFallbackAttributes) {
}
}

TEST(Context, ConnectionPeerCertificateNotValidated) {
// Presented but not validated (e.g. ACCEPT_UNTRUSTED): mtls=true, peer_certificate_valid=false.
NiceMock<StreamInfo::MockStreamInfo> info;
auto ssl_info = std::make_shared<NiceMock<Ssl::MockConnectionInfo>>();
info.downstream_connection_info_provider_->setSslConnection(ssl_info);
EXPECT_CALL(*ssl_info, peerCertificatePresented()).WillRepeatedly(Return(true));
EXPECT_CALL(*ssl_info, peerCertificateValidated()).WillRepeatedly(Return(false));

Protobuf::Arena arena;
ConnectionWrapper connection(arena, info);

{
auto value = connection[CelValue::CreateStringView(MTLS)];
EXPECT_TRUE(value.has_value());
ASSERT_TRUE(value.value().IsBool());
EXPECT_TRUE(value.value().BoolOrDie());
}

{
auto value = connection[CelValue::CreateStringView(PeerCertificateValid)];
EXPECT_TRUE(value.has_value());
ASSERT_TRUE(value.value().IsBool());
EXPECT_FALSE(value.value().BoolOrDie());
}
}

TEST(Context, ConnectionAttributes) {
NiceMock<StreamInfo::MockStreamInfo> info;
std::shared_ptr<NiceMock<Upstream::MockClusterInfo>> cluster_info(
Expand Down Expand Up @@ -585,6 +611,7 @@ TEST(Context, ConnectionAttributes) {

EXPECT_CALL(*downstream_ssl_info, peerCertificatePresented()).WillRepeatedly(Return(true));
EXPECT_CALL(*upstream_ssl_info, peerCertificatePresented()).WillRepeatedly(Return(true));
EXPECT_CALL(*downstream_ssl_info, peerCertificateValidated()).WillRepeatedly(Return(true));
EXPECT_CALL(*upstream_host, address()).WillRepeatedly(Return(upstream_address));
EXPECT_CALL(*upstream_host, locality()).WillRepeatedly(ReturnRef(upstream_locality));

Expand Down Expand Up @@ -721,6 +748,13 @@ TEST(Context, ConnectionAttributes) {
EXPECT_TRUE(value.value().BoolOrDie());
}

{
auto value = connection[CelValue::CreateStringView(PeerCertificateValid)];
EXPECT_TRUE(value.has_value());
ASSERT_TRUE(value.value().IsBool());
EXPECT_TRUE(value.value().BoolOrDie());
}

{
auto value = connection[CelValue::CreateStringView(RequestedServerName)];
EXPECT_TRUE(value.has_value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3833,6 +3833,8 @@ TEST_P(ExtProcIntegrationTest, RequestResponseAttributes) {
proto_config_.mutable_request_attributes()->Add("connection.id"); // tests uint64
proto_config_.mutable_request_attributes()->Add(
"connection.peer_certificate"); // tests string, not present without TLS
proto_config_.mutable_request_attributes()->Add(
"connection.peer_certificate_valid"); // tests bool, present and false without TLS
proto_config_.mutable_request_attributes()->Add("response.code");
proto_config_.mutable_response_attributes()->Add("response.code"); // tests int64
proto_config_.mutable_response_attributes()->Add("response.code_details");
Expand All @@ -3859,8 +3861,11 @@ TEST_P(ExtProcIntegrationTest, RequestResponseAttributes) {
EXPECT_TRUE(proto_struct.fields().at("connection.id").has_number_value());
// connection.peer_certificate is not present without TLS
EXPECT_FALSE(proto_struct.fields().contains("connection.peer_certificate"));
// connection.peer_certificate_valid is present and false without TLS (like connection.mtls)
EXPECT_EQ(proto_struct.fields().at("connection.peer_certificate_valid").bool_value(),
false);
// Make sure we did not include the attribute which was not yet available.
EXPECT_EQ(proto_struct.fields().size(), 6);
EXPECT_EQ(proto_struct.fields().size(), 7);
EXPECT_FALSE(proto_struct.fields().contains("response.code"));

// Make sure we are not including any data in the deprecated HttpHeaders.attributes.
Expand Down