Security Solutionsセキュリティソフトウェア
ドキュメント

2. Database tier (Oracle or MongoDB)

この技術ドキュメントは英語で提供しています。

Sentinel ID stores people, vehicles, cases, templates, sightings and the audit log in Oracle Database or MongoDB, chosen by the agency. This page installs MongoDB; Oracle is at the end. At national scale MongoDB runs as a sharded cluster: config servers hold the cluster metadata, shards hold the data (each a 3-member replica set), and mongos routers on the application servers send each query to the right shard.

For the reference size: 3 config servers, 24 shards × 3 members. A pilot can start with one 3-member replica set and be converted to a sharded cluster later.

Install MongoDB (every database server)

curl -fsSL https://www.mongodb.org/static/pgp/server-8.0.asc | sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg --dearmor
echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-8.0.list
sudo apt update && sudo apt install -y mongodb-org

Use XFS for the data volume, mounted with noatime, and disable Transparent Huge Pages as MongoDB recommends.

Security first: TLS and member authentication

Every member authenticates to the others with its x.509 certificate from the internal CA, and all traffic is TLS:

# /etc/mongod.conf (common part)
net:
  port: 27018
  bindIp: 10.40.1.21            # this server's data-zone address only
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/tls/server.pem
    CAFile: /etc/mongodb/tls/ca.pem
security:
  authorization: enabled
  clusterAuthMode: x509
storage:
  dbPath: /data/mongodb
  wiredTiger:
    engineConfig:
      cacheSizeGB: 180           # about 70% of RAM on a 256 GB server
systemLog:
  destination: file
  path: /var/log/mongodb/mongod.log
  logAppend: true

Config servers (3 servers)

Add to /etc/mongod.conf:

sharding:
  clusterRole: configsvr
replication:
  replSetName: cfg

Start them and initiate the replica set from one of them:

rs.initiate({ _id: "cfg", configsvr: true, members: [
  { _id: 0, host: "db-cfg-a.data.internal:27019" },
  { _id: 1, host: "db-cfg-b.data.internal:27019" },
  { _id: 2, host: "db-cfg-c.data.internal:27019" } ] })

Shards (24 replica sets of 3)

On each member of shard 12, for example:

sharding:
  clusterRole: shardsvr
replication:
  replSetName: s12

Initiate each shard's replica set the same way (rs.initiate with its three members). Place the three members of a shard in different racks or power domains.

Routers (mongos) on application and ingest servers

Run one mongos per application and ingest server, listening on 127.0.0.1 only, so the application connects locally:

# /etc/mongos.conf
sharding:
  configDB: cfg/db-cfg-a.data.internal:27019,db-cfg-b.data.internal:27019,db-cfg-c.data.internal:27019
net:
  port: 27017
  bindIp: 127.0.0.1
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/tls/client.pem
    CAFile: /etc/mongodb/tls/ca.pem

Create a systemd unit mongos.service that runs /usr/bin/mongos --config /etc/mongos.conf as the mongodb user.

Add the shards and shard the collections

From any mongos, as the cluster administrator:

sh.addShard("s01/db-s01-a.data.internal:27018,db-s01-b.data.internal:27018,db-s01-c.data.internal:27018")
// ... repeat for s02 to s24

sh.enableSharding("sentinel_id")
sh.shardCollection("sentinel_id.fingerprinttemplates", { _id: "hashed" })
sh.shardCollection("sentinel_id.facetemplates",        { _id: "hashed" })
sh.shardCollection("sentinel_id.people",               { _id: "hashed" })
sh.shardCollection("sentinel_id.vehicles",             { _id: "hashed" })
sh.shardCollection("sentinel_id.sightings",            { cameraId: 1, capturedAt: 1 })
sh.shardCollection("sentinel_id.events",               { _id: "hashed" })

Application user

Create a least-privilege user for Sentinel ID (read and write on its database only), plus a separate read-only user for reporting and a backup user:

db.getSiblingDB("admin").createUser({ user: "sentinel_app", pwd: passwordPrompt(), roles: [ { role: "readWrite", db: "sentinel_id" } ] })

The application's connection string is then:

MONGO_URI=mongodb://sentinel_app:<password>@127.0.0.1:27017/sentinel_id?authSource=admin&tls=true

Encryption at rest

Use encrypted disks (LUKS2, see Prerequisites) on every member. Where your MongoDB edition supports the encrypted storage engine, enable it as well, with keys held in the agency KMS over KMIP.

Firewall rules (data zone)

  • 27018 (shards) and 27019 (config) from the application, ingest and matcher zones and from the other members only.
  • SSH from the bastion only. Nothing from the edge zone.

Oracle instead of MongoDB

Agencies that standardise on Oracle run Sentinel ID on Oracle Database 23ai / 26ai. Set DB_TYPE=oracle and ORACLE_URI, and copy existing data with npm run db:copy. Partitioning, RAC and Data Guard then provide the scale-out and recovery described above.

Next: Install the application tier.