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
-
1CRMScreates a document key, 256 bits, just for this document
-
2CRMSencrypts the bytes with AES-256-GCM and binds them to the revision
-
3CRMS→File storagestores the encrypted bytes under
crms/<owner>/<chain>/<revision>, locked untilretainUntil, and with a legal hold too while one applies -
4File storage→CRMSanswers with the object's version id
-
5CRMS→Databaserecords object key and version id in the revisionResult: 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_UNLOCKED | Versioning on? | Start |
|---|---|---|---|---|
| no | – | – | – | fails |
| yes | yes | – | – | starts, objects are locked |
| yes | no | false | – | fails |
| yes | no | true | no | fails |
| yes | no | true | yes | starts 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_BUCKETsays. 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, plusCODAMAI_S3_REGION(defaultus-east-1) andCODAMAI_S3_PATH_STYLE(defaulttrue, MinIO needs it). Each module names only its own bucket. All variables are listed in Configuration.
Who brings the storage
| embedded | separate service | |
|---|---|---|
| Where CRMS runs | in your application | in the CRMS service |
| Who brings the CRMS S3 storage | your application, as long as document revisions are on | the CRMS service |
| Who configures the bucket | your application | the 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
| Key | Status | Meaning |
|---|---|---|
document-locked | 409 | S3 refused a delete or change: lock or legal hold |
document-object-missing | 500 | S3 does not hold this version |
storage-versioning-missing | 500 | S3 returned no version id, the bucket is not versioned |
storage-failed | 502 | any other refusal by S3, details in the log |