Fluent Bit can be configured to use mutual TLS for securing communication between its inputs and outputs, ensuring both parties authenticate each other.

Let’s see this in action. Imagine we have a Fluent Bit instance collecting logs from a web server and sending them to a remote logging service. We want to ensure that the Fluent Bit instance is indeed talking to the correct logging service, and that the logging service is accepting logs only from our authorized Fluent Bit instance.

Here’s a simplified Fluent Bit configuration snippet demonstrating this:

[INPUT]
    Name              tail
    Path              /var/log/nginx/access.log
    Tag               web.access
    <TLS>
        Mode          require
        Client.Key    /etc.fluent-bit/certs/fluent-bit.key
        Client.Cert   /etc.fluent-bit/certs/fluent-bit.crt
        CA.File       /etc.fluent-bit/certs/ca.crt
    </TLS>

[OUTPUT]
    Name              http
    Match             web.access
    Host              logging.example.com
    Port              443
    URI               /v1/logs
    Format            json
    <TLS>
        Mode          verify_peer
        Client.Key    /etc.fluent-bit/certs/fluent-bit.key
        Client.Cert   /etc.fluent-bit/certs/fluent-bit.crt
        CA.File       /etc.fluent-bit/certs/ca.crt
    </TLS>

In this setup, the tail input is configured to require a TLS connection and present its own certificate (fluent-bit.crt and fluent-bit.key) to the upstream service. It also verifies that the upstream service’s certificate is signed by a trusted Certificate Authority (ca.crt). The http output, conversely, is configured to verify the peer (the upstream logging service), meaning it expects the logging service to present a certificate that is signed by the ca.crt. It also presents its own client certificate to the logging service for mutual authentication.

The core problem mTLS solves is blind trust. In a typical TLS setup (like a web browser connecting to a website), the client trusts the server based on its certificate. But what if you have two services that both need to trust each other? For example, an agent sending logs to a central collector, or a microservice calling another microservice. Without mTLS, the agent might be sending logs to a malicious collector pretending to be the real one, or the microservice could be calling a fake endpoint. mTLS establishes a two-way handshake: the server proves its identity to the client, and the client proves its identity to the server.

Internally, Fluent Bit uses the mbedTLS library for its TLS operations. When Mode is set to require (often used on the server-side input in a mTLS scenario, though Fluent Bit inputs don’t typically act as the server in a mTLS handshake with an output; this mode is more for when an input itself is acting as a TLS server and requires clients to authenticate), it expects the connecting client to present a valid certificate. When Mode is set to verify_peer (common for client-side outputs connecting to TLS servers), Fluent Bit acts as the TLS client, verifying the server’s certificate against the CA.File, and also sending its own Client.Cert and Client.Key for the server to verify. The CA.File is crucial; it contains the root certificate(s) of the Certificate Authority that signed the server’s certificate (or the client’s certificate if it’s acting as a server).

The key parameters are:

  • Mode: Controls the TLS handshake behavior. require means the peer must present a certificate and it must be valid. verify_peer means the peer’s certificate will be verified. For mTLS, you’ll typically see require on the "server" side of the connection (which in Fluent Bit’s input/output model, is usually the output verifying the upstream service) and the client certificate being sent.
  • Client.Key: The private key for the Fluent Bit instance’s identity.
  • Client.Cert: The public certificate for the Fluent Bit instance’s identity.
  • CA.File: The certificate of the Certificate Authority that signed the other party’s certificate (i.e., the server’s certificate if Fluent Bit is the client, or the client’s certificate if Fluent Bit is the server).

When you configure mTLS, you’re essentially embedding a mini-PKI (Public Key Infrastructure) into your Fluent Bit configuration. You need to generate or obtain a server certificate and its private key for the receiving endpoint, and a client certificate and its private key for the Fluent Bit instance. Critically, both parties must trust the same Certificate Authority that signed their respective certificates. The CA.File in Fluent Bit’s configuration points to the CA certificate that Fluent Bit will use to validate the other endpoint’s certificate.

The one thing most people don’t realize is that the CA.File is used by Fluent Bit to verify the remote endpoint’s certificate. If you’re configuring an output to connect to a TLS-enabled service, the CA.File should contain the CA certificate that signed the server’s certificate. If you’re configuring an input to act as a TLS server and expect clients to authenticate (less common for standard inputs but possible with plugins like http_server), the CA.File would contain the CA certificate that signed the client’s certificate. For true mTLS where both sides authenticate, you’ll often have a setup where the output verifies the server using its CA.File, and the server verifies the Fluent Bit client using its own CA file (which would be configured on the server-side, not in Fluent Bit itself).

After successfully configuring mTLS, the next challenge you’ll likely encounter is managing certificate rotation and expiration.

Want structured learning?

Take the full Fluentbit course →