Minimal and persistent key-value store designed with security in mind

Overview

microkv

Actions crates.io version Docs

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 RwLocks, 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!

License

MIT license

Comments
  • Make read and write locks useful

    Make read and write locks useful

    This PR would close #14. It servers as a proposal to discuss the direction we should go to solve this problem. If this is the way we want to go, I can extend it to the remaining useful functions and we can merge the PR.

    opened by plainerman 6
  • Support set base path, and change key use AsRef<str> to support multiple string types

    Support set base path, and change key use AsRef to support multiple string types

    Some OS not have HOME environment, like windows. or want sore file to special path. so this pr add some new api to set it.

    • new_with_base_path
    • open_with_base_path

    And change store key from &str to AsRef<str>, this way help to simple to use these api. multiple string can be set &str String OsString ...

    support auto commit

    opened by fewensa 3
  • Add serialize trait to get value

    Add serialize trait to get value

    Sometimes the value is not necessarily fixed and similar. After adding serialize, you can use serde to serialize it to what you want. like there

    https://github.com/darwinia-network/bridger/blob/d87e725a3c0c1d145f9a99104f47964050498ddb/bin/src/route/kv.rs#L43

    The server query from microkv, and response data to client, maybe any types, so there can be serialize to serde_json::Value, need add Serialize to there.

    This pull request is include https://github.com/ex0dus-0x/microkv/pull/10, I think the namespace is important. so please consider merging first #10

    opened by fewensa 1
  • Derive clone

    Derive clone

    Derive clone, support multiple runtime/thread.

    for example: when we create a system have multiple threads, but all thread share global state, this state include microkv, now we need microkv support Clone send to all thread.

    Maybe also need Send + Sync ? not currently needed, add if necessary.

    I think need derive it, and I wrote a test in playground, https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=62d4ef3361532d074676ab37d28b003d and add a new test test_multiple_thread It's work's. if you have any questions, you can tell me, I'll change it.

    the reason for not using borrowing is that the lifetime makes the code very complicated.

    opened by fewensa 1
  • `put` should take `&V` instead of `V`

    `put` should take `&V` instead of `V`

    https://github.com/ex0dus-0x/microkv/blob/610cdee922a7634f1bbc8382ea38246c8ee33d7d/src/kv.rs#L230

    The only use of _value is to pass a reference to bincode::serialize. Thus, _value should be of type &V instead of V. The way it is now: if your caller has only a reference then you force your caller to make an unnecessary clone into _value in order to call put.

    opened by ggutoski 1
  • unused type parameter for `exists`

    unused type parameter for `exists`

    https://github.com/ex0dus-0x/microkv/blob/610cdee922a7634f1bbc8382ea38246c8ee33d7d/src/kv.rs#L307-L314

    Seems that the type parameter K is not actually used in exists. The compiler cannot infer the type for K, so I must add an explicit type annotation in order to call exists.

    opened by ggutoski 1
  • Usefulness of locks

    Usefulness of locks

    Thank you for creating this awesome project. The only issue I have is that the current state of the read and write lock are lacking helper functions to be useful. I see the following main issues:

    1. microkv uses bincode serialization, when only having the IndexMap (e.g., read or write lock) users would have to do the serialization + encryption themselves
    2. making matters worse, external encryption part cannot rely on the stored secret as it is private. So users would need to store it in a second place
    3. formatting the namespace strings is private, so users cannot access them and need to build them in the closure themselves (which is not very nice)

    I propose we extend the index map in such a way that we have helper functions (that are also used internally by the namespaces). With them, users can use them inside a lock like this

    db.lock_write(|mut kv| {
        kv.kv_put(db, "namespace", "key", 1);
    }
    

    I created a PR that serves as a proposal to discuss a a possible direction we could go to solve this problem (#15). If this is the way we want to go, I can extend it to the remaining useful functions and we can merge the PR.

    I would love to hear your opinion on this issue.

    opened by plainerman 0
  • Proposal: Raft consensus PoC

    Proposal: Raft consensus PoC

    Demonstrate how we can implement some type of consensus, ideally with Raft with microkv. This should work with the CLI application that is currently being implemented, and should demonstrate how the minimal API can be incorporated well within a distributed systems context.

    enhancement experimental 
    opened by ex0dus-0x 0
  • Try to mitigate tampering with Shamir Secret Sharing

    Try to mitigate tampering with Shamir Secret Sharing

    Besides using strong symmetric encryption for cold storage, we could also use threshold-based techniques to try to shard the database for some type of distribution.

    opened by ex0dus-0x 0
  • Proposal: cross-compatible secure enclaves

    Proposal: cross-compatible secure enclaves

    We should consider phasing out secstr for our own "secured memory" implementation, with full support for other primitives for isolating memory pages to support different OSes:

    • Linux - typical support for mlock and zeroing, but also thinking MFD_SECRET_*, as posed here to further isolate sensitive memory from kernel space and even cache. Have not seen a merge upstream to a new revision yet, but interesting to think about.

    • macOS - mlock again, but also potentially pushing support for Secure Enclave storage, which will requiring signing rather than our current symmetric encryption.

    • Windows - CryptProtectMemory and SecureZeroMemory for explicit zeroing.

    Backing to other native "keyring" implementations (Credential Manager, macOS Keychain) are also interesting and provides security and isolation for free(-ish).

    opened by ex0dus-0x 0
Owner
Alan
Security Engineer | NYU 2023
Alan
🕵️‍♀️ Find, locate, and query files for ops and security experts ⚡️⚡️⚡️

Recon Find, locate, and query files for ops and security experts Key Features • How To Use • Download • Contributing • License Key Features Query with

Rusty Ferris Club 11 Dec 16, 2022
OpenSK is an open-source implementation for security keys written in Rust that supports both FIDO U2F and FIDO2 standards.

OpenSK This repository contains a Rust implementation of a FIDO2 authenticator. We developed OpenSK as a Tock OS application. We intend to bring a ful

Google 2.4k Jan 7, 2023
Automate device security provisioning with edge intelligence.

UNiD Automate device security provisioning with edge intelligence Features Decentralized PKI(DPKI), DIDs, DKMS, and Credential Management End-to-End E

UNiD 101 Oct 21, 2022
A utility like pkg-audit for Arch Linux. Based on Arch Security Team data.

arch-audit pkg-audit-like utility for Arch Linux. Based on data from security.archlinux.org collected by the awesome Arch Security Team. Installation

Andrea Scarpino 316 Nov 22, 2022
The Swiss Army Knife for Binary (In)security

binsec Swiss Army Knife for Binary (In)security binsec is a minimal static analysis utility for detecting security capabilities in ELF/PE/Mach-O execu

Alan 15 Dec 16, 2022
A Rust implementation of the Message Layer Security group messaging protocol

Molasses An extremely early implementation of the Message Layer Security group messaging protocol. This repo is based on draft 4 of the MLS protocol s

Trail of Bits 109 Dec 13, 2022
Bindings to the macOS Security.framework

macOS/iOS Security framework for Rust Documentation Bindings to the Apple's Security.framework. Allows use of TLS and Keychain from Rust. License Lice

Kornel 172 Jan 2, 2023
Applied offensive security with the Rust programming language

Black Hat Rust Applied offensive security with the Rust programming language Buy the book now! While the Rust Book does an excellent job teaching What

Sylvain Kerkour 2.2k Jan 8, 2023
Audit Cargo.lock files for dependencies with security vulnerabilities

RustSec Crates ?? ??️ ?? The RustSec Advisory Database is a repository of security advisories filed against Rust crates published via crates.io. The a

RustSec 1.2k Jan 5, 2023
Security advisory database for Rust crates published through crates.io

RustSec Advisory Database The RustSec Advisory Database is a repository of security advisories filed against Rust crates published via https://crates.

RustSec 682 Jan 1, 2023
irulescan is a static security analyzer for iRules

irulescan is a tool to scan iRules for unexpected/unsafe expressions that may have undesirable effects like double substitution.

Simon Kowallik 2 Dec 18, 2022
cert_installer - a utility that adds a CA certificate to Android's System Trust Store

cert_installer is a utility that adds a CA certificate to Android's System Trust Store by overwriting the /system/etc/security/cacerts directory with a tmpfs mount. Changes made to the System Trust Store is not persistant across reboots.

Terry Chia 5 Apr 11, 2022
The Heros NFT Marketplace Boilerplate project is designed to let users fork, customize, and deploy their own nft marketplace app to a custom domain, ultra fast.

Heros NFT on Solana The Heros NFT Marketplace Boilerplate project is designed to let users fork, customize, and deploy their own nft marketplace app t

nightfury 6 Jun 6, 2022
Bottlerocket - An operating system designed for hosting containers

Bottlerocket OS Welcome to Bottlerocket! Bottlerocket is a free and open-source Linux-based operating system meant for hosting containers. If you’re r

null 7k Dec 31, 2022
Steals browser passwords and cookies and sends to webhook.

Browser-Stealer Steals browser passwords and cookies and sends to webhook. Donating Educational Purposes Only This code is made so you can learn from

RadonCoding 3 Sep 27, 2021
Xori is an automation-ready disassembly and static analysis library for PE32, 32+ and shellcode

Xori - Custom disassembly framework Xori is an automation-ready disassembly and static analysis library that consumes shellcode or PE binaries and pro

ENDGAME 712 Nov 28, 2022
Semi-automatic OSINT framework and package manager

sn0int sn0int (pronounced /snoɪnt/) is a semi-automatic OSINT framework and package manager. It was built for IT security professionals and bug hunter

null 1.4k Dec 31, 2022
A Comprehensive Web Fuzzer and Content Discovery Tool

rustbuster A Comprehensive Web Fuzzer and Content Discovery Tool Introduction Check the blog post: Introducing Rustbuster — A Comprehensive Web Fuzzer

Francesco Soncina 467 Dec 26, 2022
A simple menu to keep all your most used one-liners and scripts in one place

Dama Desktop Agnostic Menu Aggregate This program aims to be a hackable, easy to use menu that can be paired to lightweight window managers in order t

null 47 Jul 23, 2022