diff --git a/kong/init.lua b/kong/init.lua index 70abad8b59c..a758dc6f653 100644 --- a/kong/init.lua +++ b/kong/init.lua @@ -1032,6 +1032,8 @@ function Kong.ssl_certificate() kong.table.clear(ngx.ctx) end +function Kong.ssl_client_hello() +end function Kong.preread() local ctx = get_ctx_table(fetch_table(CTX_NS, CTX_NARR, CTX_NREC)) diff --git a/kong/llm/proxy/handler.lua b/kong/llm/proxy/handler.lua index 1ae9e1885ec..ced4586f385 100644 --- a/kong/llm/proxy/handler.lua +++ b/kong/llm/proxy/handler.lua @@ -13,7 +13,14 @@ local kong_utils = require("kong.tools.gzip") local buffer = require "string.buffer" local strip = require("kong.tools.string").strip local cycle_aware_deep_copy = require("kong.tools.table").cycle_aware_deep_copy +local kong_global = require("kong.global") +local PHASES = kong_global.phases +local certificate = require("kong.tls.plugins.certificate") +local sni_filter = require("kong.tls.plugins.sni_filter") + +local TTL_FOREVER = { ttl = 0 } +-- local SNI_CACHE_KEY = "ai:llm:cert_enabled_snis" local EMPTY = require("kong.tools.table").EMPTY @@ -477,4 +484,31 @@ function _M:access(conf) end +function _M:init_worker_for_plugin(plugin_name) + -- TODO: remove nasty hacks once we have singleton phases support in core + + local orig_ssl_client_hello = kong.ssl_client_hello -- luacheck: ignore + kong.ssl_client_hello = function() -- luacheck: ignore + orig_ssl_client_hello() + + local ctx = ngx.ctx + -- ensure phases are set + ctx.KONG_PHASE = PHASES.certificate + + kong_global.set_namespaced_log(kong, plugin_name) + local sni_cache_key = "ai:llm:cert_enabled_snis:" .. plugin_name + local snis_set, err = kong.cache:get(sni_cache_key, TTL_FOREVER, + sni_filter.build_ssl_route_filter_set, plugin_name) + + if err then + kong.log.err("unable to request client to present its certificate: ", + err) + return ngx.exit(ngx.ERROR) + end + certificate.execute_client_hello(snis_set, { disable_http2 = true }) + kong_global.reset_log(kong) + + end +end + return _M diff --git a/kong/plugins/ai-proxy/handler.lua b/kong/plugins/ai-proxy/handler.lua index 558f4f24198..36a54d552bd 100644 --- a/kong/plugins/ai-proxy/handler.lua +++ b/kong/plugins/ai-proxy/handler.lua @@ -3,7 +3,9 @@ local deep_copy = require "kong.tools.table".deep_copy local _M = deep_copy(require("kong.llm.proxy.handler")) - +_M.init_worker = function() + _M.init_worker_for_plugin("ai-proxy") +end _M.PRIORITY = 770 _M.VERSION = kong_meta.version diff --git a/kong/templates/nginx_kong.lua b/kong/templates/nginx_kong.lua index 184ba9370c1..470fa61e459 100644 --- a/kong/templates/nginx_kong.lua +++ b/kong/templates/nginx_kong.lua @@ -126,6 +126,9 @@ server { ssl_certificate_by_lua_block { Kong.ssl_certificate() } + ssl_client_hello_by_lua_block { + Kong.ssl_client_hello() + } > end # injected nginx_proxy_* directives diff --git a/kong/templates/nginx_kong_stream.lua b/kong/templates/nginx_kong_stream.lua index bfd276f25b4..c07407ad120 100644 --- a/kong/templates/nginx_kong_stream.lua +++ b/kong/templates/nginx_kong_stream.lua @@ -119,6 +119,9 @@ server { ssl_certificate_by_lua_block { Kong.ssl_certificate() } + ssl_client_hello_by_lua_block { + Kong.ssl_client_hello() + } > end set $upstream_host ''; diff --git a/kong/tls/plugins/certificate.lua b/kong/tls/plugins/certificate.lua index f53d7d96788..4bf80fd3bc0 100644 --- a/kong/tls/plugins/certificate.lua +++ b/kong/tls/plugins/certificate.lua @@ -7,6 +7,7 @@ --- Copyright 2019 Kong Inc. local ngx_ssl = require "ngx.ssl" +local ssl_clt = require "ngx.ssl.clienthello" local sni_filter = require("kong.tls.plugins.sni_filter") local pl_stringx = require "pl.stringx" local server_name = ngx_ssl.server_name @@ -22,7 +23,6 @@ local EMPTY_T = {} local function match_sni(snis, server_name) - local matched_sni if server_name then -- search plain snis if snis[server_name] then @@ -96,4 +96,35 @@ function _M.execute(snis_set) end end +function _M.execute_client_hello(snis_set, options) + + if not options then + return + end + + if not options.disable_http2 then + return + end + + local server_name, err = ssl_clt.get_client_hello_server_name() + if err then + kong.log.debug("unable to get client hello server name: ", err) + return + end + + local sni_mapping = match_sni(snis_set, server_name) + + if sni_mapping then + -- TODO: improve detection of ennoblement once we have DAO functions + -- to filter plugin configurations based on plugin name + + kong.log.debug("enabled, will disable http2 alpn") + + local res, err = kong.tls.disable_http2_alpn() + if not res then + kong.log.err("unable to disable http2 alpn: ", err) + end + end +end + return _M diff --git a/spec/fixtures/1.2_custom_nginx.template b/spec/fixtures/1.2_custom_nginx.template index 2f3851d919a..faa15037ec5 100644 --- a/spec/fixtures/1.2_custom_nginx.template +++ b/spec/fixtures/1.2_custom_nginx.template @@ -102,6 +102,9 @@ http { ssl_certificate_by_lua_block { Kong.ssl_certificate() } + ssl_client_hello_by_lua_block { + Kong.ssl_client_hello() + } > end # injected nginx_proxy_* directives