Overview
The etcd Server is ML Defender’s distributed coordination hub, providing centralized configuration management , automatic crypto seed exchange , and service discovery for all components. Implemented in C++ with the etcd v3 API , it ensures consistent state across the entire pipeline.
Core Functions
Distributed Configuration : Single source of truth
Crypto Key Exchange : ChaCha20-Poly1305 seed distribution
Service Registration : Component discovery
Health Monitoring : Heartbeat tracking
Performance
<50ms service registration latency
<100ms crypto seed exchange
30-second heartbeat intervals
60-second lease TTL
Architecture
The etcd Server acts as the coordination layer between all ML Defender components:
Key-Value Store Structure
Crypto Keys
Configuration
Service Registry
Path : /crypto/<component>/tokens/crypto/
├── sniffer/tokens → ChaCha20-Poly1305 key (256-bit)
├── ml-detector/tokens → ChaCha20-Poly1305 key (256-bit)
└── firewall/tokens → ChaCha20-Poly1305 key (256-bit)
Purpose : Automatic encryption key distribution without manual key exchange.Path : /config/<component>/config/
├── sniffer/
│ ├── interface → "eth1"
│ ├── profile → "lab"
│ └── thresholds/ddos → 0.85
├── ml-detector/
│ ├── models/level1 → "level1_rf.onnx"
│ └── thresholds → {...}
└── firewall/
├── ipset_max_elements → 1000
└── batch_size → 10
Purpose : Runtime configuration updates without service restarts.Path : /services/<component>/services/
├── sniffer/
│ ├── node_id → "cpp_sniffer_v33_day12"
│ ├── version → "3.3.3"
│ ├── status → "healthy"
│ ├── last_heartbeat → 1638360000
│ └── endpoints/zmq_push → "tcp://127.0.0.1:5571"
├── ml-detector/
│ ├── partner_component → "sniffer"
│ └── endpoints/zmq_pub → "tcp://127.0.0.1:5572"
└── firewall/
├── partner_component → "ml-detector"
└── ipset_name → "ml_defender_blacklist_test"
Purpose : Dynamic service discovery and health monitoring.
Crypto Seed Exchange
The etcd Server automates ChaCha20-Poly1305 key distribution across the pipeline:
Key Exchange Flow
Component Registration
Sniffer registers with etcd Server on startup:// Sniffer registration request
POST http: //localhost:2379/register
{
"component" : "sniffer" ,
"version" : "3.3.3" ,
"node_id" : "cpp_sniffer_v33_day12" ,
"capabilities" : [ "ebpf" , "xdp" , "encryption" ]
}
etcd Generates Key
etcd Server generates a 256-bit ChaCha20-Poly1305 key:// etcd_server.cpp
std :: string ComponentRegistry :: get_encryption_key () {
if ( encryption_key_ . empty ()) {
// Generate 256-bit key (32 bytes)
encryption_key_ = generate_random_hex ( 32 );
}
return encryption_key_;
}
Key Stored in etcd
Key persisted in etcd key-value store:etcdctl put /crypto/sniffer/tokens "a1b2c3d4e5f6..."
Downstream Components Retrieve
ML Detector and Firewall Agent retrieve the key:// ML Detector retrieves key
std ::string key = etcd_client . get ( "/crypto/sniffer/tokens" );
crypto_transport :: set_decryption_key (key);
Security : Keys are generated once at component registration and rotated every 24 hours automatically.
Service Registration & Heartbeats
Registration Protocol
Registration Request
Registration Response
Heartbeat
POST /register
{
"component" : "ml-detector" ,
"version" : "1.0.0" ,
"node_id" : "ml-detector-default" ,
"endpoints" : {
"zmq_pull" : "tcp://127.0.0.1:5571" ,
"zmq_pub" : "tcp://127.0.0.1:5572"
},
"partner_component" : "sniffer" ,
"capabilities" : [
"tricapa_classification" ,
"onnx_inference" ,
"encryption" ,
"compression"
]
}
{
"status" : "success" ,
"message" : "Component registered successfully" ,
"component" : "ml-detector" ,
"encryption_key" : "a1b2c3d4e5f6789..." ,
"lease_id" : 7587869823761236487 ,
"ttl" : 60
}
PUT /heartbeat
{
"component" : "ml-detector" ,
"node_id" : "ml-detector-default" ,
"timestamp" : 1638360000 ,
"status" : "healthy" ,
"metrics" : {
"events_processed" : 1847234 ,
"latency_ms" : 3.5 ,
"cpu_usage" : 0.42
}
}
Interval : Every 30 secondsLease Renewal : Automatically extends 60-second TTL
Health Monitoring
Health Check (etcd_server.cpp)
// Check if component is healthy (heartbeat within TTL)
bool ComponentRegistry :: is_component_healthy (
const std :: string & component_name
) {
auto it = components_ . find (component_name);
if (it == components_ . end ()) return false ;
auto now = std :: chrono :: system_clock :: now ();
auto last_heartbeat = it -> second . last_heartbeat ;
auto diff = std :: chrono :: duration_cast < std :: chrono :: seconds >(
now - last_heartbeat
);
// Unhealthy if no heartbeat in 90 seconds (1.5x TTL)
return diff . count () < 90 ;
}
C++ Implementation
The etcd Server is implemented in modern C++ using the httplib library for HTTP endpoints:
Server Core
Component Registry
Configuration Validation
// etcd_server/src/etcd_server.cpp
#include "etcd_server/etcd_server.hpp"
#include "httplib.h"
#include <nlohmann/json.hpp>
using json = nlohmann :: json ;
void EtcdServer :: run_server () {
httplib ::Server server;
// Registration endpoint
server . Post ( "/register" , [ this ]( const httplib :: Request & req ,
httplib :: Response & res ) {
try {
auto json_body = json :: parse ( req . body );
std ::string component_name = json_body [ "component" ];
if ( component_registry_ -> register_component (
component_name, req . body
)) {
json response = {
{ "status" , "success" },
{ "component" , component_name},
{ "encryption_key" ,
component_registry_ -> get_encryption_key ()}
};
res . set_content ( response . dump (), "application/json" );
} else {
res . status = 400 ;
res . set_content (
R"({"status": "error"})" ,
"application/json"
);
}
} catch ( const std ::exception & e) {
res . status = 400 ;
json error = {
{ "status" , "error" },
{ "message" , "JSON invalid" },
{ "details" , e . what ()}
};
res . set_content ( error . dump (), "application/json" );
}
});
// Listen on port 2379
server . listen ( "0.0.0.0" , port_);
}
// etcd_server/include/etcd_server/component_registry.hpp
class ComponentRegistry {
public:
bool register_component (
const std :: string & component_name ,
const std :: string & config_json
);
std :: string get_component_config (
const std :: string & component_name
);
bool update_component_config (
const std :: string & component_name ,
const std :: string & config_path ,
const std :: string & value
);
std :: string get_encryption_key ();
bool is_component_healthy (
const std :: string & component_name
);
private:
std ::unordered_map < std ::string, ComponentInfo > components_;
std ::string encryption_key_;
std ::mutex registry_mutex_;
};
// Validate component configuration consistency
std :: string ComponentRegistry :: validate_configuration () {
json validation_report;
for ( const auto & [name, info] : components_) {
json component_report;
// Check required fields
if ( info . config . contains ( "encryption" ) &&
info . config [ "encryption" ][ "enabled" ]) {
if ( encryption_key_ . empty ()) {
component_report [ "warnings" ]. push_back (
"Encryption enabled but no key generated"
);
}
}
// Check partner components exist
if ( info . config . contains ( "partner_component" )) {
std ::string partner =
info . config [ "partner_component" ];
if ( components_ . find (partner) == components_ . end ()) {
component_report [ "errors" ]. push_back (
"Partner component not registered: " + partner
);
}
}
validation_report [name] = component_report;
}
return validation_report . dump ( 2 );
}
Configuration
etcd Server Configuration
{
"server" : {
"port" : 2379 ,
"bind_address" : "0.0.0.0" ,
"enable_tls" : false ,
"max_connections" : 100
},
"storage" : {
"backend" : "in_memory" ,
"persist_to_disk" : false ,
"data_dir" : "/var/lib/ml-defender/etcd"
},
"crypto" : {
"key_generation" : "automatic" ,
"key_rotation_hours" : 24 ,
"key_length_bits" : 256
},
"lease" : {
"default_ttl_seconds" : 60 ,
"min_ttl_seconds" : 10 ,
"max_ttl_seconds" : 3600
},
"logging" : {
"level" : "info" ,
"file" : "/vagrant/logs/lab/etcd-server.log"
}
}
Client Configuration (per component)
Sniffer etcd Client Config
ML Detector etcd Client Config
{
"etcd" : {
"enabled" : true ,
"endpoints" : [ "localhost:2379" ],
"connection_timeout_ms" : 5000 ,
"retry_attempts" : 3 ,
"retry_interval_ms" : 1000 ,
"crypto_token_path" : "/crypto/sniffer/tokens" ,
"config_sync_path" : "/config/sniffer" ,
"required_for_encryption" : true ,
"heartbeat_interval_seconds" : 30 ,
"lease_ttl_seconds" : 60
}
}
Deployment
Prerequisites
sudo apt-get install -y \
build-essential cmake \
nlohmann-json3-dev \
libssl-dev
Build
Navigate
cd /vagrant/etcd-server
mkdir -p build && cd build
Configure
cmake .. -DCMAKE_BUILD_TYPE=Release
Run
Standalone
With Custom Port
Background Daemon
Real-time Output:
[ETCD-SERVER] 🔧 Initializing server on port 2379
[ETCD-SERVER] 🚀 Server started
[ETCD-SERVER] 📝 POST /register received
[ETCD-SERVER] ✅ Component registered: sniffer
[ETCD-SERVER] 🔐 Generated encryption key: a1b2c3d4...
[ETCD-SERVER] 📝 POST /register received
[ETCD-SERVER] ✅ Component registered: ml-detector
[ETCD-SERVER] ❤️ Heartbeat received: sniffer (healthy)
API Reference
REST Endpoints
POST /register - Register Component
Request: {
"component" : "sniffer" ,
"version" : "3.3.3" ,
"node_id" : "cpp_sniffer_v33_day12" ,
"capabilities" : [ "ebpf" , "xdp" ]
}
Response (200 OK): {
"status" : "success" ,
"message" : "Component registered successfully" ,
"component" : "sniffer" ,
"encryption_key" : "a1b2c3d4e5f6789..."
}
PUT /heartbeat - Send Heartbeat
Request: {
"component" : "ml-detector" ,
"node_id" : "ml-detector-default" ,
"timestamp" : 1638360000 ,
"status" : "healthy"
}
Response (200 OK): {
"status" : "success" ,
"lease_renewed" : true ,
"ttl_remaining" : 60
}
GET /config/:component - Get Configuration
Request: curl http://localhost:2379/config/sniffer
Response (200 OK): {
"interface" : "eth1" ,
"profile" : "lab" ,
"thresholds" : {
"ddos" : 0.85 ,
"ransomware" : 0.90
}
}
PUT /config/:component/:path - Update Configuration
Request: PUT /config/sniffer/thresholds.ddos
{
"value" : 0.90
}
Response (200 OK): {
"status" : "success" ,
"updated" : "thresholds.ddos" ,
"old_value" : 0.85 ,
"new_value" : 0.90
}
GET /validate - Validate Configuration
Request: curl http://localhost:2379/validate
Response (200 OK): {
"sniffer" : {
"warnings" : [],
"errors" : []
},
"ml-detector" : {
"warnings" : [],
"errors" : []
},
"firewall" : {
"warnings" : [
"IPSet capacity approaching limit (900/1000)"
],
"errors" : []
}
}
Troubleshooting
Components Cannot Connect
# Check etcd Server is running
netstat -tulpn | grep 2379
# Test HTTP endpoint
curl http://localhost:2379/health
# Check firewall rules
sudo iptables -L -n | grep 2379
# Enable verbose logging
./etcd_server --log-level debug
# Check component JSON is valid
echo '{"component": "test"}' | jq .
# Verify HTTP POST
curl -X POST http://localhost:2379/register \
-H 'Content-Type: application/json' \
-d '{"component": "test"}'
Symptom : Components marked as unhealthy after 90 secondsSolution : Increase heartbeat frequency or TTL:{
"etcd" : {
"heartbeat_interval_seconds" : 20 , // From 30
"lease_ttl_seconds" : 90 // From 60
}
}
Next Steps
Sniffer Configure network packet capture
ML Detector Set up ML inference pipeline
Firewall Agent Deploy autonomous blocking
Distributed Deployment Multi-node etcd cluster setup