Files
Redflag/aggregator-agent/internal/logging/example_integration.go
jpetree331 f97d4845af feat(security): A-1 Ed25519 key rotation + A-2 replay attack fixes
Complete RedFlag codebase with two major security audit implementations.

== A-1: Ed25519 Key Rotation Support ==

Server:
- SignCommand sets SignedAt timestamp and KeyID on every signature
- signing_keys database table (migration 020) for multi-key rotation
- InitializePrimaryKey registers active key at startup
- /api/v1/public-keys endpoint for rotation-aware agents
- SigningKeyQueries for key lifecycle management

Agent:
- Key-ID-aware verification via CheckKeyRotation
- FetchAndCacheAllActiveKeys for rotation pre-caching
- Cache metadata with TTL and staleness fallback
- SecurityLogger events for key rotation and command signing

== A-2: Replay Attack Fixes (F-1 through F-7) ==

F-5 CRITICAL - RetryCommand now signs via signAndCreateCommand
F-1 HIGH     - v3 format: "{agent_id}:{cmd_id}:{type}:{hash}:{ts}"
F-7 HIGH     - Migration 026: expires_at column with partial index
F-6 HIGH     - GetPendingCommands/GetStuckCommands filter by expires_at
F-2 HIGH     - Agent-side executedIDs dedup map with cleanup
F-4 HIGH     - commandMaxAge reduced from 24h to 4h
F-3 CRITICAL - Old-format commands rejected after 48h via CreatedAt

Verification fixes: migration idempotency (ETHOS #4), log format
compliance (ETHOS #1), stale comments updated.

All 24 tests passing. Docker --no-cache build verified.
See docs/ for full audit reports and deviation log (DEV-001 to DEV-019).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-28 21:25:47 -04:00

138 lines
3.7 KiB
Go

package logging
// This file contains example code showing how to integrate the security logger
// into various parts of the agent application.
import (
"fmt"
"time"
"github.com/Fimeg/RedFlag/aggregator-agent/internal/config"
"github.com/denisbrodbeck/machineid"
)
// Example of how to initialize the security logger in main.go
func ExampleInitializeSecurityLogger(cfg *config.Config, dataDir string) (*SecurityLogger, error) {
// Create the security logger
securityLogger, err := NewSecurityLogger(cfg, dataDir)
if err != nil {
return nil, err
}
return securityLogger, nil
}
// Example of using the security logger in command executor
func ExampleCommandExecution(securityLogger *SecurityLogger, command string, signature string) {
// Simulate signature verification
signatureValid := false // In real code, this would be actual verification
if !signatureValid {
securityLogger.LogCommandVerificationFailure(
"cmd-123",
"signature verification failed: crypto/rsa: verification error",
)
} else {
// Only log success if configured
event := &SecurityEvent{
Timestamp: time.Now().UTC(),
Level: "INFO",
EventType: SecurityEventTypes.CmdSignatureVerificationSuccess,
Message: "Command signature verified successfully",
}
securityLogger.Log(event)
}
}
// Example of using the security logger in update handler
func ExampleUpdateHandler(securityLogger *SecurityLogger, updateID string, updateData []byte, signature string) {
// Simulate nonce validation
nonceValid := false
if !nonceValid {
securityLogger.LogNonceValidationFailure(
"deadbeef-1234-5678-9abc-1234567890ef",
"nonce expired or reused",
)
}
// Simulate signature verification
signatureValid := false
if !signatureValid {
securityLogger.LogUpdateSignatureVerificationFailure(
updateID,
"signature does not match update data",
)
}
}
// Example of machine ID monitoring
func ExampleMachineIDMonitoring(securityLogger *SecurityLogger) {
// Get current machine ID
currentID, err := machineid.ID()
if err != nil {
return
}
// In real code, you would store the previous ID somewhere
// This is just an example of how to log when it changes
previousID := "previous-machine-id-here"
if currentID != previousID {
securityLogger.LogMachineIDChangeDetected(
previousID,
currentID,
)
}
}
// Example of configuration monitoring
func ExampleConfigMonitoring(securityLogger *SecurityLogger, configPath string) {
// In real code, you would calculate and store a hash of the config
// and validate it periodically
configTampered := true // Simulate detection
if configTampered {
securityLogger.LogConfigTamperingWarning(
configPath,
"configuration hash mismatch",
)
}
}
// Example of unauthorized command attempt
func ExampleUnauthorizedCommand(securityLogger *SecurityLogger, command string) {
// Check if command is in allowed list
allowedCommands := map[string]bool{
"scan": true,
"update": true,
"cleanup": true,
}
if !allowedCommands[command] {
securityLogger.LogUnauthorizedCommandAttempt(
command,
"command not in allowed list",
)
}
}
// Example of sending security events to server
func ExampleSendSecurityEvents(securityLogger *SecurityLogger, client interface{}) {
// Get batch of security events
events := securityLogger.GetBatch()
if len(events) > 0 {
// In real code, you would send these to the server
// If successful:
fmt.Printf("Sending %d security events to server...\n", len(events))
// Simulate successful send
success := true
if success {
securityLogger.ClearBatch()
fmt.Printf("Security events sent successfully\n")
} else {
// Events remain in buffer for next attempt
fmt.Printf("Failed to send security events, will retry\n")
}
}
}