Merge 92d5771e4c into 39bf0d3c6a
This commit is contained in:
commit
582c8ff0b2
|
|
@ -3010,6 +3010,22 @@ common_params_context common_params_parser_init(common_params & params, llama_ex
|
|||
}
|
||||
}
|
||||
).set_examples({LLAMA_EXAMPLE_SERVER}));
|
||||
add_opt(
|
||||
common_arg(
|
||||
{ "--security-log-folder" }, "PATH",
|
||||
"directory for security audit logs; creates dated log files security_YYYY-MM-DD.log (default: disabled)",
|
||||
[](common_params & params, const std::string & value) {
|
||||
params.security_log_folder = value;
|
||||
if (!fs_is_directory(params.security_log_folder)) {
|
||||
throw std::invalid_argument("not a directory: " + value);
|
||||
}
|
||||
// if doesn't end with DIRECTORY_SEPARATOR, add it
|
||||
if (!params.security_log_folder.empty() &&
|
||||
params.security_log_folder[params.security_log_folder.size() - 1] != DIRECTORY_SEPARATOR) {
|
||||
params.security_log_folder += DIRECTORY_SEPARATOR;
|
||||
}
|
||||
})
|
||||
.set_examples({ LLAMA_EXAMPLE_SERVER }));
|
||||
add_opt(common_arg(
|
||||
{"--models-dir"}, "PATH",
|
||||
"directory containing models for the router server (default: disabled)",
|
||||
|
|
@ -3881,4 +3897,4 @@ void common_params_add_preset_options(std::vector<common_arg> & args) {
|
|||
// "in server router mode, do not unload this model if models_max is exceeded",
|
||||
// [](common_params &) { /* unused */ }
|
||||
// ).set_preset_only());
|
||||
}
|
||||
}
|
||||
|
|
@ -622,7 +622,8 @@ struct common_params {
|
|||
bool log_json = false;
|
||||
|
||||
std::string slot_save_path;
|
||||
std::string media_path; // path to directory for loading media files
|
||||
std::string media_path; // path to directory for loading media files
|
||||
std::string security_log_folder; // path to directory for security audit logs
|
||||
|
||||
float slot_prompt_similarity = 0.1f;
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,9 @@
|
|||
|
||||
#include "server-common.h"
|
||||
|
||||
#include <ctime>
|
||||
#include <fstream>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <fstream>
|
||||
|
|
@ -613,6 +616,7 @@ json json_get_nested_values(const std::vector<std::string> & paths, const json &
|
|||
result[path] = current;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
|
@ -763,9 +767,18 @@ static server_tokens tokenize_input_subprompt(const llama_vocab * vocab, mtmd_co
|
|||
llama_tokens tmp = tokenize_mixed(vocab, json_prompt.at(JSON_STRING_PROMPT_KEY), add_special, parse_special);
|
||||
return server_tokens(tmp, false);
|
||||
}
|
||||
<<<<<<< HEAD
|
||||
} else {
|
||||
throw std::runtime_error("\"prompt\" elements must be a string, a list of tokens, a JSON object containing a prompt string, or a list of mixed strings & tokens.");
|
||||
}
|
||||
=======
|
||||
} else {
|
||||
throw std::runtime_error(
|
||||
"\"prompt\" elements must be a string, a list of tokens, a JSON object containing a prompt string, or "
|
||||
"a "
|
||||
"list of mixed strings & tokens.");
|
||||
}
|
||||
>>>>>>> 6325a9c4 (server: implement security audit logging functions)
|
||||
}
|
||||
|
||||
std::vector<server_tokens> tokenize_input_prompts(const llama_vocab * vocab, mtmd_context * mctx, const json & json_prompt, bool add_special, bool parse_special) {
|
||||
|
|
@ -2071,3 +2084,110 @@ server_tokens format_prompt_rerank(
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
// security logging implementation
|
||||
static struct common_log * g_security_log = nullptr;
|
||||
static std::string g_security_log_folder;
|
||||
static std::string g_current_log_file;
|
||||
static std::mutex g_security_log_mutex;
|
||||
|
||||
static std::string get_current_date_string() {
|
||||
std::time_t t = std::time(nullptr);
|
||||
std::tm tm = *std::localtime(&t);
|
||||
char buffer[11];
|
||||
std::strftime(buffer, sizeof(buffer), "%Y-%m-%d", &tm);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
static void rotate_security_log_if_needed() {
|
||||
std::lock_guard<std::mutex> lock(g_security_log_mutex);
|
||||
|
||||
if (g_security_log_folder.empty() || !g_security_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string current_date = get_current_date_string();
|
||||
std::string new_log_file = g_security_log_folder + "/security_" + current_date + ".log";
|
||||
|
||||
if (new_log_file != g_current_log_file) {
|
||||
// Close old file if any
|
||||
if (!g_current_log_file.empty()) {
|
||||
common_log_set_file(g_security_log, nullptr);
|
||||
}
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
if (!fs_create_directory_with_parents(g_security_log_folder)) {
|
||||
LOG_WRN("Failed to create security log directory: %s\n", g_security_log_folder.c_str());
|
||||
}
|
||||
|
||||
// Set new log file
|
||||
common_log_set_file(g_security_log, new_log_file.c_str());
|
||||
common_log_set_prefix(g_security_log, false);
|
||||
common_log_set_timestamps(g_security_log, true);
|
||||
|
||||
g_current_log_file = new_log_file;
|
||||
|
||||
LOG_INF("Security logging started: %s\n", new_log_file.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void security_log_init(const std::string & folder_path) {
|
||||
std::lock_guard<std::mutex> lock(g_security_log_mutex);
|
||||
|
||||
if (folder_path.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_security_log_folder = folder_path;
|
||||
g_security_log = common_log_init();
|
||||
|
||||
if (!g_security_log) {
|
||||
LOG_ERR("Failed to initialize security log\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Set initial log file
|
||||
rotate_security_log_if_needed();
|
||||
}
|
||||
|
||||
void security_log_cleanup() {
|
||||
std::lock_guard<std::mutex> lock(g_security_log_mutex);
|
||||
|
||||
if (g_security_log) {
|
||||
common_log_free(g_security_log);
|
||||
g_security_log = nullptr;
|
||||
}
|
||||
|
||||
g_security_log_folder.clear();
|
||||
g_current_log_file.clear();
|
||||
}
|
||||
|
||||
void security_log_audit_event(const std::string & event_type,
|
||||
const std::string & endpoint,
|
||||
const std::string & method,
|
||||
const std::string & remote_addr,
|
||||
const std::string & api_key_name,
|
||||
const std::string & details) {
|
||||
std::lock_guard<std::mutex> lock(g_security_log_mutex);
|
||||
|
||||
if (!g_security_log) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Rotate log file if date changed
|
||||
rotate_security_log_if_needed();
|
||||
|
||||
// Create JSON log entry
|
||||
json log_entry = {
|
||||
{"timestamp", std::time(nullptr)},
|
||||
{ "event_type", event_type },
|
||||
{ "endpoint", endpoint },
|
||||
{ "method", method },
|
||||
{ "remote_addr", remote_addr },
|
||||
{ "api_key_name", api_key_name },
|
||||
{ "details", details }
|
||||
};
|
||||
|
||||
// Write as JSON line
|
||||
common_log_add(g_security_log, GGML_LOG_LEVEL_NONE, "%s\n", log_entry.dump().c_str());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -366,9 +366,18 @@ llama_tokens format_prompt_infill(
|
|||
const llama_tokens & tokens_prompt);
|
||||
|
||||
// format rerank task: [BOS]query[EOS][SEP]doc[EOS].
|
||||
server_tokens format_prompt_rerank(
|
||||
const struct llama_model * model,
|
||||
const struct llama_vocab * vocab,
|
||||
mtmd_context * mctx,
|
||||
const std::string & query,
|
||||
const std::string & doc);
|
||||
server_tokens format_prompt_rerank(const struct llama_model * model,
|
||||
const struct llama_vocab * vocab,
|
||||
mtmd_context * mctx,
|
||||
const std::string & query,
|
||||
const std::string & doc);
|
||||
|
||||
// security logging
|
||||
void security_log_init(const std::string & folder_path);
|
||||
void security_log_cleanup();
|
||||
void security_log_audit_event(const std::string & event_type,
|
||||
const std::string & endpoint,
|
||||
const std::string & method,
|
||||
const std::string & remote_addr,
|
||||
const std::string & api_key_name,
|
||||
const std::string & details);
|
||||
|
|
|
|||
|
|
@ -155,12 +155,24 @@ bool server_http_context::init(const common_params & params) {
|
|||
req_api_key = req_api_key.substr(prefix.size());
|
||||
}
|
||||
|
||||
// audit logging for missing API key
|
||||
if (req_api_key.empty()) {
|
||||
security_log_audit_event("auth_failure", req.path, req.method, req.remote_addr, "missing",
|
||||
"No API key provided");
|
||||
}
|
||||
|
||||
// validate the API key
|
||||
if (std::find(api_keys.begin(), api_keys.end(), req_api_key) != api_keys.end()) {
|
||||
security_log_audit_event("auth_success", req.path, req.method, req.remote_addr, "provided",
|
||||
"API key validated");
|
||||
return true; // API key is valid
|
||||
}
|
||||
|
||||
// API key is invalid or not provided
|
||||
if (!req_api_key.empty()) {
|
||||
security_log_audit_event("auth_failure", req.path, req.method, req.remote_addr, "invalid",
|
||||
"Invalid API key provided");
|
||||
}
|
||||
res.status = 401;
|
||||
res.set_content(
|
||||
safe_json_to_str(json {
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ int main(int argc, char ** argv) {
|
|||
}
|
||||
|
||||
common_init();
|
||||
security_log_init(params.security_log_folder);
|
||||
|
||||
// struct that contains llama context and inference
|
||||
server_context ctx_server;
|
||||
|
|
@ -226,6 +227,7 @@ int main(int argc, char ** argv) {
|
|||
if (models_routes.has_value()) {
|
||||
models_routes->models.unload_all();
|
||||
}
|
||||
security_log_cleanup();
|
||||
llama_backend_free();
|
||||
};
|
||||
|
||||
|
|
@ -246,6 +248,7 @@ int main(int argc, char ** argv) {
|
|||
SRV_INF("%s: cleaning up before exit...\n", __func__);
|
||||
ctx_http.stop();
|
||||
ctx_server.terminate();
|
||||
security_log_cleanup();
|
||||
llama_backend_free();
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue