Repository navigation
Conversation
The default excon backend reads only the first certificate of client_cert, so a client certificate issued by an intermediate CA that the server does not know fails the handshake with "unknown ca". excon sends extra certificates only from its separate client_chain option, which the plugin did not expose. Add a client_chain parameter to out_opensearch (and so to out_opensearch_data_stream) and in_opensearch, and pass it to excon. Signed-off-by: Lucas Barros <lucasbarros.kam@gmail.com>
Watson1978
left a comment
There was a problem hiding this comment.
Thanks for working on this.
I checked the fix with a local TLS server. The server requires a client certificate and trusts only the root CA. The client certificate is issued by an intermediate CA. On main, both out_opensearch and in_opensearch fail with unknown ca. With this PR, both succeed when client_chain points at the intermediate certificate. The existing tests pass too.
For in_opensearch, I used check_connection false in this test. With the default check_connection true, the connection check does not send the client certificate, so it fails on main too. That is a separate issue, and this PR does not need to fix it.
One change is needed before merging. When client_chain is not set, the excon options should stay the same as on main. Please see the inline comments.
| case @http_backend | ||
| when :excon | ||
| { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, nonblock: @http_backend_excon_nonblock } | ||
| { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, nonblock: @http_backend_excon_nonblock, client_chain: @client_chain } |
There was a problem hiding this comment.
MUST: When client_chain is not set, this passes client_chain: nil to excon. excon starts from Excon.defaults and then merges the connection options. So the explicit nil hides Excon.defaults[:client_chain].
A setup that sets Excon.defaults[:client_chain] and does not set client_chain in the plugin works on main. With this PR it fails with unknown ca. I reproduced this with a local TLS server for both out_opensearch and in_opensearch, using check_connection false for in_opensearch.
Please add the key only when client_chain is set:
| { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, nonblock: @http_backend_excon_nonblock, client_chain: @client_chain } | |
| options = { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, nonblock: @http_backend_excon_nonblock } | |
| options[:client_chain] = @client_chain if @client_chain | |
| options |
Please do not use .compact here. It would also drop client_key: nil and client_cert: nil, and that changes how Excon.defaults applies to them.
Could you also add this line to test_configure, right after assert_nil instance.client_chain? Please add it in both test/plugin/test_out_opensearch.rb and test/plugin/test_in_opensearch.rb:
assert_false instance.backend_options.key?(:client_chain)Both assertions fail on the current PR head and pass after applying both suggestions in this review.
| case @http_backend | ||
| when :excon | ||
| { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass } | ||
| { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, client_chain: @client_chain } |
There was a problem hiding this comment.
MUST: Same issue as in out_opensearch.rb. Please add client_chain only when it is set:
| { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass, client_chain: @client_chain } | |
| options = { client_key: @client_key, client_cert: @client_cert, client_key_pass: @client_key_pass } | |
| options[:client_chain] = @client_chain if @client_chain | |
| options |
An explicit client_chain: nil hides Excon.defaults[:client_chain], so a setup that sets it there and not in the plugin would stop sending the intermediate certificates. Leave the other options as they are. Signed-off-by: Lucas Barros <lucasbarros.kam@gmail.com>
|
Good catch on Excon.defaults. |
Fixes #139.
With the default
exconbackend, only the first certificate ofclient_certis sent. When the client certificate is issued by an intermediate CA and the server trusts only the root, the handshake fails withunknown ca(PKIX path building failedon the OpenSearch side). excon sends extra certificates only from its ownclient_chainoption, which the plugin did not expose.As proposed in the issue, this adds a
client_chainparameter (path to the intermediate certificates) toout_opensearch, whichout_opensearch_data_streaminherits, and toin_opensearch, and passes it to excon.typhoeusalready sends the whole chain fromclient_cert, so it is left as is and the README says so.Tests:
configure client_chain for excon(out) andtest_configure_client_chain_for_excon(in) check the parameter and the exconbackend_options. Both fail on main (undefined method 'client_chain').client_chainis nil.client_certaloneclient.infofails withtlsv1 alert unknown ca; withclient_chainpointing at the intermediate it succeeds.test_out_opensearch.rb(311 tests) andtest_in_opensearch.rbpass locally on Ruby 4.0.(check all that apply)
versionin gemspec are untouched