This page is a tutorial on how to set up Blockdaemon's external audit server, and how to configure the MPC nodes in a Builder Vault instance to post audit logs to the audit service.

This tutorial assumes that your Builder Vault has three MPC nodes, but it should be easy to adapt to Builder Vault instances with any other number of MPC nodes.

## Log in to Blockdaemon's Docker Registry

Start by login into Blockdaemon's private docker registry using the credentials you were provided:

```undefined
docker login bv.sepior.net
```

## Create Audit Server Configuration

The MPC nodes in Builder Vault will communicate with the Audit Server on port 3000, the logs can be queried on port 8000 and the Audit server will communicate with a MongoDB instance (or Amazon DocumentDB) on port 27017.

Start by generating a private/public key pair for the Audit Server:

```shell
openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out audit_private.key
openssl ec -inform DER -in audit_private.key -pubout -outform DER -out audit_public.key
```

Next, generate a new set of private/public keys for each of the MPC nodes used just for logging:

```shell
openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out audit_private0.key
openssl ec -inform DER -in audit_private0.key -pubout -outform DER -out audit_public0.key
openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out audit_private1.key
openssl ec -inform DER -in audit_private1.key -pubout -outform DER -out audit_public1.key
openssl ecparam -name P-256 -genkey -param_enc named_curve -outform DER -out audit_private2.key
openssl ec -inform DER -in audit_private2.key -pubout -outform DER -out audit_public2.key
```

Get the Audit Server private key in base64:

```shell
openssl base64 -A -in audit_private.key; echo
```

Then get the all the nodes' base64 encoded public keys:

```shell
openssl base64 -A -in audit_public0.key; echo
openssl base64 -A -in audit_public1.key; echo
openssl base64 -A -in audit_public2.key; echo
```

And lastly, a random password for accessing the Audit Server:

```shell
LC_ALL=C tr -cd "[:alnum:]" < /dev/urandom | fold -w24 | head -n1
```

Finally, fill all of the above into the template below and save it to a file called `config.toml`

```toml
[Database]
  Host = "<mongodb hostname>"
  Username = "<mongodb username>"
  Password = "<mongodb password>"

[LogServer]
  Port = 3000
  PrivateKey = "<audit server private key base64>"

[LogServer.HTTPResponseHeaders] # Optional
  <key = value>

[QueryServer]
  Port = 8000
  CertificateFile = ""      # HTTPS disabled
  CertificateKeyFile = ""   # HTTPS disabled

[QueryServer.HTTPResponseHeaders] # Optional
  <key = value>

[TSM.demo]
  Password = "<random password>"
  PublicKeys = [\
    "<node0 audit public key as base64>",\
    "<node1 audit public key as base64>",\
    "<node2 audit public key as base64>"\
  ]
```

### Host Configuration

The _Host_ field can be used for setting any configuration option, which the _mongo-go-driver_ will accept. For instance ssl can be added, by specifying

```toml
[Database]
  Host = "hostname:27017/?ssl=true&tlsCAFile=ca-bundle.pem"
  Username = "<mongodb username>"
  Password = "<mongodb password>"
```

When running via Docker, you can mount the folder containing the .pem file, and point to the absolute file path in _Host_, remember to URI encode the path.

Further inspiration can be found here:

