envoyproxy / envoy

Cloud-native high-performance edge/middle/service proxy

Home Page:https://www.envoyproxy.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Surface connection SSL peer certificate information to CEL

salrashid123 opened this issue · comments

FR to surface the ssl cert information such that it is available for use within wasm.

eg, the fields surfaced to wasm that pertain to the upstream/downstream SSL certs is here:
https://github.com/envoyproxy/envoy/blob/master/source/extensions/filters/common/expr/context.cc#L43-L64

but it omits some additional fields visible to the tls conn:
https://github.com/envoyproxy/envoy/blob/master/include/envoy/ssl/connection.h#L49


i'm specificaly intersted in sha256PeerCertificateDigest but all the conn fields should be availabe as is the case with LUA:

function envoy_on_request(request_handle)
  local stream = request_handle:streamInfo()
  local peerDigest = stream:downstreamSslConnection():sha256PeerCertificateDigest()

This issue has been automatically marked as stale because it has not had activity in the last 30 days. It will be closed in the next 7 days unless it is tagged "help wanted" or "no stalebot" or other activity occurs. Thank you for your contributions.

This issue has been automatically closed because it has not had activity in the last 37 days. If this issue is still valid, please ping a maintainer and ask them to label it as "help wanted" or "no stalebot". Thank you for your contributions.

@mattklein123
could we add one of the labels to revive this?

commented

/assign @kyessenov

the sha256PeerCertificateDigest info part would be really useful for wasm to help with mTLS cert-bound tokens (ie., validate the peer certificate presented in a bearer token)

i don't really know cpp (if i did, i'd file a PR :) ),
but the i think the following would be parts where the change would take place:

absl::optional<CelValue> extractSslInfo(const Ssl::ConnectionInfo& ssl_info,
                                        absl::string_view value) {
  if (value == TLSVersion) {
    return CelValue::CreateString(&ssl_info.tlsVersion());
   ...
   ...
  } else if (value == SHA256PeerCertificateDigest) {
    if (!ssl_info.sha256PeerCertificateDigest().empty()) {
      return CelValue::CreateString(&ssl_info.sha256PeerCertificateDigest());
    }
  }
  return {};
}
  • envoy/source/extensions/filters/common/expr/context.h
constexpr absl::string_view SHA256PeerCertificateDigest = "sha256_peer_certificate_digest";

Available through ref Ssl::ConnectionInfo

if anyone wants to contribute ,LMK, i can altest test

atleast for ref, my repo here

ok, bit it working by modifying the two files cited above

# git diff
diff --git a/source/extensions/filters/common/expr/context.cc b/source/extensions/filters/common/expr/context.cc
index ac0a47bd9..db801af4f 100644
--- a/source/extensions/filters/common/expr/context.cc
+++ b/source/extensions/filters/common/expr/context.cc
@@ -63,6 +63,10 @@ absl::optional<CelValue> extractSslInfo(const Ssl::ConnectionInfo& ssl_info,
     if (!ssl_info.dnsSansPeerCertificate().empty()) {
       return CelValue::CreateString(&ssl_info.dnsSansPeerCertificate()[0]);
     }
+  } else if (value == SHA256PeerCertificateDigest) {
+    if (!ssl_info.sha256PeerCertificateDigest().empty()) {
+      return CelValue::CreateString(&ssl_info.sha256PeerCertificateDigest());
+    }
   }
   return {};
 }
diff --git a/source/extensions/filters/common/expr/context.h b/source/extensions/filters/common/expr/context.h
index 2f3f2539c..8107d1347 100644
--- a/source/extensions/filters/common/expr/context.h
+++ b/source/extensions/filters/common/expr/context.h
@@ -63,6 +63,7 @@ constexpr absl::string_view URISanLocalCertificate = "uri_san_local_certificate"
 constexpr absl::string_view URISanPeerCertificate = "uri_san_peer_certificate";
 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";
 
 // Source properties
 constexpr absl::string_view Source = "source";

once thats done, the wasm filter can read the jwt claims and compare that to the fingerprint from TLS

[2021-12-30 16:42:26.919][3116401][debug][wasm] [source/extensions/common/wasm/context.cc:1164]
 wasm log my_plugin tb_root_id tb_root_id: 
      [examples/wasm-cc/envoy_filter_http_wasm_tokenbinding.cc:96]::onRequestHeaders()  
                x5t#S256 -> kV_FTD_BllHKImAMlqqbEm6LoHO0QYWATO5f823YckA

[2021-12-30 16:42:26.919][3116401][debug][wasm] [source/extensions/common/wasm/context.cc:1164] 
     wasm log my_plugin tb_root_id tb_root_id: 
          [examples/wasm-cc/envoy_filter_http_wasm_tokenbinding.cc:114]::onRequestHeaders()
              sha256_peer_certificate_digest: kV_FTD_BllHKImAMlqqbEm6LoHO0QYWATO5f823YckA

[2021-12-30 16:42:26.919][3116401][debug][wasm] [source/extensions/common/wasm/context.cc:1164] 
       wasm log my_plugin tb_root_id tb_root_id: 
               [examples/wasm-cc/envoy_filter_http_wasm_tokenbinding.cc:120]::onRequestHeaders() 
                        sha256_peer_certificate_digest and digest_from_cbf_header matched