Security
Off by default. Turn it on and the first command on a connection is authenticate, with both a user and a password.
With [security] commented, or enabled false, every command is accepted. That is the server the install starts. Turn it on when a connection must prove who it is, and when you want page files and the log encrypted.
[security] enabled = true encryption_key = ""
KOVA_SECURITY_ENABLED overrides enabled. KOVA_ENCRYPTION_KEY overrides the key. The key is 64 hex characters (32 bytes). Empty leaves the files compressed and readable. Set it and each page file and each log record is AES-256-GCM, with a fresh nonce per write. The buffer pool and your queries still see plaintext. Startup with encrypted files and no key fails. A data directory does not mix encrypted and plaintext pages.
The first user
The catalog starts empty. The first createUser has to be root. After that, a connection authenticates before any other command.
db.getSiblingDB("admin").runCommand({
createUser: "root",
pwd: "secret",
roles: ["root"]
})
db.getSiblingDB("admin").runCommand({
authenticate: 1,
user: "root",
pwd: "secret"
})
The password is stored as an Argon2id hash. The plaintext is not written to the catalog or the log. authenticate checks the hash and binds the connection to that user. Later commands on the same connection are checked against the user's roles. A disabled user and an unknown user fail the same way. A wrong password fails the same way.
secret for root and ada-secret for ada are sample values. Pick your own before anyone else can reach the port.
Roles
Five built-in roles. A custom role is a name plus a subset of the actions below. A custom role cannot name an action outside the list. The command fails and names the rejected action. A built-in role cannot be dropped.
| Role | Actions |
|---|---|
read | find (find, count, aggregate, search, sql) |
readWrite | read, plus insert, update, remove |
dbAdmin | readWrite, plus createCollection, dropCollection, createIndex, dropIndex, viewStatus |
userAdmin | createUser, grantRole |
root | All eleven actions |
| Action | Commands |
|---|---|
find | find, count, aggregate, search, sql |
insert | insert |
update | update |
remove | delete |
createCollection | create |
dropCollection | drop, dropDatabase |
createIndex | createIndexes |
dropIndex | dropIndexes, deleteIndexes |
viewStatus | collStats, dbStats, listCollections, listIndexes, listDatabases, serverStatus |
createUser | createUser, updateUser |
grantRole | createRole, dropRole, grantRolesToUser, revokeRolesFromUser |
More users
db.runCommand({
createUser: "ada",
pwd: "ada-secret",
roles: ["read"]
})
db.runCommand({
createRole: "payroll",
actions: ["find", "insert", "update"]
})
db.runCommand({
grantRolesToUser: "ada",
roles: ["payroll"]
})
db.runCommand({ updateUser: "ada", enabled: false })
db.runCommand({
revokeRolesFromUser: "ada",
roles: ["payroll"]
})
db.runCommand({ dropRole: "payroll" })
updateUser enables or disables the account. Disabling closes that user's open connections. root can be granted. The last root cannot be revoked or disabled.
ODBC sends UID and PWD as this same authenticate before SQL. Both empty stays anonymous, which matches security left off. Both set logs in. One of the two is refused.