tls: openssl: Fail verification if client certificate is not provided
We are interested in using fluentbit with mTLS. However, currently fluentbit accepts connections from clients who do not provide a certificate at all. This change to the openssl library forces the connection to fail if certificates are not provided when fluent-bit is in server mode.
Tested with following configuration:
pipeline:
inputs:
- name: syslog
mode: tcp
parser: syslog-rfc5424
listen: 0.0.0.0
port: 6514
tag: syslog.remote.log
tls: on
tls.verify: on
tls.debug: 1
tls.crt_file: ./certs/server.crt
tls.key_file: ./certs/server.key
tls.ca_file: ./certs/ca.crt
Output without client certificate
[2025/12/04 16:04:26.322586020] [debug] [tls] connection #102 SSL_accept: before SSL initialization
[2025/12/04 16:04:26.322606762] [debug] [tls] connection #102 WANT_READ
[2025/12/04 16:04:26.822746151] [debug] [tls] connection #102 SSL_accept: before SSL initialization
[2025/12/04 16:04:26.823028373] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS read client hello
[2025/12/04 16:04:26.823332483] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write server hello
[2025/12/04 16:04:26.823417104] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write change cipher spec
[2025/12/04 16:04:26.823435740] [debug] [tls] connection #102 SSL_accept: TLSv1.3 write encrypted extensions
[2025/12/04 16:04:26.823458629] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write certificate request
[2025/12/04 16:04:26.823796114] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write certificate
[2025/12/04 16:04:26.825319389] [debug] [tls] connection #102 SSL_accept: TLSv1.3 write server certificate verify
[2025/12/04 16:04:26.825394738] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write finished
[2025/12/04 16:04:26.825401950] [debug] [tls] connection #102 SSL_accept: TLSv1.3 early data
[2025/12/04 16:04:26.825411284] [debug] [tls] connection #102 WANT_READ
[2025/12/04 16:04:27.325601341] [debug] [tls] connection #102 SSL_accept: TLSv1.3 early data
[2025/12/04 16:04:27.325751148] [debug] [tls] connection #102 SSL3 alert write:fatal:unknown
[2025/12/04 16:04:27.325765551] [error] [tls] connection #102 SSL_accept: error in error
[2025/12/04 16:04:27.325771902] [error] [tls] error: unexpected EOF
[2025/12/04 16:04:27.325826387] [debug] [downstream] connection #102 failed
[2025/12/04 16:04:27.325867515] [error] [input:syslog:syslog.4] could not accept new connection
Output with client certificate
[2025/12/04 16:05:52.618787245] [debug] [tls] connection #102 SSL_accept: before SSL initialization
[2025/12/04 16:05:52.618802905] [debug] [tls] connection #102 WANT_READ
[2025/12/04 16:05:53.118952005] [debug] [tls] connection #102 SSL_accept: before SSL initialization
[2025/12/04 16:05:53.119237744] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS read client hello
[2025/12/04 16:05:53.119554356] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write server hello
[2025/12/04 16:05:53.119639994] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write change cipher spec
[2025/12/04 16:05:53.119658718] [debug] [tls] connection #102 SSL_accept: TLSv1.3 write encrypted extensions
[2025/12/04 16:05:53.119679475] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write certificate request
[2025/12/04 16:05:53.120048759] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write certificate
[2025/12/04 16:05:53.121813125] [debug] [tls] connection #102 SSL_accept: TLSv1.3 write server certificate verify
[2025/12/04 16:05:53.121901348] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write finished
[2025/12/04 16:05:53.121908052] [debug] [tls] connection #102 SSL_accept: TLSv1.3 early data
[2025/12/04 16:05:53.121920830] [debug] [tls] connection #102 WANT_READ
[2025/12/04 16:05:53.622055891] [debug] [tls] connection #102 SSL_accept: TLSv1.3 early data
[2025/12/04 16:05:53.622447387] [debug] [tls] connection #102 SSL_accept: TLSv1.3 read client compressed certificate
[2025/12/04 16:05:53.622526465] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS read certificate verify
[2025/12/04 16:05:53.622563918] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS read finished
[2025/12/04 16:05:53.622741077] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write session ticket
[2025/12/04 16:05:53.622810213] [debug] [tls] connection #102 SSL_accept: SSLv3/TLS write session ticket
Fluent Bit is licensed under Apache 2.0, by submitting this pull request I understand that this code will be released under the terms of that license.
Summary by CodeRabbit
- Bug Fixes
- TLS peer verification refined: server connections now correctly require a peer certificate when verification is enabled.
- Client connections preserve previous verification behavior, avoiding unintended certificate requirement changes.
✏️ Tip: You can customize this high-level summary in your review settings.
Walkthrough
Add support for requiring client certificates: new config flag and API to request client verification, plumbing from input config -> flb_tls API -> TLS backend -> OpenSSL SSL_CTX to set SSL_VERIFY_FAIL_IF_NO_PEER_CERT when in server mode.
Changes
| Cohort / File(s) | Summary |
|---|---|
OpenSSL backend src/tls/openssl.c |
Add tls_context_set_verify_client(void *ctx_backend, int verify_client) and wire it into tls_openssl as .context_set_verify_client. Compute and apply verify flags on the SSL_CTX, OR-ing SSL_VERIFY_FAIL_IF_NO_PEER_CERT only when server and verify_client is true. |
TLS core and API include/fluent-bit/tls/flb_tls.h, src/tls/flb_tls.c |
Add verify_client field to struct flb_tls, new backend hook context_set_verify_client(void *, int), and implement flb_tls_set_verify_client(struct flb_tls *tls, int verify_client); propagate setting to backend when available. |
Input config and usage include/fluent-bit/flb_input.h, src/flb_input.c |
Add tls_verify_client flag to input instance, expose tls.verify_client_cert config key, initialize field, and call flb_tls_set_verify_client during input TLS setup (fail on error). |
Sequence Diagram(s)
sequenceDiagram
participant Input as Input (flb_input)
participant TLS as flb_tls
participant Backend as OpenSSL backend
participant SSL as OpenSSL SSL_CTX
Input->>TLS: flb_tls_set_verify_client(tls, verify_client)
TLS->>TLS: tls->verify_client = verify_client
TLS->>Backend: if (tls->ctx && api->context_set_verify_client) call context_set_verify_client(ctx, verify_client)
Backend->>SSL: compute verify_flags (SSL_VERIFY_PEER | maybe SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
Backend->>SSL: SSL_CTX_set_verify(ctx, verify_flags, verify_cb)
SSL-->>Backend: return status
Backend-->>TLS: return status
TLS-->>Input: return status
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~20–30 minutes
- Inspect
src/tls/openssl.cchanges: verify server-mode detection, flag composition, and error paths. - Validate
flb_tls_set_verify_clientpropagation and null/backend capability checks insrc/tls/flb_tls.c. - Check
src/flb_input.cconfig parsing, initialization order, and behavior on TLS setup failure. - Review public headers (
include/...) for API and struct compatibility.
Suggested reviewers
- edsiper
- cosmo0920
Poem
🐰 I hop through headers, flags in tow,
"Require a paw—er, cert!" I softly crow.
Servers ask kindly, clients stay calm,
Tunnels keep secrets, snug as a charm.
🥕
Pre-merge checks and finishing touches
❌ Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | ⚠️ Warning | Docstring coverage is 22.22% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
✅ Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| Title check | ✅ Passed | The pull request title accurately describes the main change: adding support to fail TLS verification when a client certificate is not provided in OpenSSL server mode. |
✨ Finishing touches
- [ ] 📝 Generate docstrings
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands and usage tips.
💡 Codex Review
https://github.com/fluent/fluent-bit/blob/0819c37314e40afad5801841e8993e4161a5806d/src/tls/openssl.c#L804-L808
mTLS now forced for TLS inputs using default verify
When verify is enabled you now OR SSL_VERIFY_FAIL_IF_NO_PEER_CERT into the server verify flags, which causes the handshake to abort if a client does not present a certificate. All input plugins default tls.verify to on (see src/flb_input.c:400 and the call at line 1308), so simply enabling TLS on an input without explicitly turning verification off will now require client certificates and reject ordinary TLS clients that do not send one—a behavior change from the previous optional client-auth flow.
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
💡 Codex Review
https://github.com/fluent/fluent-bit/blob/0819c37314e40afad5801841e8993e4161a5806d/src/tls/openssl.c#L804-L808
mTLS now forced for TLS inputs using default verify
When
verifyis enabled you now ORSSL_VERIFY_FAIL_IF_NO_PEER_CERTinto the server verify flags, which causes the handshake to abort if a client does not present a certificate. All input plugins defaulttls.verifytoon(seesrc/flb_input.c:400and the call at line 1308), so simply enabling TLS on an input without explicitly turning verification off will now require client certificates and reject ordinary TLS clients that do not send one—a behavior change from the previous optional client-auth flow. ℹ️ About Codex in GitHub
This is a breaking change as it would break already running deployments.
On the other hand one could also argue that this is a security issue as people might expect the client certificate to be checked but it is not, which might be surprising.
Should we consider a new option for this? e.g. something like verify = enforced?
💡 Codex Review
https://github.com/fluent/fluent-bit/blob/0819c37314e40afad5801841e8993e4161a5806d/src/tls/openssl.c#L804-L808
mTLS now forced for TLS inputs using default verify When
verifyis enabled you now ORSSL_VERIFY_FAIL_IF_NO_PEER_CERTinto the server verify flags, which causes the handshake to abort if a client does not present a certificate. All input plugins defaulttls.verifytoon(seesrc/flb_input.c:400and the call at line 1308), so simply enabling TLS on an input without explicitly turning verification off will now require client certificates and reject ordinary TLS clients that do not send one—a behavior change from the previous optional client-auth flow. ℹ️ About Codex in GitHubThis is a breaking change as it would break already running deployments.
On the other hand one could also argue that this is a security issue as people might expect the client certificate to be checked but it is not, which might be surprising.
Should we consider a new option for this? e.g. something like
verify = enforced?
Yes. We need to keep backward compatibility. So, introducing new option would be great.
added a new configuration option that can be activated as follows:
tls: on
tls.debug: 1
tls.verify: on
tls.verify_client_cert: on
tls.crt_file: ./certs/server.crt
tls.key_file: ./certs/server.key
tls.ca_file: ./certs/ca.crt
| tls.verify | tls.verify_client_cert | result |
|---|---|---|
| on | on | client certificate is strictly validated |
| on | off | client certificate is optionally validated |
| off | on | no validation takes place |
| off | off | no validation takes place |