Kong/kong-python-pdk

Unable to identify anything during the `certificate` phase

Opened this issue · 10 comments

I'm trying to conditionally request a client certificate with kong.client.tls.request_client_certificate() in the certificate phase, however, I don't find anything I can use to identify the request.

Almost none of the methods are available in the certificate phase, however according to the docs of the mtls plugin (https://docs.konghq.com/hub/kong-inc/mtls-auth/#client-certificate-request), the SNI should be available.

Is there a way to get the SNI in the certificate phase?

I remember I've answered the same question before but cannot find the record...
The plugin implemented the logic to interfere certificate with an internal interface. The internal interface is not accessible from external plugins (Go, Python, JS), and is very dangerous to implement yourself even with Lua plugins.
So sadly we don't have a way to do it for Python.

Hmm, that makes the whole certificate phase pretty useless, since we can't figure out what request we are handling. You can only request a client certificate for all requests.

I understand that the mtls plugin isn't open source, but by denying access to this information from other plugins, there is no solution but to use the closed source plugin?

@michaelarnauts
Sorry. I confirmed with @fffonion offline and it's possible to do what you want (just not the way I expected when I wrote down the answer).

kong.nginx.get_var("ssl_server_name") can be used to get the Nginx variable "ssl_server_name".

Ref:
https://kong.github.io/kong-python-pdk/kong.html#kong.kong.nginx.get_var
(Note the document is not accurate. Will create a fix for that.)
http://nginx.org/en/docs/http/ngx_http_ssl_module.html#:~:text=%24-,ssl_server_name,-returns%20the%20server

@StarlightIbuki thanks for the update. I'll try to find some time to test the kong.nginx.get_var() method.

@StarlightIbuki @fffonion

I've tried the suggested kong.nginx.get_var("ssl_server_name"), but I get back the following error.

It seems that this is thrown due to a patch that kong made itself: https://github.com/Kong/kong/blob/a9ff98a168924b8135eda010f3c79bc91c157908/build/openresty/patches/ngx_lua-0.10.21_02-dyn_upstream_keepalive.patch#L1030

Python code:

    def certificate(self, kong: kong.kong):
        kong.log.debug("---- Certificate execution -----")
        kong.log.debug("nginx var ssl_server_name = %s" % kong.nginx.get_var("ssl_server_name"))

Kong logs:

...
2023/05/31 14:19:15 [info] 1245035#0: *595 [mtls-auth-prod:1245061] DEBG - [22:19:15] rpc: #2 return: {'Data': {'Method': 'kong.log.debug', 'Args': ('---- Certificate execution -----',)}, 'EventId': 0}, context: ngx.timer
2023/05/31 14:19:15 [debug] 1245037#0: *606 [kong] mp_rpc.lua:161 [mtls-auth-prod] ---- Certificate execution -----
2023/05/31 14:19:15 [info] 1245035#0: *595 [mtls-auth-prod:1245061] DEBG - [22:19:15] rpc: #3 method: plugin.Step args: [{'EventId': 0}], context: ngx.timer
2023/05/31 14:19:15 [info] 1245035#0: *595 [mtls-auth-prod:1245061] DEBG - [22:19:15] rpc: #3 return: {'Data': {'Method': 'kong.nginx.get_var', 'Args': ('ssl_server_name',)}, 'EventId': 0}, context: ngx.timer
2023/05/31 14:19:15 [error] 1245037#0: *606 lua entry thread aborted: runtime error: ...local/share/lua/5.1/kong/runloop/plugin_servers/init.lua:41: API disabled in the current context
stack traceback:
coroutine 0:
        [C]: in function 'error'
        /usr/local/openresty/lualib/resty/kong/var.lua:111: in function '__index'
        ...local/share/lua/5.1/kong/runloop/plugin_servers/init.lua:41: in function 'method'
        ...cal/share/lua/5.1/kong/runloop/plugin_servers/mp_rpc.lua:161: in function 'call_pdk_method'
        ...cal/share/lua/5.1/kong/runloop/plugin_servers/mp_rpc.lua:317: in function 'bridge_loop'
        ...cal/share/lua/5.1/kong/runloop/plugin_servers/mp_rpc.lua:336: in function 'handle_event'
        ...local/share/lua/5.1/kong/runloop/plugin_servers/init.lua:274: in function <...local/share/lua/5.1/kong/runloop/plugin_servers/init.lua:273>
        /usr/local/share/lua/5.1/kong/init.lua:351: in function 'execute_plugins_iterator'
        /usr/local/share/lua/5.1/kong/init.lua:879: in function 'ssl_certificate'
        ssl_certificate_by_lua:2: in main chunk, context: ssl_certificate_by_lua*, client: xxx.xxx.xxx.xxx, server: 0.0.0.0:443
2023/05/31 14:19:15 [info] 1245037#0: *605 SSL_do_handshake() failed (SSL: error:1417A179:SSL routines:tls_post_process_client_hello:cert cb error) while SSL handshaking, client: xxx.xxx.xxx.xxx, server: 0.0.0.0:443

Sorry for the confusion. I thought the API is available for certificate phase but it's actually not.
Ping @fffonion for help on this issue. Do we have any workaround for this?

Also sorry for replying late. Sometimes it got buried in a flood of notifications. Please feel free to ping me when you think it takes too long.

yes, sorry this was an oversight, the approach doesn't work in certificate phase. we will need a new PDK API that calls ngx.ssl.server_name() to extract SNI, there's no such support exists in kong yet.

yes, sorry this was an oversight, the approach doesn't work in certificate phase. we will need a new PDK API that calls ngx.ssl.server_name() to extract SNI, there's no such support exists in kong yet.

That's unfortunate. Is this planned, or something where I could help?

@michaelarnauts this is currently not on our roadmap. PRs are welcomed, Kong/kong#9512 is a good example on how to add such function in PDK. Note you only need to implement at kong/lua side, no extra effort needed on python-pdk side.