Skip to content

Per-Org SIEM Configuration

Arbitex supports per-organization SIEM connector configuration for organizations that need to route their audit events to a dedicated SIEM endpoint, independently of the global platform connectors. This is distinct from global connectors, which are configured at the platform level via environment variables and receive events from all organizations.

Per-org SIEM configs are stored in the siem_configs database table with Fernet-encrypted credential payloads. The platform loads active configs for each org at request time using a 60-second TTL cache.


Audit Event
SinkManager
├─► Global connectors (env var config, all orgs)
└─► Per-org connectors (DB config, org-specific)
└─ siem_config_service.get_org_siem_configs(db, org_id)
└─ SiemConfig rows (Fernet-encrypted)
└─ instantiate_connector(type, decrypted_config)

When an audit event is dispatched, the SinkManager routes it to all configured global connectors and all active per-org connectors for the event’s org. Connectors operate independently — a failure in one does not affect delivery to others.


Per-org SIEM configurations are stored in the siem_configs table (SiemConfig):

Column Type Description
id UUID Config entry identifier
org_id UUID Owning organization UUID
connector_type string (≤30) Connector type identifier (see below)
config text Fernet-encrypted JSON config string
is_enabled bool Whether this config is active for event routing
created_at timestamp Creation time
updated_at timestamp Last modification time
last_delivery_at timestamp Timestamp of most recent successful delivery
delivery_status string healthy, degraded, or failed

The config column stores a URL-safe base64 Fernet token that decrypts to a JSON object containing connector credentials. The encryption key is set via the FERNET_KEY environment variable. In development/test, a transient per-process key is generated with a warning log — FERNET_KEY must be set in production.

Indexes: (org_id), (org_id, is_enabled) for fast per-org lookups.


Seven connector types are supported for per-org configuration:

connector_type Connector Protocol Notes
splunk_hec Splunk HEC HTTPS POST HTTP Event Collector
sentinel Microsoft Sentinel HTTPS POST (DCR) Azure Monitor Log Ingestion API
elastic Elasticsearch HTTPS Bulk API API key or basic auth
datadog Datadog HTTPS Logs Intake v2 API key
sumo_logic Sumo Logic HTTPS HTTP Source URL-embedded auth
cortex_xsiam Palo Alto Cortex XSIAM HTTPS HEC-compatible; uses SplunkHECConnector internally
qradar IBM QRadar Syslog CEF over TLS Dedicated QRadarConnector

Multiple configs for the same connector type can exist for an org (e.g., two Splunk instances). Each is a separate row with its own encrypted config.


{
"url": "https://splunk.example.com:8088/services/collector/event",
"token": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"index": "arbitex_audit",
"source": "arbitex"
}
Field Required Description
url Yes HEC endpoint URL
token Yes HEC token
index No Splunk index name
source No Event source label
{
"tenant_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_id": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"client_secret": "your-client-secret",
"dcr_endpoint": "https://your-dce.eastus-1.ingest.monitor.azure.com",
"dcr_id": "dcr-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"stream_name": "Custom-ArbitexAudit_CL"
}
Field Required Description
tenant_id Yes Azure AD tenant ID
client_id Yes Azure AD app client ID
client_secret Yes Azure AD app client secret
dcr_endpoint Yes Data Collection Endpoint URL
dcr_id Yes DCR immutable ID
stream_name Yes Custom stream name in DCR
{
"url": "https://your-cluster.es.io:9200",
"api_key": "base64encodedapikey==",
"index": "arbitex-audit"
}
Field Required Description
url Yes Elasticsearch cluster URL
api_key Yes API key (base64-encoded)
index Yes Target index name
{
"api_key": "your-datadog-api-key",
"site": "datadoghq.com",
"source": "arbitex",
"service": "arbitex-gateway"
}
Field Required Description
api_key Yes Datadog API key
site No Datadog site (default datadoghq.com)
source No Log source tag
service No Service tag
{
"url": "https://endpoint1.collection.sumologic.com/receiver/v1/http/your-token"
}
Field Required Description
url Yes HTTP Source URL (authentication embedded in URL)
{
"url": "https://your-xsiam-instance.xdr.paloaltonetworks.com/api/v1/event-collector",
"token": "your-xsiam-token"
}

Cortex XSIAM uses the HEC-compatible ingestion endpoint. The SplunkHECConnector is used internally with the connector ID set to cortex_xsiam_org for log identification.

Field Required Description
url Yes XSIAM HEC endpoint URL
token Yes XSIAM ingestion token
{
"host": "qradar.example.com",
"port": 514,
"tls_cert": "/etc/arbitex/certs/qradar-client.pem"
}
Field Required Description
host Yes QRadar syslog receiver hostname or IP
port No Syslog port. Default 514.
tls_cert No Path to TLS client certificate PEM file

Per-org configs are loaded with a 60-second TTL cache (_ORG_CONFIG_CACHE). The cache is keyed by org_id and stores a list of SiemConfig ORM objects along with a monotonic timestamp.

  • Cache hit: Configs loaded from the in-process cache within the TTL window.
  • Cache miss: DB query executed via SELECT … WHERE org_id = ? AND is_enabled = TRUE.
  • Invalidation: invalidate_org_cache(org_id) removes the cache entry. This is called after any create, update, or delete operation on a SiemConfig row, so changes take effect within one TTL period or immediately on the next miss.

When a config is loaded from the cache, instantiate_connector(connector_type, decrypted_config) is called to build a live SIEMConnector instance. Instantiation failures are logged as errors but do not prevent other connectors from being instantiated or events from being dispatched to healthy connectors.


The delivery_status column tracks connector health. Values:

Status Meaning
healthy Most recent delivery succeeded
degraded Recent delivery failures with ongoing retries
failed Connector has exhausted retries; dead letter queue active

last_delivery_at is updated on each successful delivery. Use these fields to monitor per-org connector health and trigger alerts when delivery_status transitions to failed.


Configuration is managed via direct database access or the platform admin API (endpoint documented separately). To add a connector for an org:

  1. Prepare the connector config JSON for the target connector type.
  2. Encrypt it: encrypt_config(config_dict) returns a Fernet token string.
  3. Insert a row into siem_configs:
INSERT INTO siem_configs (org_id, connector_type, config, is_enabled)
VALUES (
'your-org-uuid',
'splunk_hec',
'gAAAAA...', -- Fernet token from encrypt_config()
true
);
  1. The cache for the org is invalidated automatically by invalidate_org_cache(org_id) if called after the insert, or expires within 60 seconds otherwise.

Set is_enabled = false on the siem_configs row and call invalidate_org_cache(org_id). The connector is no longer loaded during cache population and is excluded from event dispatch.