[https://github.com/mongodb/mongo-go-driver/blob/master/mongo/client_examples_test.go](https://github.com/mongodb/mongo-go-driver/blob/master/mongo/client_examples_test.go)

## Update the MPC Node Configuration

We need to add an `[Audit]` section to the MPC node configuration files we already have.

For each of the three MPC nodes, we need to first get the audit server public key as base64:

```shell
openssl base64 -A -in audit_public.key; echo
```

the MPC node audit private key as base64:

```shell
openssl base64 -A -in audit_private0.key; echo
```

and a random signing seed (each node should use its own seed):

```shell
openssl rand -base64 32
```

That is all plugged in to the template below, and inserted in to the MPC node configuration file that we made earlier.

```toml
[Audit]
  ReceiverURL = "https://<audit server hostname>:<audit server logging port>/log"
  ReceiverPublicKey = "<audit server public key>"
  ClientPrivateKey = "<MPC node audit private key>"
  LogEntrySigningKeySeed = "<random signing seed>"
  MaxBatchSize = 50
  MinWaitTime = "5s"
  MaxWaitTime = "2m"
```

## Start the Audit Server

Add the following to the `docker-compose.yml` file we made earlier, insert mongodb username and password, and restart:

```yaml
  mongo:
    image: mongo
    command: --noscripting
    restart: always
    volumes:
      - ./audit_server/db/:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: <mongo username>
      MONGO_INITDB_ROOT_PASSWORD: <mongo password>

audit-server:
    image: bv.sepior.net/audit-server
    ports:
      - 8000:8000/tcp
      - 3000:3000/tcp
    restart: always
    volumes:
      - ./config.toml:/config/config.toml
```

## Querying

To query the server basic authentication is required. The username is the name of the TSM in the audit configuration file, i.e., `demo` in the above example, and the password is the `<random password>` in the `[TSM.demo]` section.

A query is on the form

```undefined
https://HOST:QUERY_PORT/logs?filter={FILTER}&options={OPTIONS}
```

Where FILTER is replaced by a MongoDB search filter, and OPTIONS is replaced by MongoDB find options (see [https://docs.mongodb.com/manual/reference/command/find/](https://docs.mongodb.com/manual/reference/command/find/)). Remember to URL encode values.

## Examples

Retrieve two log entries with a session id, showing the `sessionID`, `timestamp`, and `keyID`:

```undefined
https://HOST:QUERY_PORT/logs?filter={"sessionID": {"$neq": null}}&options={"limit": 2, "projection": {"_id": 0, "sessionID": 1, "timestamp": 1, "keyID": 1 }}
```

Retrieve all logs without a session id, showing the `userID`, and the `operation`:

```undefined
https://HOST:QUERY_PORT/logs?filter={"sessionID": {"$eq": null}}&options={"projection": {"_id": 0, "userID": 1, "operation": 1}}
```

In the next example we use cURL to retrieve two log entries, and parse them with `jq`. We assume that the audit server has its query endpoint at `http://localhost:8000/logs` and we use the URL-encoded parameters `filter={}&options={"limit": 2}`. The basic auth in the audit server config file is `[TSM.demo] Password = "demo_password"

```shell
curl -s -u demo:demo_password "http://localhost:8000/logs?filter=%7B%7D&options=%7B%22limit%22%3A%202%7D" | jq
```

This should result in JSON output like this:

```json
[\
  {\
    "_id": "67d97714a292eb1b22a8b7de",\
    "algorithm": "ECDSA",\
    "keyID": "1hC9DhuUqMGieUMNtQSutGhqumvV",\
    "operation": "Keygen",\
    "parameters": {\
      "curve": "secp256k1"\
    },\
    "player": 0,\
    "sessionID": "MXa9LrKvkLq49v5DpgtVZ_30tf8QbMtXy8iMbpORXZY",\
    "signature": "Vw16bm/nwnMKl2w1rkqsesyLvfMvJSsLNJztx1UWqtDMIEXib8EYC5SNGZx2zUznNfrDtrSrmyXTmkFFJSXfDA==",\
    "timestamp": 1742302418310,\
    "userID": "b4zVds2jyvvJ2wXgSfNuHyryJUWa"\
  },\
  {\
    "_id": "67d97714a292eb1b22a8b7df",\
    "algorithm": "ECDSA",\
    "keyID": "1hC9DhuUqMGieUMNtQSutGhqumvV",\
    "operation": "PresigGen",\
    "parameters": {\
      "Count": 3\
    },\
    "player": 0,\
    "sessionID": "ttSsU5W5kEhrCc0MDRGg3i0DBabQ8LMs-vTa_kH8ZAk",\
    "signature": "xbe7bZT1g4mKzEtCGs0xrUOB5/vqzOtOofa0mkt5XNK3E2z2+v3fMf7dbue1bHblsP22z6kYZKLnZfHNT7AOCA==",\
    "timestamp": 1742302418334,\
    "userID": "b4zVds2jyvvJ2wXgSfNuHyryJUWa"\
  }\
]
```
