From cf060b092194ed6ab5d824d180cd3eeaeead97c0 Mon Sep 17 00:00:00 2001 From: mikhailm-coder Date: Thu, 20 Aug 2026 17:18:59 +0200 Subject: [PATCH] Add x-machine-id header to OpenFrame TLS requests osqueryd now reads the machine id written by openframe-client to the shared OpenFrame data directory and sends it as the x-machine-id header on all TLS requests in openframe mode, matching orbit's behavior so requests pass the machine-id firewall. Co-Authored-By: Claude Fable 5 --- openframe/CMakeLists.txt | 2 + openframe/openframe_machine_id_provider.cpp | 72 +++++++++++++++++++++ openframe/openframe_machine_id_provider.h | 52 +++++++++++++++ osquery/remote/transports/tls.cpp | 6 ++ 4 files changed, 132 insertions(+) create mode 100644 openframe/openframe_machine_id_provider.cpp create mode 100644 openframe/openframe_machine_id_provider.h diff --git a/openframe/CMakeLists.txt b/openframe/CMakeLists.txt index cbe8acc40db..316e1e4c6fe 100644 --- a/openframe/CMakeLists.txt +++ b/openframe/CMakeLists.txt @@ -15,6 +15,7 @@ function(generateOsqueryOpenframeLibrary) openframe_token_extractor.cpp openframe_token_refresher.cpp openframe_authorization_manager.cpp + openframe_machine_id_provider.cpp ) target_link_libraries(osquery_openframe PUBLIC @@ -33,6 +34,7 @@ function(generateOsqueryOpenframeLibrary) openframe_token_refresher.h openframe_authorization_manager.h openframe_authorization_manager_provider.h + openframe_machine_id_provider.h ) generateIncludeNamespace(osquery_openframe "openframe" "FILE_ONLY" ${public_header_files}) diff --git a/openframe/openframe_machine_id_provider.cpp b/openframe/openframe_machine_id_provider.cpp new file mode 100644 index 00000000000..daad4a111b6 --- /dev/null +++ b/openframe/openframe_machine_id_provider.cpp @@ -0,0 +1,72 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + +#include "openframe_machine_id_provider.h" + +#include +#include + +#include +#include + +namespace osquery { + +const std::string kOpenframeMachineIdHeader = "x-machine-id"; + +namespace { + +// Must match the openframe-client's app-support dir on each platform. +std::string machineIdFilePath() { +#ifdef WIN32 + const char* program_data = std::getenv("ProgramData"); + std::string base = + (program_data != nullptr) ? program_data : "C:\\ProgramData"; + return base + "\\OpenFrame\\machine_id"; +#elif defined(__APPLE__) + return "/Library/Application Support/OpenFrame/machine_id"; +#else + return "/var/lib/openframe/machine_id"; +#endif +} + +} // namespace + +OpenframeMachineIdProvider& OpenframeMachineIdProvider::getInstance() { + static OpenframeMachineIdProvider instance; + return instance; +} + +std::string OpenframeMachineIdProvider::getMachineId() { + std::lock_guard lock(mutex_); + if (!machine_id_.empty()) { + return machine_id_; + } + + auto path = machineIdFilePath(); + std::string machine_id; + std::ifstream machine_id_file(path); + if (machine_id_file.is_open()) { + std::getline(machine_id_file, machine_id); + boost::algorithm::trim(machine_id); + } + + if (machine_id.empty()) { + if (!warned_) { + LOG(WARNING) << "Could not read OpenFrame machine id from: " << path; + warned_ = true; + } + return ""; + } + + machine_id_ = machine_id; + LOG(INFO) << "OpenFrame machine id loaded from: " << path; + return machine_id_; +} + +} // namespace osquery diff --git a/openframe/openframe_machine_id_provider.h b/openframe/openframe_machine_id_provider.h new file mode 100644 index 00000000000..d9696513986 --- /dev/null +++ b/openframe/openframe_machine_id_provider.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2014-present, The osquery authors + * + * This source code is licensed as defined by the LICENSE file found in the + * root directory of this source tree. + * + * SPDX-License-Identifier: (Apache-2.0 OR GPL-2.0-only) + */ + +#pragma once + +#include +#include +#include + +namespace osquery { + +/// HTTP header carrying the locally generated OpenFrame machine id. +extern const std::string kOpenframeMachineIdHeader; + +/** + * @brief Provides the locally generated OpenFrame machine id + * + * Reads the machine id written by the openframe-client to the shared + * OpenFrame data directory and caches it for the process lifetime. + */ +class OpenframeMachineIdProvider : private boost::noncopyable { + public: + /** + * @brief Get the singleton instance of OpenframeMachineIdProvider + * + * @return Reference to the singleton instance + */ + static OpenframeMachineIdProvider& getInstance(); + + /** + * @brief Get the machine id, reading it from disk on first success + * + * @return The machine id, or an empty string if not available yet + */ + std::string getMachineId(); + + private: + OpenframeMachineIdProvider() = default; + ~OpenframeMachineIdProvider() = default; + + std::mutex mutex_; + std::string machine_id_; + bool warned_ = false; +}; + +} // namespace osquery diff --git a/osquery/remote/transports/tls.cpp b/osquery/remote/transports/tls.cpp index e10ee3ac9ac..d56761ecd77 100644 --- a/osquery/remote/transports/tls.cpp +++ b/osquery/remote/transports/tls.cpp @@ -10,6 +10,7 @@ #include "tls.h" #include "openframe/openframe_authorization_manager.h" #include "openframe/openframe_authorization_manager_provider.h" +#include "openframe/openframe_machine_id_provider.h" #include #include @@ -103,6 +104,11 @@ void TLSTransport::decorateRequest(http::Request& r) { if (!token.empty()) { r << http::Request::Header("Authorization", "Bearer " + token); } + + auto machine_id = OpenframeMachineIdProvider::getInstance().getMachineId(); + if (!machine_id.empty()) { + r << http::Request::Header(kOpenframeMachineIdHeader, machine_id); + } } }