Encryption & Security

ZeroFS encrypts all your data by default using XChaCha20-Poly1305. In this guide, we'll explore how encryption works, what's protected, and security best practices for deployments.

How Encryption Works

Key Architecture

  1. Data Encryption Key (DEK): A 256-bit key that encrypts your actual data
  2. Key Encryption Key (KEK): Derived from your password using Argon2id
  3. Encrypted DEK Storage: The DEK is encrypted with the KEK and stored in the database

This approach allows you to change your password without re-encrypting all data.

Encryption Algorithm

  • Algorithm: XChaCha20-Poly1305
  • Compression: Zstd (default) or LZ4 compression before encryption
  • Key Derivation: Argon2id

Configuration

# ZeroFS generates a new DEK on first run
[storage]
url = "s3://bucket/path"
encryption_password = "strong-password"

Password Change

# Change password without re-encrypting data
zerofs change-password --config zerofs.toml

# Enter new password when prompted
# ZeroFS re-encrypts only the DEK, not all data

# Update config file afterwards:
# encryption_password = "new-strong-password"

What's Encrypted

Encryption applies at the SST block level: ZeroFS hands each encoded block (containing keys, values, and the block's internal index) to ZeroFS's block transformer, which compresses then encrypts the whole block. Decryption happens once per block on read; comparisons inside a block run on plaintext keys in memory, so there's no per-key encryption overhead.

Encrypted at Rest

  • Name
    File Contents
    Type
    encrypted
    Description

    All file data is encrypted in 32KB chunks using unique nonces

  • Name
    File Metadata
    Type
    encrypted
    Description

    Permissions, timestamps, ownership, directory-entry payloads, symlink targets, and other inode data

  • Name
    Keys Inside Blocks
    Type
    encrypted
    Description

    Inode IDs, directory entry names, chunk identifiers, each block is encrypted as a unit, so the keys it indexes are protected

  • Name
    SST Index & Filter Blocks
    Type
    encrypted
    Description

    Per-block first-key markers and bloom filter contents

Visible in Plaintext on the Object Store

  • Name
    Per-SST First/Last Key
    Type
    plaintext
    Description

    The SST footer's SsTableInfo flatbuffer stores each SST's first and last key in plaintext. For a directory-entry SST this leaks the lexicographically-first and -last (dir_id, filename) it contains.

  • Name
    Manifest
    Type
    plaintext
    Description

    SST IDs, segment prefixes ("meta", "chunk"), object sizes, checkpoint pointers, format version

  • Name
    Object Metadata
    Type
    plaintext
    Description

    SST blob names, sizes, and counts (anything visible to an S3 LIST).

Local Cache Directory

  • Name
    Cache Contents
    Type
    plaintext
    Description

    The on-disk cache (default ~/.cache/zerofs) stores decrypted, decompressed SST blocks so subsequent reads don't pay the decrypt cost.

What S3 Sees

# Encrypted block payloads in SST data files:
s3://bucket/path/
├── compacted
   ├── 01K1JW549K0H0MV3FH28CKBWTY.sst
   ├── 01K1JW54FCCA109H1RJEHZ5NYK.sst
   ├── 01K1JW54KE1XMV5DQG9KQ5R9B5.sst
├── manifest
   ├── 00000000000000000001.manifest
   └── ...
└── wal
    ├── 00000000000000000001.sst
    └── ...
# Inside each SST:
# - Data blocks: encrypted (keys + values opaque on disk)
# - Index blocks: encrypted (per-block first-key markers)
# - Filter blocks: encrypted (bloom filter bytes)
# - SST footer (SsTableInfo): plaintext, includes
#   the SST's first and last key
# The manifest is plaintext.

Password Management

Secure password management is critical for ZeroFS deployments:

Password Requirements

  • Minimum Length: No enforced minimum, but use 25+ characters
  • Complexity: Use a mix of characters or a passphrase

Secure Password Practices

# Generate a secure password
openssl rand -base64 32

# Store in a secret manager (AWS example)
aws secretsmanager create-secret \
  --name zerofs-prod-password \
  --secret-string "$(openssl rand -base64 32)"

# Use in production with environment variable substitution
# In zerofs.toml:
# [storage]
# encryption_password = "${ZEROFS_PASSWORD}"

export ZEROFS_PASSWORD=$(
  aws secretsmanager get-secret-value \
    --secret-id zerofs-prod-password \
    --query SecretString --output text
)

zerofs run --config zerofs.toml

Lost Password Recovery

Security Best Practices

Network Security

# Bind to localhost only (default) in zerofs.toml
[servers.nfs]
addresses = ["127.0.0.1:2049"]

[servers.nbd]
addresses = ["127.0.0.1:10809"]

# For remote access, use VPN or SSH tunneling
# ssh -L 2049:localhost:2049 user@zerofs-server

Security Architecture

Was this page helpful?