Key takeaways
- S3 Object Lock in compliance mode stops every user, including the AWS account root user, from deleting or overwriting a protected version until its retain-until date. It requires versioning and can be enabled on existing buckets, but cannot be turned off afterward.
- SSE-KMS protects who can read an object. It is not, by itself, integrity proof that an outsider can check.
- AWS KMS HMAC keys (GenerateMac and VerifyMac) give an integrity check that only parties with access to the key can verify. Asymmetric signing keys (Sign and Verify) let a third party verify offline with the public key, which makes them the stronger evidence.
- Amazon SES cannot write to a bucket that has default Object Lock retention, so the usual design stages the message, then copies it to the locked bucket with explicit retention.
- A good archive also keeps S3 SHA-256 checksums, CloudTrail records and, optionally, an RFC 3161 timestamp, and has a written routine for verifying everything years later.
The problem: a promise you have to be able to prove
Some firms have to show, years later, exactly what they sent and received, because a regulator asks, a client disputes it or a court orders it. A folder of saved messages is not proof: anyone with enough access could have changed a file, and nobody can show they did not. This article lays out the building blocks on Amazon Web Services (AWS) for an email archive that cannot be deleted and whose contents can be proven, what each does and does not do, and how to choose.
Two questions are involved, and mixing them up causes most design mistakes. Can anyone delete or overwrite the stored message? That is storage. Can you prove it is exactly what was captured? That is cryptography. AWS answers the first with Amazon S3 Object Lock and the second with AWS Key Management Service (AWS KMS), plus a few supporting records.
Layer 1: make the storage undeletable
Amazon S3 Object Lock uses a write-once-read-many (WORM) model. AWS describes it as preventing objects from being deleted or overwritten for a fixed or variable amount of time, or indefinitely. It works only in buckets that have S3 Versioning turned on, and it protects individual object versions. A simple delete request only adds a delete marker on top; a permanent delete of a locked version returns Access Denied.
Object Lock has two retention modes. In governance mode, users cannot overwrite or delete a version or change its lock unless they hold special permission (s3:BypassGovernanceRetention). In compliance mode, no user can overwrite or delete a protected version, including the root user of the AWS account. The mode cannot be changed and the period cannot be shortened. AWS states that the only way to delete an object under compliance mode before its retain-until date is to delete the AWS account itself.
Retention can be set per object or as a bucket default in days or years; an explicit setting on an upload overrides the default. A legal hold is separate: it has no expiry date and stays until someone with s3:PutObjectLegalHold removes it. If a retention period ends while a legal hold is on, the object stays protected. Use it when litigation is announced and the end date is unknown.
A point that surprises people: existing buckets can use Object Lock. AWS documents turning it on for an existing bucket (console, AWS Command Line Interface, SDKs, REST API) as long as versioning is enabled. Two cautions apply. After you enable Object Lock you cannot disable it or suspend versioning for that bucket, and the console asks you to acknowledge that the change is permanent.
Weaker alternatives exist, and it helps to know where they stop:
- S3 Versioning alone keeps old versions and turns deletes into delete markers, but anyone with the right permission can still delete a specific version.
- MFA Delete requires a second authentication factor to permanently delete a version or change the versioning state. Only the bucket owner (the root account) can enable it, and not from the console; it needs the AWS CLI or the API. It adds friction against stolen credentials but is not a retention period or a WORM guarantee.
- A bucket policy that denies deletes is a useful second layer, but whoever can edit the policy can undo it. It is a rule, not a lock.
- AWS Backup Vault Lock applies WORM protection to backup vaults. In compliance mode it has a cooling-off period (a grace time of at least 3 days), after which the vault and its lock cannot be changed or deleted by any user or by AWS while recovery points exist. It protects backups, so we treat it as a second copy, not the primary store.
AWS publishes a Cohasset Associates assessment of S3 Object Lock for environments subject to SEC Rule 17a-4, CFTC and FINRA regulations. It is a starting point for a compliance officer, not a replacement for a review of your own rules.
Layer 2: prove what the message said, using AWS KMS
Locking the file stops removal. It does not prove the file is what was captured on day one. For that you want a cryptographic record made at capture time. AWS KMS offers three levels, and they are not interchangeable.
Option A: SSE-KMS encryption only. With server-side encryption using AWS KMS keys, S3 asks KMS for a data key for each object, and the key policy controls who can use the KMS key. This is strong for confidentiality and an access trail. By itself it is not proof of integrity that an outsider can check.
Option B: KMS HMAC keys. An HMAC KMS key is a symmetric key used with the GenerateMac and VerifyMac operations. The key material is generated in AWS KMS hardware security modules and never leaves AWS KMS unencrypted. You send a message of up to 4,096 bytes, or a hash of it, and get a message authentication code back. Later, VerifyMac with the same key, message and algorithm confirms the match. The HMAC_256 key spec uses the HMAC_SHA_256 algorithm. This is a good integrity check inside your organization. But verification always means calling KMS, so only parties you grant access to the key can verify, and verification ends if the key is deleted. An HMAC is a shared-secret construction, so it is weaker evidence to an outside party.
Option C: KMS asymmetric signing keys. An asymmetric KMS key with key usage SIGN_VERIFY signs with a private key that stays inside KMS. The Sign operation accepts messages up to 4,096 bytes. For larger content you compute the hash yourself and pass it with MessageType set to DIGEST, so KMS does not hash it a second time. A common choice is a SHA-256 digest signed with an ECC_NIST_P256 key and the ECDSA_SHA_256 algorithm; RSA key specs with RSASSA-PSS are the other usual choice. Record the KMS key and the signing algorithm, because AWS notes both are needed to verify. The decisive advantage: you can download the public key with GetPublicKey and verify the signature outside AWS KMS. AWS says anyone with the public key can verify that the message was signed by that private key and has not changed since. A regulator or an opposing expert can check it without any AWS account. That is why we treat Option C as the strongest for evidence.
One limit applies to both: neither carries a timestamp. AWS suggests putting a timestamp inside the message you sign, and the records in the next section help show when.
Layer 3: independent records that back the signature
Good evidence does not hang on one control. We add records that one administrator could not rewrite alone.
- S3 additional checksums. SHA-256 is a supported algorithm, but the default is CRC-64/NVME, so SHA-256 has to be requested. S3 independently calculates the checksum on the server and validates it against the one you send before storing the object. A Compute checksum job in S3 Batch Operations can re-verify objects at rest. When SSE-KMS is used, the checksum in the object metadata is stored in encrypted form. We use the SHA-256 checksum as the message fingerprint and do not rely on the ETag.
- AWS CloudTrail. KMS calls, including cryptographic operations, are logged in CloudTrail. So the Sign or GenerateMac call that produced your evidence is itself recorded with the caller, time and key. S3 object-level data events (PutObject, GetObject, DeleteObject) are not logged by default; you must create a trail and enable them. A trail can be set to exclude KMS events, which would hide key use, so restrict who can change event selectors. CloudTrail log file integrity validation adds hourly signed digest files, using SHA-256 for hashing and SHA-256 with RSA for signing, so a changed or removed log file can be detected.
- A trusted timestamp. RFC 3161 defines how a Time Stamping Authority (TSA) time-stamps a piece of data to give proof that it existed at a given moment. Sending a daily hash of your manifests to an outside TSA gives a time proof that does not depend on AWS. It is optional.
- Amazon QLDB, AWS's ledger database, is a tempting fit for verifiable history. AWS has announced the end of support for it, so we do not recommend a new evidence design on it.
Capturing the email in the first place
Everything above starts once a copy of the message lands in storage. How you get that copy depends on the mail platform.
Amazon Simple Email Service (Amazon SES) receipt rules can deliver incoming mail to an S3 bucket. SES provides the raw, unmodified message in MIME format, with a default maximum size of 40 MB including headers. Here is the catch that shapes the design: AWS states that SES does not support receipt rules that upload to S3 buckets with Object Lock configured with a default retention period. So the usual pattern is two buckets. SES writes to a staging bucket without default retention. A small function then copies each message into the locked bucket with an explicit retention setting, computes the SHA-256 hash, and asks KMS to sign it. The staging copy expires on a short schedule. Note also that if you turn on message encryption in the SES action, SES encrypts with the S3 encryption client, not S3 server-side encryption, so you need that client to read the message back. Many designs skip that setting and use SSE-KMS on the final bucket.
For Microsoft 365, journaling is the mechanism for sending a copy of mail outside the tenant. Microsoft describes a journal report as a message the Journaling agent creates when a message matches a journal rule; the original message is included unaltered as an attachment, and the body carries details such as sender, subject, message ID and recipients. A journaling mailbox cannot be an Exchange Online mailbox. Reports go to an on-premises system or a third-party archiving service, so the address must point at a system you control, and Microsoft notes that you are responsible for watching non-delivery receipts. Microsoft recommends Microsoft 365 retention where it meets your needs, since journaling is an older feature.
DomainKeys Identified Mail (DKIM) adds sender-side evidence. A DKIM signature is made with the sending domain's private key, and recipient servers verify it with a public key in DNS. In Amazon SES it is optional, with Easy DKIM, Bring Your Own DKIM, or manual signing. It shows the message was authorized by the domain owner and that signed parts were not modified in transit. It is not proof of delivery.
"Delivered" needs its own evidence. When sending through Amazon SES with event publishing set up, a Delivery event records the time Amazon SES delivered the email to the recipient's mail server, the recipients, the smtpResponse from the remote server, the sending host name, and the remote server's IP address. It shows the receiving server accepted the message. It does not show that a person read it. Store these event records in the locked bucket and include them in the signed manifest.
Verifying years later
The routine we would document:
- Retrieve the object version and recompute its SHA-256. Compare with the stored checksum and with the hash in the signed manifest.
- Check the signature. With a signing key, verify with the exported public key outside AWS, or call Verify. With an HMAC key, call VerifyMac.
- Check retention. Read the object's retention mode and retain-until date and any legal hold, and confirm the bucket still has Object Lock enabled.
- Check CloudTrail. Find the Sign or GenerateMac call and the PutObject event, and validate the CloudTrail digest files for that period.
- Check the timestamp. If an RFC 3161 token was stored, validate it against the authority's certificate.
Keep the public key, key ARN, algorithm name and manifest format with the archive, for the day the person who built it has left.
Which option to choose
- Need only confidentiality and an access log: SSE-KMS with a customer managed key, plus CloudTrail. Not an integrity proof.
- Need to detect tampering inside your own team and auditors: Object Lock compliance mode, S3 SHA-256 checksums, and KMS HMAC (GenerateMac and VerifyMac). Verification stays inside AWS.
- Need evidence a third party or court can check on its own: Object Lock compliance mode plus KMS asymmetric signing of a SHA-256 manifest (DIGEST), the public key exported and kept, CloudTrail data events on, and optionally an RFC 3161 timestamp. This is our default recommendation.
- Need protected backup copies of the archive: add AWS Backup Vault Lock in compliance mode as a second copy.
- Need to preserve material for a specific case: add a legal hold on the relevant object versions.
The same idea on other clouds
On Google Cloud, Cloud Storage Bucket Lock makes a locked retention policy irreversible: objects cannot be deleted or replaced until they reach the age in the policy. Cloud Key Management Service (Cloud KMS) asymmetric keys sign a digest you compute, and the public key verifies the signature outside Google Cloud,. On Microsoft Azure, immutable storage for Blob Storage offers time-based retention policies and legal holds, and a locked time-based policy cannot be deleted; Azure Key Vault supports sign and verify on a hash you compute, with EC and RSA keys. On Oracle Cloud Infrastructure (OCI), Object Storage retention rules can be locked after a mandatory 14‑day delay, and not even a tenancy administrator or Oracle Support can delete a locked rule; OCI Vault supports digital signing and verification with RSA and ECDSA keys, and the public key can be downloaded. One difference to plan for: OCI retention rules cannot be used on a bucket with versioning enabled.
Our team designs and operates these archives and tests the verification routine, not only the storage. Scope is discussed during scoping.
Sources
- AWS: Locking objects with S3 Object Lock
- AWS: Configuring S3 Object Lock
- AWS: Retaining multiple versions of objects with S3 Versioning
- AWS: Configuring MFA delete
- AWS Backup: Vault Lock
- AWS KMS: HMAC keys in AWS KMS
- AWS KMS API: GenerateMac
- AWS KMS API: Sign
- AWS KMS: Key spec reference
- Amazon S3: Using server-side encryption with AWS KMS keys (SSE-KMS)
- Amazon S3: Checking object integrity
- AWS KMS: Logging AWS KMS API calls with AWS CloudTrail
- Amazon S3: Enabling CloudTrail event logging for S3 buckets and objects
- AWS CloudTrail: Validating log file integrity
- IETF: RFC 3161, Time-Stamp Protocol (TSP)
- Amazon SES: Deliver to S3 bucket action
- Amazon SES: Event data published to Amazon SNS
- Amazon SES: Authenticating email with DKIM
- Microsoft Learn: Journaling in Exchange Online
- Google Cloud: Bucket Lock
- Google Cloud: Create and validate digital signatures (Cloud KMS)
- Microsoft Learn: Immutable storage for Azure Blob Storage
- Microsoft Learn: Azure Key Vault key types, algorithms and operations
- Oracle: Object Storage retention rules
- Oracle: Key Management (OCI Vault) concepts
This article is general information, not legal advice. It reflects AWS, Microsoft, Google Cloud and Oracle documentation as read on November 8, 2026; features and limits change, so confirm current behavior before you build. Regulatory recordkeeping requirements depend on the rules that apply to your firm and should be reviewed with your counsel and compliance officer. AWS publishes a Cohasset Associates assessment of S3 Object Lock, and that assessment does not make any specific design compliant. Product and company names are trademarks of their owners and are named here as experience, not partnership. Last reviewed .
Keep reading
Next · RegulationSEC Regulation S-P Amendments: A Practical Checklist for Investment Advisers and Broker-DealersSmaller entities had to comply with the amended Regulation S-P by June 3, 2026; larger entities by December 3, 2025. Here is what examiners will look for, and how to check your firm today.7 min read- Penetration Testing Explained for Executives: Scope, Reports and How Often to Test8 min
- Ransomware Readiness and Incident Response: A Checklist Based on the CISA #StopRansomware Guide9 min
Need help with this?
Cloud cost review and management, without compromising on quality or security.
Cloud Management