microkv
Minimal and persistent key-value store designed with security in mind.
Introduction
microkv is a persistent key-value store implemented in Rust, aiming to maintain a balance between security and performance. It is built out of a yearning to learn more about the intricacies of distributed systems, databases, and secure persistent storage.
While microkv shouldn't be used in large-scale environments that facilitate an insane volume of transactional interactions, it is still optimal for use in a production-grade system/application that may not require the complex luxuries of a full-blown database or even industry-standard KV-store like Redis or LevelDB.
Example Use Cases
- Local persistent serialization for sensitive configurations
- Secrets management for a single-process application
- License key management
Features
- Performant
microkv's underlying map structure is based off of @bluss's indexmap implementation, which offers performance on par with built-in HashMap
's amortized constant runtime, but can also provided sorted key iteration, similar to the less-performant BTreeMap
. This provides a strong balance between performance and functionality.
When reading and persisting to disk, the key-value store uses bincode
for fast de/serialization of the underlying structures, allowing users to insert any serializable structure without worrying about incurred overhead for storing complex data structures.
- Secure
microkv acts almost in the sense of a secure enclave with any stored information. First, inserted values are immediately encryped using authenticated encryption with XSalsa20 (stream cipher) and Poly1305 (HMAC) from sodiumoxide
, guarenteeing security and integrity. Encryped values in-memory are also memory-locked with mlock
, and securely zeroed when destroyed to avoid persistence in memory pages.
microkv also provides locking support with RwLock
s, which utilize mutual exclusion like mutexes, but robust in the sense that concurrent read locks can be held, but only one writer lock can be held at a time. This helps remove thread-safety and data race concerns, but also enables multiple read accesses safely.
- Small
At its core, microkv is implemented in ~500 LOCs, making the implementation portable and auditable. It remains faithfully opinionated, meaning it will not offer extensions to other serializable formats, or any other user-involved configurability, allowing it to work right out of the box.
Design
Usage
To install locally, simply clone the repository and install with cargo
:
# .. from crates.io
$ cargo install microkv
# .. or locally
$ git clone https://github.com/ex0dus-0x/microkv
$ cargo install --path .
Here's example usage of the microkv
library crate:
use microkv::MicroKV;
#[derive(Serialize, Deserialize, Debug)]
struct Identity {
uuid: u32,
name: String,
sensitive_data: String,
}
fn main() {
let unsafe_pwd: String = "my_password_123";
// initialize in-memory database with (unsafe) cleartext password
let db: MicroKV = MicroKV::new("my_db")
.with_pwd_clear(unsafe_pwd);
// ... or backed by disk, with auto-commit per transaction
let db: MicroKV = MicroKV::open_with_base_path("my_db_on_disk", SOME_PATH)
.expect("Failed to create MicroKV from a stored file or create MicroKV for this file")
.set_auto_commit(true)
.with_pwd_clear(unsafe_pwd);
// simple interaction to default namespace
db.put("simple", 1);
print("{}", db.get_unwrap("simple").unwrap());
db.delete("simple");
// more complex interaction to default namespace
let identity = Identity {
uuid: 123,
name: String::from("Alice"),
sensitive_data: String::from("something_important_here")
};
db.put("complex", identity);
let stored_identity: Identity = db.get_unwrap("complex").unwrap();
println!("{:?}", stored_identity);
db.delete("complex");
}
microkv also supports transactions on other namespaces to support grouping and organizing keys (thanks @fewensa!):
let namespace_one = db.namespace("one");
namespace_one.put("zoo", &"big".to_string()).unwrap();
microkv also includes a simple command line application that is installed alongside the package. While not entirely useful at the moment, future plans are to be able to integrate it such that it can be exposed through a Docker container.
Contributions
Interested on improving the state of this project? Check out the issue tracker for what we need help on!