refactor(ebpf): simplify web server configuration with server list

Refactor uprobes configuration to use a single server list instead
of separate nginx_bin_path and apache_enabled options.

Configuration changes:
- Uprobes.Servers: []string (was: NginxBinPath + ApacheEnabled)
  - Accepts: ["nginx"], ["apache"], or ["nginx", "apache"]
  - Can also use "both" to enable both servers
- Environment variable: JA4EBPF_UPROBES_SERVERS (was: separate vars)

Examples:
  YAML:
    uprobes:
      enabled: true
      servers: ["nginx", "apache"]

  Environment:
    JA4EBPF_UPROBES_SERVERS=nginx,apache

Code changes:
- Generic loop over cfg.Uprobes.Servers for attachment and consumption
- Remove duplicate checks for Enabled/ApacheEnabled
- Update attachNginxUprobesWithRetry to use default nginx path
- Update attachApacheUprobesWithRetry to remove ApacheEnabled check
- Update documentation to reflect both nginx and apache support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jacquin Antoine
2026-04-20 13:43:32 +02:00
parent 7dfe640003
commit cba1cca180
2 changed files with 55 additions and 37 deletions

View File

@ -64,11 +64,10 @@ type Config struct {
} `yaml:"log"`
Uprobes struct {
Enabled bool `yaml:"enabled"` // activer l'attachement automatique des uprobes
NginxBinPath string `yaml:"nginx_bin_path"` // chemin vers le binaire nginx
ApacheEnabled bool `yaml:"apache_enabled"` // activer la capture Apache httpd
MaxRetries int `yaml:"max_retries"` // nombre de tentatives d'attachement (défaut: 30)
RetryIntervalSec int `yaml:"retry_interval_sec"` // intervalle entre tentatives (défaut: 2)
Enabled bool `yaml:"enabled"` // activer l'attachement automatique des uprobes
Servers []string `yaml:"servers"` // serveurs web à capturer: ["nginx", "apache", "both"]
MaxRetries int `yaml:"max_retries"` // nombre de tentatives d'attachement (défaut: 30)
RetryIntervalSec int `yaml:"retry_interval_sec"` // intervalle entre tentatives (défaut: 2)
} `yaml:"uprobes"`
}
@ -89,8 +88,7 @@ func loadConfig(path string) (*Config, error) {
cfg.Log.Level = "info"
cfg.Log.Format = "json"
cfg.Uprobes.Enabled = false
cfg.Uprobes.NginxBinPath = "/usr/sbin/nginx"
cfg.Uprobes.ApacheEnabled = false
cfg.Uprobes.Servers = []string{} // vide par défaut, peut être ["nginx"], ["apache"], ["nginx", "apache"]
cfg.Uprobes.MaxRetries = 30
cfg.Uprobes.RetryIntervalSec = 2
@ -140,11 +138,17 @@ func loadConfig(path string) (*Config, error) {
if v := os.Getenv("JA4EBPF_UPROBES_ENABLED"); v != "" {
cfg.Uprobes.Enabled = strings.EqualFold(v, "true") || v == "1" || v == "yes"
}
if v := os.Getenv("JA4EBPF_NGINX_BIN_PATH"); v != "" {
cfg.Uprobes.NginxBinPath = v
}
if v := os.Getenv("JA4EBPF_APACHE_ENABLED"); v != "" {
cfg.Uprobes.ApacheEnabled = strings.EqualFold(v, "true") || v == "1" || v == "yes"
if v := os.Getenv("JA4EBPF_UPROBES_SERVERS"); v != "" {
// Accepte une liste séparée par des virgules: "nginx,apache" ou "both" pour les deux
if strings.EqualFold(v, "both") {
cfg.Uprobes.Servers = []string{"nginx", "apache"}
} else {
cfg.Uprobes.Servers = strings.Split(v, ",")
// Normaliser les noms de serveurs (trim whitespace et lowercase)
for i, s := range cfg.Uprobes.Servers {
cfg.Uprobes.Servers[i] = strings.ToLower(strings.TrimSpace(s))
}
}
}
@ -295,15 +299,21 @@ func main() {
log.Printf("[ja4ebpf] avertissement tracepoint accept4: %v", err)
}
// --- 4b. Attachement uprobes nginx (avec retry automatique) ---
if err := attachNginxUprobesWithRetry(ctx, ldr, cfg); err != nil {
log.Printf("[ja4ebpf] erreur attachement uprobes nginx: %v", err)
}
// --- 4c. Attachement uprobes Apache httpd ---
if cfg.Uprobes.ApacheEnabled {
if err := attachApacheUprobesWithRetry(ctx, ldr, cfg); err != nil {
log.Printf("[ja4ebpf] erreur attachement uprobes Apache: %v", err)
// --- 4b. Attachement uprobes serveurs web (nginx, apache) ---
if cfg.Uprobes.Enabled && len(cfg.Uprobes.Servers) > 0 {
for _, server := range cfg.Uprobes.Servers {
switch server {
case "nginx":
if err := attachNginxUprobesWithRetry(ctx, ldr, cfg); err != nil {
log.Printf("[ja4ebpf] erreur attachement uprobes nginx: %v", err)
}
case "apache":
if err := attachApacheUprobesWithRetry(ctx, ldr, cfg); err != nil {
log.Printf("[ja4ebpf] erreur attachement uprobes Apache: %v", err)
}
default:
log.Printf("[ja4ebpf] avertissement: serveur web inconnu '%s' (options: nginx, apache)", server)
}
}
}
@ -351,9 +361,14 @@ func main() {
// --- 8. Compteurs d'événements consommés (mode debug) ---
consumed := &eventCounters{}
go consumeNginxHTTPEvents(ctx, ldr.NginxHTTPReader, mgr, &consumed.nginx)
if cfg.Uprobes.ApacheEnabled {
go consumeApacheHTTPEvents(ctx, ldr.ApacheHTTPReader, mgr, &consumed.apache)
// Démarrer les goroutines de consommation pour chaque serveur configuré
for _, server := range cfg.Uprobes.Servers {
switch server {
case "nginx":
go consumeNginxHTTPEvents(ctx, ldr.NginxHTTPReader, mgr, &consumed.nginx)
case "apache":
go consumeApacheHTTPEvents(ctx, ldr.ApacheHTTPReader, mgr, &consumed.apache)
}
}
// --- 9. Goroutines de consommation des ring buffers ---
@ -1225,14 +1240,9 @@ func updateH2Settings(last *correlation.HTTPRequest, settings *parser.HTTP2Setti
// Retente jusqu'à maxRetries fois toutes les retryInterval secondes.
// Utile pour attendre que nginx démarre après ja4ebpf.
func attachNginxUprobesWithRetry(ctx context.Context, l *loader.Loader, cfg *Config) error {
if !cfg.Uprobes.Enabled {
log.Printf("[uprobes] nginx uprobes désactivés (uprobes.enabled=false)")
return nil
}
binPath := cfg.Uprobes.NginxBinPath
maxRetries := cfg.Uprobes.MaxRetries
retryInterval := time.Duration(cfg.Uprobes.RetryIntervalSec) * time.Second
binPath := "/usr/sbin/nginx" // chemin par défaut pour nginx
log.Printf("[uprobes] tentative d'attachement nginx uprobes (bin=%s, max_retries=%d, interval=%v)",
binPath, maxRetries, retryInterval)
@ -1275,10 +1285,9 @@ func attachNginxUprobesWithRetry(ctx context.Context, l *loader.Loader, cfg *Con
// Retente jusqu'à maxRetries fois toutes les retryInterval secondes.
// Utile pour attendre que Apache httpd démarre après ja4ebpf.
func attachApacheUprobesWithRetry(ctx context.Context, l *loader.Loader, cfg *Config) error {
if !cfg.Uprobes.ApacheEnabled {
log.Printf("[uprobes] Apache uprobes désactivés (uprobes.apache_enabled=false)")
return nil
}
maxRetries := cfg.Uprobes.MaxRetries
retryInterval := time.Duration(cfg.Uprobes.RetryIntervalSec) * time.Second
maxRetries := cfg.Uprobes.MaxRetries
retryInterval := time.Duration(cfg.Uprobes.RetryIntervalSec) * time.Second