Communications Backbone
Communications Backbone by C2 Team (NOC)
Data flow
- Client A sends to
client-a-outbox
(or POSTs to API /send - not yet implemented) - Messages are forwarded from
client-a-outbox
tosoar-publish
- Messages are published from
soar-publish
with the given topic read from the message - Subscribers listen to for messages
- Subscription is delivered to
client-b-inbox
- Client B reads from `client-b-inbox (or GETs from API /receive)
There is a parallel flow when a client sends to client-a-notify
in which case the
messages are delivered through the broadcast exchange to all clients client-x-inbox
.
Auth placeholder
As a proxy for proper authentication, when you post a client a random secret is returned in the response. To send to / receive from the bus you then call the API with the client_id and secret and it checks they match. The client_id determines which queues it reads from.
Subsequent requests to the client endpoint return the client_id but not the secret.
Testing
Current coverage:
- API: yes
- Pika RabbitMQ implementation: no
pytest
Running via docker-compose
Using docker-compose
will mean that everything is setup automatically, this includes the rabbitmq
container, the backbone API, and the backbone bus. The run-compose.sh
script has been provided to simplify this even further - all you have to do is set whatever env vars you need in the .env
file and then run ./run-compose.sh
(the defaults in .env
are fine for local dev work, but ones not labelled optional
will need setting in a production setting). The env vars are:
-
DATA_DIR
- Where to mount the volume of the API container on your local system. This defaults to the result ofpwd
, which should be within thecommunications-backbone
repo -
SOAR_TOKEN_LIFETIME
(Optional) - The number of hours until a newly created token expires -
SOAR_TOKEN_SECRET
(Optional) - A secret key used to encrypt/decrypt token data. If specified the value should be set using TokenModel.getKey()
Running manually
Setup
In a virtual environment
pip install -r requirements-dev.txt
RabbitMQ
docker run --rm -p 5672:5672 -d --hostname rmq --name rmq rabbitmq:management
API
python api.py
Event bus
python soar_bus.py
Usage
To use the backbone you have to create a client. The client id and name should be unique but human readable. A client secret is returned by the API and client credential grants using this client_id and secret are used to authenticate client application connections.
Create some clients
POST
to http://localhost:3000/clients
Send / Receive directly
# Send a message
python client_send.py noc-c2-outbox 'soar.noc.slocum.something' from noc-c2
# Receive messages
python client_read.py noc-sfmc-inbox
Receive via API
As a placeholder for proper authentication you post the client_id
and
secret
and it checks that a client with that id exists and that the
secret matches before allowing the request.
This should be replaced with a proper auth layer.
GET http://localhost:5000/receive?client_id=[client_id]&secret=[secret]