---
module: technical.aria
title: ARIA — ATM threat intelligence & precursor-sequence detection
tab: Overview
order: 10
audience: dev
---

> **DRAFT · internal.** Written 2026-07-01 from hiveops-aria source. Verify against code before relying on specifics.

## Responsibility

ARIA (`hiveops-aria`, `spring.application.name=hiveops-aria`, port **8095**) is the threat-intelligence service. It owns the IOC (indicator-of-compromise) catalog seeded from FBI FLASH alerts and refreshed from external feeds (OTX, MalwareBazaar, ThreatFox), ingests device threat events from agents, classifies/matches them against IOCs, and detects multi-phase attack "precursor sequences" (e.g. ATM jackpotting) within a time window. It also tracks per-device security posture. Cross-link [platform.service-ownership].

## Data

- **Database:** `hiveiq_aria` (PostgreSQL). Datasource via `DB_URL` env var (`spring.datasource.url=${DB_URL:jdbc:postgresql://localhost:5432/hiveiq_aria}`), `DB_USERNAME`/`DB_PASSWORD`. `ddl-auto=validate`; schema managed by **Flyway** (`db/migration`, V1–V8). Cross-link [platform.data-stores].

| Table | Purpose |
|-------|---------|
| `threat_ioc` | IOC catalog (ioc_type, value, source, source_ref, confidence, active, expires_at). Seeded in V2 from FBI FLASH `FLASH-20260219-001` (Ploutus jackpotting). |
| `threat_event` | Ingested/classified device events (device_agent_id, signal_key, event_type, severity, matched_ioc_id, attack_phase, sequence_id, raw_payload JSONB). |
| `precursor_sequence_alert` | Detected attack sequences (sequence_type, phases_detected[], confidence, auto_response_taken, resolved_at/by, sequence_id UUID). |
| `device_security_posture` | Per-device posture (gold_image_hash vs current_image_hash, disk_encryption_enabled, os_eol_status, posture_score). |
| `ioc_feed_run` | External feed refresh run history (added V6). |

## Kafka

**Produced** (both defined in `AriaKafkaConfig`, JSON serializer):

| Topic | Producer class | Trigger |
|-------|---------------|---------|
| `hiveops.aria.threats` | `AriaThreatProducer.publishThreatEvent` | called from `ThreatEventIngestionService` (key = deviceAgentId) |
| `hiveops.aria.sequences` | `AriaSequenceProducer.publishSequenceAlert` | called from `SequenceDetectionService` when a precursor sequence trips |

**Consumed:** No Kafka consumers — no `@KafkaListener` in the codebase. `spring.kafka.admin.fail-fast=false`. Cross-link [platform.kafka].

## API surface

Base paths under `/api/aria`. Most read/admin endpoints require `hasRole('BCOS_ADMIN')`.

| Method | Path | Purpose |
|--------|------|---------|
| POST | `/api/aria/ingest/events` | Agent/internal event ingestion (X-Service-Secret header, permitAll) |
| POST | `/api/aria/posture/report` | Device posture report submission (permitAll) |
| GET | `/api/aria/posture` | List device postures |
| GET | `/api/aria/posture/{deviceId}` | Single device posture |
| GET | `/api/aria/events` | List threat events |
| GET | `/api/aria/stats` | Threat/dashboard stats |
| GET | `/api/aria/ioc` | List IOCs |
| GET | `/api/aria/ioc/active` | Active IOCs (authenticated, no BCOS_ADMIN gate) |
| POST | `/api/aria/ioc` | Create IOC |
| PUT | `/api/aria/ioc/{id}` | Update IOC |
| DELETE | `/api/aria/ioc/{id}` | Delete IOC |
| GET | `/api/aria/sequences` | List precursor sequence alerts |
| GET | `/api/aria/sequences/{id}/events` | Events composing a sequence |
| POST | `/api/aria/sequences/{id}/resolve` | Resolve a sequence alert |
| GET | `/api/aria/feeds/status` | Feed status |
| GET | `/api/aria/feeds/runs` | Feed run history |
| POST | `/api/aria/feeds/refresh` `/refresh/{feedName}` | Trigger feed refresh |

## Gotchas

- **Auth model:** stateless JWT (`JwtAuthenticationFilter`) + `@EnableMethodSecurity`. Almost every admin/read endpoint uses `hasRole('BCOS_ADMIN')` — note it is **BCOS_ADMIN only**, not the usual `hasAnyRole('MSP_ADMIN','BCOS_ADMIN')` seen elsewhere.
- **Public endpoints:** `/api/aria/ingest/**` and `/api/aria/posture/report` are `permitAll()` in `SecurityConfig`. Ingestion is instead gated by the `X-Service-Secret` header compared to `aria.internal.service-secret` (`ARIA_SERVICE_SECRET`) — **but only if that secret is non-blank**; if unset, the endpoint accepts any request.
- `GET /api/aria/ioc/active` has no `@PreAuthorize`, so any authenticated caller can read active IOCs (unlike the BCOS_ADMIN-gated `/ioc`).
- **Sequence detection window:** `aria.sequence.window.minutes` (`ARIA_SEQUENCE_WINDOW_MINUTES`, default 15).
- **Feed refresh:** scheduled via cron `aria.feed.refresh.cron` (default `0 0 3 * * *`), toggle `ARIA_FEED_ENABLED` (default true). Optional API keys for OTX / MalwareBazaar / ThreatFox.
- **Auto-response is off by default:** `aria.autoresponse.shutdown.enabled=false`. Auto-response fleet tasks would call hiveops-incident (`INCIDENT_SERVICE_URL`, default `http://hiveiq-incident:8080`).
- Swagger disabled unless `SWAGGER_ENABLED=true`. `spring.security` logging is at DEBUG.
- Enum DB types were converted to VARCHAR in V3 (`convert_enums_to_varchar`) despite V1 defining PG enum types.
