n6 Stream API: Docker-Based Installation¶
The n6 Stream API installation is based on Debian 12. This guide describes how to set up an instance of n6 Stream Api with Docker.
The simplified data flow of the n6 Stream API:
n6's internal pipeline
|
event data
↓
n6anonymizer
|
event data per client organization
↓
Stream API Server (RabbitMQ)
------------------------------------------------------------------------------
Client
|
initial STOMP communication
↓
Stream API Server ←→ Broker Auth API + Auth DB
| (authenticaion & authorization)
|
event data per client organization
↓
Client
Prerequisites¶
To build the Docker version of the n6 Stream API, we first need to set up the Docker version of n6. To do this follow the official guide for Docker-based n6 installation. Once you have a Docker-based instance of n6:
-
Make sure the Docker network
n6_n6-pub-netis created. The Docker images of n6 should be part of that network. -
Make sure the Auth DB database has been initialized.
Getting started¶
Note
Make sure you are in the top-level directory of the cloned source code repository.
To build the necessary images for n6 Stream API:
docker compose -f docker-compose.stream-api.yml build
If the build process was successful, you should be able to run the following command to obtain a result similar to what is listed here:
docker images | grep n6
n6_stream_api latest c6da117e027b 3 hours ago 1.17GB
n6_worker latest 834b41858684 3 hours ago 2.29GB
n6_web latest ede14648e4c0 3 hours ago 3.15GB
n6_base latest f8a048d63db2 3 hours ago 1.93GB
n6_mysql latest 2f5da49187d5 3 hours ago 434MB
n6_stream_api_rabbit latest 0f8faa554d36 3 hours ago 253MB
n6_rabbit latest ad5b4cf53d4e 3 hours ago 253MB
n6_mailhog latest 55b5f0a82c69 3 years ago 392MB
To launch the Docker version of n6 Stream API run.
docker compose -f docker-compose.stream-api.yml up
Configuration of Stream API access¶
First inside the stream_api container run the n6anonymizer:
docker compose exec stream_api bash
source venv-n6datapipeline/bin/activate
n6anonymizer
Note
The Anonymizer will not generate any output unless specific error handling or logging mechanisms are configured.
Then, in n6adminpanel, create a new Organization and a user within. Make sure the Stream API Enabled option is checked.
- Sync the org config with the stream api broker config:
Run the exchange_updater inside the stream_api container:
docker compose exec stream_api bash
source venv-n6datapipeline/bin/activate
python /home/dataman/n6/N6DataPipeline/n6datapipeline/aux/exchange_updater.py
Testing¶
- Make sure the
n6anonymizeris running within thevenv-n6datapipelineenvironment in thestream_apicontainer - Make sure you have created the n6 user’s API Key (see the relevant fragment of the Docker-based n6 installation guide)
- Connect to
stream_api_rabbiton port61614(see the Stream API usage guide or use the script provided below) - Push some data into the n6 pipeline. Ensure that the organization the user is connected to has all the necessary rights to read these events. The access list is the same as in the REST API and Portal
- Events should be received by the connected client
Example client (stomp.py required)¶
To use the provided script fill the required variables: STREAM_API_RABBIT_DOCKER_IP, login, passcode.
import ssl
import stomp # type: ignore
import time
STREAM_API_RABBIT_DOCKER_IP = ''
PORT = 61614
login = <USER_LOGIN>
passcode = <USER_API_KEY>
conn = stomp.Connection([(STREAM_API_RABBIT_DOCKER_IP, PORT)], heartbeats=(3000, 3000))
conn.set_ssl(for_hosts=[(STREAM_API_RABBIT_DOCKER_IP, PORT)], ssl_version=ssl.PROTOCOL_TLS)
class MyListener(stomp.ConnectionListener):
def on_connecting(self, host_and_port):
print(f"Connecting to {host_and_port}")
def on_connected(self, frame):
print("********* CONNECTED ************")
return super().on_connected(frame)
def on_error(self, frame):
print("Error:\n%s" % frame)
def on_message(self, frame):
print("Message received:\n%s" % frame)
def on_disconnected(self):
print("\n****** DISCONNECTED *****")
# return super().on_disconnected()
conn.set_listener('', MyListener())
conn.connect(login=login, passcode=passcode, wait=True)
conn.subscribe(destination="/exchange/<YOUR_ORGANIZATION>.com/*.*.*.*", id="001", ack="auto")
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("Interrupted")
conn.disconnect()
Example output:
Message received:
{cmd=MESSAGE,headers=[{'subscription': '001', 'destination': '/exchange/clients/threats.phish.hidden.123456789abcdef0', 'message-id': 'T_001@@session-N-jGLLK57hJFJgk6KKHF7j@@11','redelivered': 'false', 'n6-client-id': 'example.com', 'persistent': '1', 'content-length': '291'}],body={"category": "phish", "time": "2025-05-20T16:32:37Z", "fqdn": "example1.com", "restriction": "public", "address": [{"ip": "1.1.1.1"}, {"ip": "2.2.2.2"}], "source": "hidden.123456789abcdef0", "id": "a6f8765c4a9e8d874cb64876a373bc65", "confidence": "high", "type": "event"}}