Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions include/fluent-bit/flb_io.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@

/* Other features */
#define FLB_IO_IPV6 128 /* network I/O uses IPv6 */
#define FLB_IO_PROXY_TLS 256 /* connection-scoped: an HTTPS proxy TLS
* session is active on this connection.
* Independent of FLB_IO_TLS, which
* describes the destination stream: must
* only ever be set on struct
* flb_connection.flags, never on the
* shared stream/upstream flags. */

struct flb_connection;

Expand Down
13 changes: 13 additions & 0 deletions include/fluent-bit/flb_output.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,16 @@ struct flb_output_instance {
int tls_win_use_enterprise_certstore; /* Use enterprise CertStore */
char *tls_win_thumbprints; /* CertStore Thumbprints (Windows) */
# endif

/*
* HTTPS proxy TLS settings: independent from the destination tls.*
* settings above, since the proxy leg and the destination leg are
* different TLS peers.
*/
int tls_proxy_verify; /* Verify proxy cert (default: true) */
int tls_proxy_verify_hostname; /* Verify proxy hostname (default: true) */
char *tls_proxy_ca_path; /* Path to CA certs for proxy verification */
char *tls_proxy_ca_file; /* CA root cert for proxy verification */
#endif

/*
Expand Down Expand Up @@ -1423,6 +1433,9 @@ int flb_output_oauth2_property_check(struct flb_output_instance *ins,
struct flb_config *config);
int flb_output_plugin_property_check(struct flb_output_instance *ins,
struct flb_config *config);
#ifdef FLB_HAVE_TLS
int flb_output_proxy_tls_ca_check(struct flb_output_instance *ins);
#endif
int flb_output_init_all(struct flb_config *config);
int flb_output_check(struct flb_config *config);
int flb_output_log_check(struct flb_output_instance *ins, int l);
Expand Down
13 changes: 13 additions & 0 deletions include/fluent-bit/flb_upstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@
#include <fluent-bit/flb_upstream_queue.h>
#include <fluent-bit/flb_stream.h>

#ifdef FLB_HAVE_TLS
#include <fluent-bit/tls/flb_tls.h>
#endif

#include <cmetrics/cmetrics.h>
#include <cmetrics/cmt_gauge.h>

Expand Down Expand Up @@ -59,6 +63,9 @@ struct flb_upstream {
int proxied_port;
char *proxy_username;
char *proxy_password;
#ifdef FLB_HAVE_TLS
struct flb_tls *proxy_tls_context; /* TLS context for the proxy (https proxy) */
#endif

/*
* If an upstream context has been created in HA mode, this flag is
Expand Down Expand Up @@ -101,6 +108,12 @@ struct flb_upstream *flb_upstream_create_url(struct flb_config *config,

int flb_upstream_destroy(struct flb_upstream *u);

#ifdef FLB_HAVE_TLS
int flb_upstream_proxy_tls_setup(struct flb_upstream *u,
int verify, int verify_hostname,
const char *ca_path, const char *ca_file);
#endif

int flb_upstream_set_property(struct flb_config *config,
struct flb_net_setup *net, char *k, char *v);
int flb_upstream_is_async(struct flb_upstream *u);
Expand Down
8 changes: 8 additions & 0 deletions include/fluent-bit/tls/flb_tls.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,14 @@ struct flb_tls_backend {
void (*session_invalidate) (void *);
int (*session_destroy) (void *);
const char *(*session_alpn_get) (void *);
/*
* Chain an inner TLS session's I/O through an outer TLS session.
* Used for TLS-in-TLS when connecting through an HTTPS proxy: after
* HTTP CONNECT is established over the proxy TLS, the destination TLS
* handshake data must be sent through (and encrypted by) the proxy TLS.
* Optional: may be NULL if the backend does not support it.
*/
int (*session_set_outer) (void *inner, void *outer);

/* I/O */
int (*net_read) (struct flb_tls_session *, void *, size_t);
Expand Down
41 changes: 39 additions & 2 deletions src/flb_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,43 @@ int flb_io_net_connect(struct flb_connection *connection,

if (connection->stream->transport == FLB_TRANSPORT_TCP &&
connection->upstream->proxied_host) {
#ifdef FLB_HAVE_TLS
/*
* When the proxy URL uses https://, the connection to the proxy
* itself must be TLS-wrapped before the HTTP CONNECT tunnel is
* established. Use the dedicated proxy TLS context which carries
* the proxy hostname as the SNI (vhost).
*/
if (connection->upstream->proxy_tls_context != NULL) {
ret = flb_tls_session_create(connection->upstream->proxy_tls_context,
connection,
coro);
if (ret != 0) {
flb_debug("[http_client] proxy TLS handshake failed for %s:%i",
connection->upstream->tcp_host,
connection->upstream->tcp_port);
flb_socket_close(fd);
connection->fd = -1;
connection->event.fd = -1;
return -1;
}
/*
* Ensure all I/O (the CONNECT request and any subsequent
* data) is routed through the proxy TLS session. This must be
* a connection-scoped flag, not a stream-level one: the
* stream/upstream object is shared across every connection to
* this destination, and flb_io_net_write/read only need a
* per-connection signal to decide whether to use
* connection->tls_session. Setting the stream's FLB_IO_TLS
* flag here would permanently mark the destination itself as
* TLS-enabled, which corrupts destination-specific behavior
* for plain-HTTP destinations (e.g. Host header port handling
* in flb_http_client.c), even though only the proxy leg uses
* TLS.
*/
flb_connection_enable_flags(connection, FLB_IO_PROXY_TLS);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
#endif
ret = flb_http_client_proxy_connect(connection);

if (ret == -1) {
Expand Down Expand Up @@ -762,7 +799,7 @@ int flb_io_net_write(struct flb_connection *connection, const void *data,
}
}
#ifdef FLB_HAVE_TLS
else if (flags & (FLB_IO_TLS | FLB_IO_DTLS)) {
else if (flags & (FLB_IO_TLS | FLB_IO_DTLS | FLB_IO_PROXY_TLS)) {
if (flags & FLB_IO_ASYNC) {
ret = flb_tls_net_write_async(coro, connection->tls_session, data, len, out_len);
}
Expand Down Expand Up @@ -814,7 +851,7 @@ ssize_t flb_io_net_read(struct flb_connection *connection, void *buf, size_t len
}
}
#ifdef FLB_HAVE_TLS
else if (flags & (FLB_IO_TLS | FLB_IO_DTLS)) {
else if (flags & (FLB_IO_TLS | FLB_IO_DTLS | FLB_IO_PROXY_TLS)) {
if (flags & FLB_IO_ASYNC) {
ret = flb_tls_net_read_async(coro, connection->tls_session, buf, len);
}
Expand Down
82 changes: 82 additions & 0 deletions src/flb_output.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,12 @@ static void flb_output_free_properties(struct flb_output_instance *ins)
if (ins->tls_ciphers) {
flb_sds_destroy(ins->tls_ciphers);
}
if (ins->tls_proxy_ca_path) {
flb_sds_destroy(ins->tls_proxy_ca_path);
}
if (ins->tls_proxy_ca_file) {
flb_sds_destroy(ins->tls_proxy_ca_file);
}
# if defined(FLB_SYSTEM_WINDOWS)
if (ins->tls_win_certstore_name) {
flb_sds_destroy(ins->tls_win_certstore_name);
Expand Down Expand Up @@ -849,6 +855,10 @@ struct flb_output_instance *flb_output_new(struct flb_config *config,
instance->tls_win_use_enterprise_certstore = FLB_FALSE;
instance->tls_win_thumbprints = NULL;
# endif
instance->tls_proxy_verify = FLB_TRUE;
instance->tls_proxy_verify_hostname = FLB_TRUE;
instance->tls_proxy_ca_path = NULL;
instance->tls_proxy_ca_file = NULL;
#endif

if (plugin->flags & FLB_OUTPUT_NET) {
Expand Down Expand Up @@ -1114,6 +1124,20 @@ int flb_output_set_property(struct flb_output_instance *ins,
else if (prop_key_check("tls.ciphers", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.ciphers", &ins->tls_ciphers, tmp);
}
else if (prop_key_check("tls.proxy.verify", k, len) == 0 && tmp) {
ins->tls_proxy_verify = flb_utils_bool(tmp);
flb_sds_destroy(tmp);
}
else if (prop_key_check("tls.proxy.verify_hostname", k, len) == 0 && tmp) {
ins->tls_proxy_verify_hostname = flb_utils_bool(tmp);
flb_sds_destroy(tmp);
}
else if (prop_key_check("tls.proxy.ca_path", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.proxy.ca_path", &ins->tls_proxy_ca_path, tmp);
}
else if (prop_key_check("tls.proxy.ca_file", k, len) == 0) {
flb_utils_set_plugin_string_property("tls.proxy.ca_file", &ins->tls_proxy_ca_file, tmp);
}
# if defined(FLB_SYSTEM_WINDOWS)
else if (prop_key_check("tls.windows.certstore_name", k, len) == 0 && tmp) {
flb_utils_set_plugin_string_property("tls.windows.certstore_name", &ins->tls_win_certstore_name, tmp);
Expand Down Expand Up @@ -1383,6 +1407,36 @@ int flb_output_plugin_property_check(struct flb_output_instance *ins,
return 0;
}

#ifdef FLB_HAVE_TLS
/* Eagerly validate tls.proxy.ca_file/ca_path so a bad path fails init here,
* instead of being silently ignored later in flb_output_upstream_set(). */
int flb_output_proxy_tls_ca_check(struct flb_output_instance *ins)
{
struct flb_tls *tls_proxy_validate;

if (ins->tls_proxy_ca_file == NULL && ins->tls_proxy_ca_path == NULL) {
return 0;
}

tls_proxy_validate = flb_tls_create(FLB_TLS_CLIENT_MODE,
ins->tls_proxy_verify,
0,
NULL,
ins->tls_proxy_ca_path,
ins->tls_proxy_ca_file,
NULL, NULL, NULL);
if (!tls_proxy_validate) {
flb_error("[output %s] error initializing TLS context for "
"tls.proxy.ca_file/tls.proxy.ca_path",
ins->name);
return -1;
}

flb_tls_destroy(tls_proxy_validate);
return 0;
}
#endif

/* Trigger the output plugins setup callbacks to prepare them. */
int flb_output_init_all(struct flb_config *config)
{
Expand Down Expand Up @@ -1681,6 +1735,11 @@ int flb_output_init_all(struct flb_config *config)
}
# endif
}

if (flb_output_proxy_tls_ca_check(ins) == -1) {
flb_output_instance_destroy(ins);
return -1;
}
#endif
/*
* Before to call the initialization callback, make sure that the received
Expand Down Expand Up @@ -1894,7 +1953,30 @@ int flb_output_upstream_set(struct flb_upstream *u, struct flb_output_instance *
flb_free(u->proxy_password);
u->proxy_password = NULL;
}

#ifdef FLB_HAVE_TLS
if (u->proxy_tls_context) {
flb_tls_destroy(u->proxy_tls_context);
u->proxy_tls_context = NULL;
}
#endif
}

#ifdef FLB_HAVE_TLS
/*
* If flb_upstream_create() built a proxy TLS context (HTTPS proxy in
* effect), reconfigure it using this instance's tls.proxy.* settings
* instead of the hardcoded defaults. Independent from ins->tls*
* (destination TLS settings) by design.
*/
if (u->proxy_tls_context != NULL) {
flb_upstream_proxy_tls_setup(u,
ins->tls_proxy_verify,
ins->tls_proxy_verify_hostname,
ins->tls_proxy_ca_path,
ins->tls_proxy_ca_file);
}
#endif

return 0;
}
Expand Down
Loading
Loading