CodamAIDocs
Topicdone

Storage on WORM

Where the bytes of a final document are kept: encrypted in an S3 bucket with Object Lock, what CRMS checks at start, and who brings the storage.

Variants
bucket with Object Lockbucket without Object Lock (development only)embedded (local)separate service (remote)document revisions off

What this is about

WORM means write once, read many: write once, read as often as you like, never change. CRMS puts the bytes of every final document into such a storage. Technically this is an S3 bucket with Object Lock. S3 is a widely used interface for object storage (for example MinIO, AWS, OBS). Object Lock is the S3 feature that locks an object until a date.

CRMS locks in compliance mode. In this mode nobody can delete or change an object before its lock ends, not even the operator with full rights on the bucket.

What happens when storing

  1. 1
    CRMS
    creates a document key, 256 bits, just for this document
  2. 2
    CRMS
    encrypts the bytes with AES-256-GCM and binds them to the revision
  3. 3
    CRMS→File storage
    stores the encrypted bytes under crms/<owner>/<chain>/<revision>, locked until retainUntil, and with a legal hold too while one applies
  4. 4
    File storage→CRMS
    answers with the object's version id
  5. 5
    CRMS→Database
    records object key and version id in the revision
    Result: The revision knows exactly which version of which object belongs to it
  • The bucket sees only encrypted bytes. Whoever can read the bucket still cannot read the document.
  • The lock is rounded up to the full second. It is never shorter than what the revision records.
  • Every access names the version id. On a locked bucket, a delete without a version “succeeds” but only sets a delete marker, and the object stays. That is why CRMS always addresses exactly the version.

The keys

Every document key is itself stored encrypted, “wrapped” with the key-encryption key from CODAMAI_CRMS_DOCUMENT_KEY (256 bits, Base64). CRMS needs the key-encryption key as long as document revisions are on. If it is missing, CRMS does not start.

Wrapping is bound to the id and owner of the document key. If someone copies wrapped bytes into another row, they cannot be unwrapped there.

One key per document allows erasure by destroying the key, see Retention, legal hold and erasure.

What CRMS checks at start

Bucket exists?Object Lock on?CODAMAI_CRMS_STORAGE_ALLOW_UNLOCKEDVersioning on?Start
no–––fails
yesyes––starts, objects are locked
yesnofalse–fails
yesnotruenofails
yesnotrueyesstarts without a lock, legal holds are not set

CODAMAI_CRMS_STORAGE_ALLOW_UNLOCKED=true is meant for development only. Without a lock, the storage is no longer WORM storage.

The bucket

  • Its name is what CODAMAI_CRMS_DOCUMENT_BUCKET says. The variable is required.
  • You create it, not CRMS, and you create it with Object Lock. On many S3 stores, Object Lock cannot be switched on later. Whoever may create a bucket could also create it without a lock. That is why CRMS does not do it itself.
  • The connection is the same for all CodamAI modules: CODAMAI_S3_ENDPOINT, CODAMAI_S3_ACCESS_KEY, CODAMAI_S3_SECRET_KEY, plus CODAMAI_S3_REGION (default us-east-1) and CODAMAI_S3_PATH_STYLE (default true, MinIO needs it). Each module names only its own bucket. All variables are listed in Configuration.

Who brings the storage

Storage per operating mode
embeddedseparate service
Where CRMS runsin your applicationin the CRMS service
Who brings the CRMS S3 storageyour application, as long as document revisions are onthe CRMS service
Who configures the bucketyour applicationthe CRMS service. Your application needs no bucket

If document revisions are off (CODAMAI_CRMS_DOCUMENT_REVISIONS=false), no operating mode needs a storage. FINAL is then refused. More about the operating modes in Embedded or as a separate service.

Errors from the storage

KeyStatusMeaning
document-locked409S3 refused a delete or change: lock or legal hold
document-object-missing500S3 does not hold this version
storage-versioning-missing500S3 returned no version id, the bucket is not versioned
storage-failed502any other refusal by S3, details in the log

Pitfalls

Next

Search