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):

ColumnTypeDescription
idUUIDConfig entry identifier
org_idUUIDOwning organization UUID
connector_typestring (≤30)Connector type identifier (see below)
configtextFernet-encrypted JSON config string
is_enabledboolWhether this config is active for event routing
created_attimestampCreation time
updated_attimestampLast modification time
last_delivery_attimestampTimestamp of most recent successful delivery
delivery_statusstringhealthy, 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_typeConnectorProtocolNotes
splunk_hecSplunk HECHTTPS POSTHTTP Event Collector
sentinelMicrosoft SentinelHTTPS POST (DCR)Azure Monitor Log Ingestion API
elasticElasticsearchHTTPS Bulk APIAPI key or basic auth
datadogDatadogHTTPS Logs Intake v2API key
sumo_logicSumo LogicHTTPS HTTP SourceURL-embedded auth
cortex_xsiamPalo Alto Cortex XSIAMHTTPSHEC-compatible; uses SplunkHECConnector internally
qradarIBM QRadarSyslog CEF over TLSDedicated 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"
}
FieldRequiredDescription
urlYesHEC endpoint URL
tokenYesHEC token
indexNoSplunk index name
sourceNoEvent 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"
}
FieldRequiredDescription
tenant_idYesAzure AD tenant ID
client_idYesAzure AD app client ID
client_secretYesAzure AD app client secret
dcr_endpointYesData Collection Endpoint URL
dcr_idYesDCR immutable ID
stream_nameYesCustom stream name in DCR
{
"url": "https://your-cluster.es.io:9200",
"api_key": "base64encodedapikey==",
"index": "arbitex-audit"
}
FieldRequiredDescription
urlYesElasticsearch cluster URL
api_keyYesAPI key (base64-encoded)
indexYesTarget index name
{
"api_key": "your-datadog-api-key",
"site": "datadoghq.com",
"source": "arbitex",
"service": "arbitex-gateway"
}
FieldRequiredDescription
api_keyYesDatadog API key
siteNoDatadog site (default datadoghq.com)
sourceNoLog source tag
serviceNoService tag
{
"url": "https://endpoint1.collection.sumologic.com/receiver/v1/http/your-token"
}
FieldRequiredDescription
urlYesHTTP 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.

FieldRequiredDescription
urlYesXSIAM HEC endpoint URL
tokenYesXSIAM ingestion token
{
"host": "qradar.example.com",
"port": 514,
"tls_cert": "/etc/arbitex/certs/qradar-client.pem"
}
FieldRequiredDescription
hostYesQRadar syslog receiver hostname or IP
portNoSyslog port. Default 514.
tls_certNoPath 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:

StatusMeaning
healthyMost recent delivery succeeded
degradedRecent delivery failures with ongoing retries
failedConnector 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.