Skip to content

XTM Composer architecture

Overview

XTM Composer is a micro-orchestration tool that manages connectors/collectors/injectors for Filigran platforms (OpenCTI and OpenAEV). Written in Rust for performance and reliability, it acts as a bridge between the platforms and container orchestration systems.

Global mechanism

Core architecture flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”     REST/GraphQL     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   OpenCTI   │◄────────────────────►│              β”‚
β”‚   Platform  β”‚                      β”‚  XTM         β”‚     Container API
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜                      β”‚  Composer    β”‚β—„β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Ίβ”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                                     β”‚              β”‚                       β”‚ Orchestratorβ”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”                      β”‚              β”‚                       β”‚ (K8s/Docker)β”‚
β”‚   OpenAEV   │◄────────────────────►│              β”‚                       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚   Platform  β”‚     REST/GraphQL     β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Main components

  1. Engine Module (src/engine/)
  2. Manages lifecycle of orchestration and health monitoring
  3. Creates separate async tasks for each platform (OpenCTI/OpenAEV)
  4. Handles graceful shutdown via system signals

  5. API Module (src/api/)

  6. Abstracts platform communication through ComposerApi trait
  7. Handles GraphQL queries/mutations for OpenCTI
  8. Manages container configuration retrieval and status updates

  9. Orchestrator Module (src/orchestrator/)

  10. Implements Orchestrator trait for different container systems
  11. Supports Kubernetes, Docker, and Portainer
  12. Handles container lifecycle operations

  13. Config Module (src/config/)

  14. Manages application settings from YAML files
  15. Supports environment-specific configurations
  16. Handles credentials and encryption keys

Terminology

XTM Composer orchestrates different types of containerized components depending on the platform:

  • OpenCTI: Deploys Connectors as containers (import, export, stream)
  • OpenAEV: Deploys Collectors and Injectors as containers

Each component is deployed and managed as a container:

Platform Component Types Deployed As
OpenCTI Connectors Container
OpenAEV Collectors/Injectors Container

This abstraction allows the composer to use the same orchestration logic regardless of the platform-specific terminology.

Execution flow

  1. Initialization
  2. Load configuration from config/default.yaml and environment
  3. Initialize RSA private key for configuration decryption
  4. Set up logging system

  5. Platform Registration

  6. Connect to platform (OpenCTI/OpenAEV)
  7. Register composer instance with unique manager ID
  8. Verify API compatibility

  9. Main Orchestration Loop

  10. Execute every execute_schedule seconds (default: 30s)
  11. Pull connector configurations
  12. Reconcile desired vs actual state
  13. Apply necessary changes

Pull mechanism

Configuration retrieval (Connectors/Collectors/Injectors)

The composer periodically pulls container configurations from the platform:

// Executed every 30 seconds by default
async fn orchestrate() {
    // 1. Fetch all container configurations from platform
    // (connectors for OpenCTI, collectors/injectors for OpenAEV)
    let connectors = api.connectors().await; // Generic method name

    // 2. For each container configuration
    for connector in connectors {
        // 3. Check if container exists in orchestrator
        let container = orchestrator.get(connector).await;

        // 4. Reconcile state
        match container {
            Some(c) => orchestrate_existing(c, connector),
            None => orchestrate_missing(connector)
        }
    }
}

Container configuration structure

Each container configuration (running a connector/collector/injector) contains: - ID: Unique identifier - Name: Human-readable name - Image: Docker image to deploy - Contract Hash: Version identifier for configuration - Status: Current and requested states - Configuration: Key-value pairs (potentially encrypted)

State synchronization

The composer maintains two-way synchronization:

  1. Platform β†’ Composer (Pull)
  2. Fetch latest component definitions (connectors/collectors/injectors)
  3. Retrieve requested status changes
  4. Get configuration updates

  5. Composer β†’ Platform (Push)

  6. Report actual container status
  7. Send container logs
  8. Update health metrics

Update mechanism

Container lifecycle management

The update mechanism handles several scenarios:

1. Deployment (Missing Container)

// Container doesn't exist but component is defined in platform
// (connector for OpenCTI, collector/injector for OpenAEV)
async fn orchestrate_missing(connector) {
    orchestrator.deploy(connector).await;
    api.patch_status(connector.id, ConnectorStatus::Stopped).await;
}

2. Status Alignment

// Align requested status with actual state
match (requested_status, current_status) {
    (RequestedStatus::Starting, ConnectorStatus::Stopped) => {
        orchestrator.start(container).await;
    }
    (RequestedStatus::Stopping, ConnectorStatus::Started) => {
        orchestrator.stop(container).await;
    }
}

3. Configuration Updates

// Check if configuration hash changed
if requested_hash != current_hash {
    orchestrator.refresh(connector).await;  // Recreate with new config
}

4. Health Monitoring

  • Tracks container restart count
  • Detects reboot loops (>3 restarts in <5 minutes)
  • Reports health metrics every 30 seconds for running containers

5. Log Collection

  • Collects container logs every logs_schedule minutes
  • Sends logs to platform for centralized monitoring
  • Maintains log history for debugging

Cleanup process

The composer automatically removes orphaned containers:

// Remove containers not defined in platform
// (connectors for OpenCTI, collectors/injectors for OpenAEV)
for container in orchestrator.list().await {
    if !platform_connectors.contains(container.id) {
        orchestrator.remove(container).await;
    }
}

Configuration encryption

Hybrid encryption scheme

XTM Composer uses RSA/AES hybrid encryption for sensitive configuration:

Platform                    Composer
────────                    ────────
1. Generate AES key
2. Encrypt config with AES
3. Encrypt AES key with RSA public key
4. Send: [Version|Encrypted AES Key|Encrypted Data]
                            β”‚
                            β–Ό
                    5. Decrypt AES key with RSA private key
                    6. Decrypt config with AES key
                    7. Use plaintext configuration

Encryption format

Encrypted values are Base64-encoded with structure:

[1 byte: Version][512 bytes: RSA-encrypted AES key+IV][N bytes: AES-encrypted data]

Key management

  1. RSA Private Key
  2. Loaded at startup from file or environment variable
  3. PKCS#8 PEM format required
  4. Used to decrypt AES keys

  5. AES Encryption

  6. AES-256-GCM for data encryption
  7. Random key and IV per configuration value
  8. Provides authenticated encryption

Security properties

  • Confidentiality: Sensitive data encrypted at rest and in transit
  • Key Isolation: Each configuration value has unique AES key
  • Forward Secrecy: Compromised AES key doesn't affect other values
  • Authentication: GCM mode provides data integrity

Performance considerations

  1. Async/Await: All I/O operations are asynchronous
  2. Periodic Execution: Configurable intervals prevent API flooding
  3. Batch Processing: Multiple connectors processed in single cycle
  4. Resource Efficiency: Rust's zero-cost abstractions minimize overhead
  5. Error Recovery: Graceful handling of failures with retry logic

Fault tolerance

  • Health Checks: Regular ping to platform ensures connectivity
  • Version Detection: Re-registers on platform upgrade
  • Reboot Loop Detection: Prevents infinite restart cycles
  • Graceful Shutdown: Handles system signals properly
  • State Persistence: Platform maintains desired state