Pre-1.0 hoardDB is pre-1.0. Expect breaking changes.
Security
What hoardDB protects out of the box, what you have to turn on, what it does not protect, and how to tell us about a vulnerability. Every feature on this page is free and unlocked in every build; there is no enterprise tier for TLS, users or encryption.
What a fresh install does
With no configuration, hoardDB-server:
- serves every connection over TLS 1.3, with no way to downgrade;
- requires a login on every connection before it will answer anything;
- generates a root credential the first time it starts, prints it once and saves
it to
<data dir>/root.passwordat mode 0600 (setHOARDDB_ROOT_USERandHOARDDB_ROOT_PASSWORDto choose your own instead); - creates its own private keys with mode 0600, in the data directory;
- stores passwords only as hashes, and leaves the audit log, the metrics endpoint and the profiling endpoint off.
It does not encrypt the data on disk until you ask it to, and it listens on every network interface. Both are covered below.
TLS and self-signed certificates
A node generates an Ed25519 key and a self-signed certificate on its first start
and serves them from <data dir>/keys/server.key and server.crt. No
certificate authority is involved, so there is nothing to renew and nothing for
a client to download — and nothing that proves to a client that it reached the
right machine, other than the certificate’s fingerprint.
The server prints its fingerprint every time it starts, in the line that says it is listening:
{"level":"INFO","msg":"TCP driver listener listening","address":"[::]:7433","fingerprint":"SHA256:d8aa96c0…","alpn":"hoarddb/1"}
Trusting a server from the CLI
The CLI treats a server it has never seen the way ssh treats a new host. It
shows the fingerprint and asks, and it remembers the answer, for that address, in
~/.hoarddb/known_servers. A later connection to the same address whose key is
different fails with WARNING: server key for <address> has changed! and shows
both fingerprints, instead of asking again. If you did replace the server,
remove the old entry from that file; if you did not, treat the warning as an
attack until you know otherwise.
A script has nobody to ask, so a non-interactive session refuses:
The authenticity of server '127.0.0.1:7433' cannot be established.
ED25519 key fingerprint is SHA256:5612612c….
Refusing to trust it non-interactively: pre-populate ~/.hoarddb/known_servers or pass --insecure to bypass.
Compare the fingerprint with the one in the server’s start-up log, then answer
y. For unattended use, put the server’s entry in ~/.hoarddb/known_servers
ahead of time.
-insecure skips the check altogether. It prints a warning that says exactly
what it gives up, and it is for a server you started yourself on the same
machine. It is a setting of the client and never makes a server less strict.
Do not put it in a script that talks to a server across a network.
Nodes trusting each other
Nodes use the same certificates between themselves. A node that is told to join
a cluster must be given the fingerprints it should expect
(HOARDDB_SEED_FINGERPRINTS) and refuses to start without them; a certificate
that changes for a node it already knows is a hard failure, not a quiet
re-trust. Configuration
has the details.
Your own certificate
You cannot substitute your own certificate in this version. A node started with
HOARDDB_TLS_MODE=custom, or with HOARDDB_TLS_CERT, HOARDDB_TLS_KEY or
HOARDDB_TLS_CA set, refuses to start: it exits with an error that names the
setting, rather than quietly serving the certificate it generated. Unset the
setting and use the generated certificate, which clients trust by its fingerprint. Operator-supplied
certificates come after 1.0. There is no certificate authority check to
configure; the fingerprint is the identity.
Users and authentication
Every connection logs in once, and what the connection may do is decided by the roles the user held at that moment.
- Passwords are hashed with Argon2id, with a server-side secret added, and
the plain text is never stored. A user’s password must be at least 12
characters (
HOARDDB_PASSWORD_MIN_LENGTH). - A password is never a command-line argument. The CLI prompts, or reads a
0600 file or standard input, so it does not end up in
psor shell history. - Repeated failures slow an address down. After five failed logins in a
row from one address, each further attempt is delayed, doubling from one second up to
thirty. At
HOARDDB_TCP_AUTH_MAX_FAILSfailures in a row (default 20) the address is refused outright for sixty seconds, before any password is checked. A successful login clears the count. - Roles are per database, from
readup toroot. A user with no grant on a database is refused there, and the refusal names the roles the user has and the command that would fix it. - Disabling or dropping a user ends that user’s sessions at once. Granting or revoking a role takes effect at the user’s next login; an open connection keeps the roles it logged in with. If you need a change to bite immediately, change the password or disable the user.
Creating users, roles and the full list of what each can do: User management. The honest list of what this model does not do: Limitations.
Rotating the root password
Stop the server and run:
hoardDB-server -reset-password admin
It asks for the new password twice, without echo, and deletes
<data dir>/root.password once the new one is written, so the bootstrap secret
does not linger on disk.
The cluster token
A cluster has a token that every node holds (<data dir>/cluster.token, mode
0600). On a clustered node the keys that sign login tokens are derived from it,
so whoever holds it can forge a login and can join a node to the cluster.
Treat it like a signing key: keep it out of backups that other people can read,
and delete it, and the node’s users.json, when you decommission a node.
Encryption at rest
Encryption at rest is built for a whole node, and it is off by default.
When it is off, the data directory is plaintext on disk, and only the
users.json file is sealed, which is not encryption at rest for your data. When
you turn it on, every bucket on that node is encrypted under a key that you
provide and that is not kept in the data directory:
encryption:
keystore: keyfile
key_file: /etc/hoarddb/kek
mode: require
What to know before you rely on it:
- It belongs to the node. One key opens every bucket on the node; there is no per-bucket key. Per-database and per-bucket keys are planned and are not built.
- It is decided when the data directory is first started. You cannot switch a node between encrypted and plaintext afterwards; you dump, and restore into a fresh directory started the way you want.
- An encrypted node seals
blobpayloads too. Blob content of 64 KiB and over is stored in files that are encrypted and authenticated in pieces, under keys kept inkeys/blobs.wrapped. Back that file up with the data directory: the node-master escrow does not cover it, and without it sealed blob files cannot be read. - A
dumpis plaintext whatever the node’s mode. Protect the file the way you protect the data. - Losing the key is unrecoverable data loss. Back the key up apart from the data directory.
- It protects a copied disk or data directory. It does not protect against someone who can run code as the server’s user, who can ask the same keystore for the key. It does not replace disk encryption either, which also covers swap and freed blocks.
How to set it up, the three places the key can come from, export and import of the node key, and what a cluster does with an unencrypted peer: Configuration.
Default network exposure
A node you start with no arguments listens on this machine only. Nothing on
the network can reach it until you say so. The Docker image is the exception: it
listens on every interface inside the container, because loopback inside a
container cannot be reached through docker run -p, and what the outside world
can reach is then decided by the ports you publish.
| What | Default (binary) | Docker image | Setting |
|---|---|---|---|
| Client port (TCP+TLS) | 127.0.0.1:7433 | 0.0.0.0:7433 | HOARDDB_TCP_LISTEN |
| Node-to-node port | 127.0.0.1:4434 | 0.0.0.0:4434 | HOARDDB_LISTEN (the node address; the port is its port plus one), or HOARDDB_TCP_INTERNODE_LISTEN to set it directly |
| Metrics | off; when on, 127.0.0.1:9090 | 0.0.0.0:9090 | HOARDDB_METRICS_ENABLED, HOARDDB_METRICS_LISTEN |
| Profiling | off; when on, 127.0.0.1:6060 | 127.0.0.1:6060 | HOARDDB_PPROF_ENABLED |
| Audit log | off | off | HOARDDB_AUDIT_ENABLED, HOARDDB_AUDIT_OUTPUT |
The start-up log says where the node listens, and when it is on loopback it names the settings that open it up.
The start-up log shows the node’s address in the ring, which is HOARDDB_LISTEN.
Its default, 127.0.0.1:4433 for HOARDDB_LISTEN, is the name other nodes use
for it, not a port the node opens.
Opening a node to other machines
Applications on other machines. Set the client address.
0.0.0.0means every interface; use one interface’s address to be narrower:HOARDDB_TCP_LISTEN=0.0.0.0:7433 hoardDB-serverA cluster across machines. Set
HOARDDB_LISTENto the address the other nodes reach this node on, and list that same address inHOARDDB_SEED_NODESon every node:HOARDDB_LISTEN=10.0.0.1:4433 HOARDDB_SEED_NODES=10.0.0.1:4433,10.0.0.2:4433,10.0.0.3:4433 ...A node whose seeds are on another machine but which is still on the loopback default is refused at start, with the setting to change in the message: it would tell its peers to reach it on
127.0.0.1, which only it can do. A cluster whose nodes all run on one machine (every seed on127.0.0.1) needs no change.
Two things follow:
- On a host that is reachable from outside your network, bind to the interface
your applications use rather than
0.0.0.0, or put a firewall in front of the client port and the node-to-node port. Peers must hold the cluster token to use the node-to-node port, but the port accepts a connection from anywhere it is reachable, so keep it to the nodes of your cluster. - The client port is protected by login and TLS, not by obscurity. Anyone who can reach it can try passwords, which the failure delay slows down but does not stop. Choose long root and user passwords.
Metrics exposure
When you enable metrics, /metrics is served over plain HTTP with no
authentication. It reports counts, durations and capacity readings for the
node and carries no document content, and it keeps no series per bucket. It is
still information about your system. It listens on the loopback interface by
default, so a scraper on the same machine needs nothing more; to let a
monitoring host reach it, bind to the address of your monitoring network (not
0.0.0.0 on a host that faces the internet):
HOARDDB_METRICS_ENABLED=true HOARDDB_METRICS_LISTEN=10.0.0.5:9090 hoardDB-server
With metrics off, the node’s capacity warnings still go to its log and to
hoardDB status; see Is this node full?. The profiling endpoint
is also unauthenticated and plain; leave it off on a server.
What is not protected
A short list, so that you do not assume otherwise:
- A connection is checked when it logs in, not on every request. A role change reaches an open connection only at its next login.
- There is no way to revoke one login token without affecting that user’s others. Revocation is per user.
- Anyone who holds the cluster token can act as a cluster member and can forge logins (above).
- Anyone who can read the data directory can read a plaintext node’s data.
The only file sealed on a node without encryption at rest is
users.json, and its key sits in the same directory. - A dump file, and the key file you export for escrow, are not encrypted.
- The CLI’s
-insecureflag removes the server-identity check for that session.
Reporting a vulnerability
Please report a security problem privately, not in a public issue or a discussion.
Send your report to the security contact named in SECURITY.md at the root of
the repository (TODO(owner): contact address). Include:
- what you found and which version or commit it affects (
hoardDB-server -v); - how to reproduce it, as short as you can make it;
- what an attacker gains, if you know.
We acknowledge a report, agree a disclosure date with you, and fix the problem before it is described in public. A security fix is announced in the changelog after it ships, and the people who reported it are credited if they want to be. Please do not test against systems you do not own.
Source: docs/user/security.md in the repository.