SOC 2 audit log retention evidence is the proof that the logs your control mentions are still there for the window that control names. The window is whatever the policy says. Teams often write one year so a Type II period is covered. Some write 90 days. The evidence has to match the number in the policy, for each log source in scope, and it has to show that a normal application role cannot delete the archive to make the window shorter. A CloudWatch retention setting on a hot log group is not that proof. The archive is.
Rutagon builds the collector that reads the trail, the bucket, and a sample object, and writes a file the GRC platform can point at when the auditor asks. We do not decide that the control is met. We produce the configuration and the object that the control owner can compare to the policy. NIST SP 800-53 AU-11 is the retention control many of these policies echo. The AWS-specific mechanics are in CloudTrail log file validation and in S3 Object Lock.
How SOC 2 audit log retention evidence is assembled
The collector starts from an inventory of log sources the control owner marked in scope. For an AWS organization that list usually includes the organization CloudTrail, VPC flow logs where the control claims network audit, and the application log groups that the policy named. Each source has a required retention in days, copied from the policy, not invented by the job. A source with no required number is listed as unscoped. We do not silently assume 365.
For CloudTrail the fields are concrete. Is there an organization trail. Is it multi-region. Is log file validation enabled. Which bucket receives the logs. Is that bucket the one you think is the archive, or a second trail someone created into a bucket with a lifecycle rule that expires objects at 90 days. A trail that looks enabled in one account and is not the organization trail will not show management events from the rest of the organization. The CloudTrail evidence pipeline is the ongoing delivery into that bucket. This article is the retention proof on top of delivery: the objects are still there at the far end of the window.
The bucket is the archive. We read Object Lock configuration: whether it is on, whether the default retention is governance or compliance mode, and the default retention days. Compliance mode means nobody, including the root user of the account, can shorten or delete the object until the retention date. Governance mode can be overridden by a principal with the bypass permission. Both can be valid. They are not the same evidence. If the control says logs cannot be altered or deleted during the window, governance mode with a broad bypass role is a gap, and the collector lists every principal allowed s3:BypassGovernanceRetention and s3:DeleteObject on the archive. Object Lock for the CloudTrail archive is the configuration we put in place. The evidence file is the read-back of that configuration plus a sample.
CloudWatch Logs is the hot store. A log group with retentionInDays of 30 will expire events in the console view after a month. That is fine when the same events were delivered to the archive and the archive holds the window. It is a gap when the control's only copy is the log group. The collector records both numbers side by side so a 30-day hot retention is not reported as a 30-day archive. CloudWatch log retention cost explains why the hot store is short. Cost is why you do not keep a year in the log group. It is not a reason to skip the archive.
source: organization-cloudtrail
required_days: 365
trail_multi_region: true
log_file_validation: true
archive_bucket: cloudtrail-archive
object_lock_mode: compliance
object_lock_days: 400
hot_store_days: 30
sample_object_age_days: 370
sample_locked_until: after the required window
delete_principals_on_archive: none
gap: none The sample object is the part a screenshot of the trail page does not provide. We select an object whose last-modified time is older than the start of the required window and newer than a small buffer, and we read its Object Lock retention. If no such object exists, the gap is archive_shorter_than_window, regardless of what the console says the retention setting is. Settings describe intent. The object describes history. A bucket created last month cannot evidence a year of logs, and the sample makes that obvious.
Four hundred days of lock against a 365-day control is deliberate slack for late delivery and for the digest files log file validation writes. The number is an example. The rule is: lock duration at least the control window, mode matching the control's language about deletion, and a sample object that is actually that old.
Gaps the file is supposed to show
VPC flow logs are a common gap. The control says network connections are logged and retained with the other audit logs. The flow log subscription writes to a log group that expires at 14 or 30 days, and nothing copies it to the locked bucket. The collector marks the source hot_only. Fixing it is a delivery into the archive, then a sample, not a sentence in the policy. VPC flow logs as SOC 2 evidence is that delivery. Retention evidence without delivery is an empty bucket with a good lock configuration.
Application logs that stay on disk on an instance are out of the archive by definition. If the policy names them, the row says not_shipped until an agent writes them to the same class of store. We do not estimate retention from "the instance has not been rebuilt." Instance disk is not a retention control.
A lifecycle rule that expires current object versions at 90 days will win against a narrative that says one year, unless Object Lock is actually retaining the versions. We read the lifecycle rules and the lock together. A rule that aborts incomplete multipart uploads is housekeeping. A rule that expires the CloudTrail prefix is the gap. The evidence row quotes the prefix and the expiration days.
Digest validation belongs in the same file. Log file validation tells you whether the log files you still have match what CloudTrail wrote. Retention tells you the files are still there. A year of objects that fail validation is a different finding from a missing year. We run validation for the sample period and store the result next to the sample key. A failure is a gap named validation_failed, with the digest time. We do not average it into a pass.
The GRC platform receives the summary: source, required days, observed archive days, lock mode, gap or no gap, collection time. The JSON in the bucket is the detail. Regenerating it the week of the audit is the point. A PDF exported in January does not describe the lifecycle rule someone added in June. Evidence freshness is the clock. Log retention evidence goes stale on the same schedule as the other configuration exports, because the setting can change.
What this file is not
It is not an attestation. It does not say the company passed an exam. It says, on a date, these sources had these settings, this object was this old, and these principals could delete or bypass. The control owner uses that to answer the request. If the policy and the file disagree, the remediation is a longer lock, a delivery that was missing, or an honest change to the policy. We will not edit the required-days field so the gap disappears.
Access to the archive bucket is itself an entitlement. The principals allowed to read it are a small list, reviewed with the rest of privileged access. A collector role that can read configuration and write the evidence object does not need to be able to change the lock. We split those. The evidence role is read-only on the archive. The configuration role is the one used when we change retention, through Terraform, with the change recorded beside the other infrastructure evidence.
Rutagon's deliverable is the inventory, the collector, the sample-object check, the principal list for delete and bypass, and the summary the GRC platform links to. The trail and the bucket remain the systems of record. The file is how you show the window without a live console walkthrough.
Frequently Asked Questions
Is CloudWatch retention the same as audit log retention?
CloudWatch retentionInDays is the hot store. It is often 30 days because a year of log groups is expensive and slow to query. The archive is the bucket the trail writes to, with Object Lock covering the control window. The evidence file shows both numbers so the hot store is not offered as the archive.
What does the sample object prove?
It proves that at least one log object older than the start of the required window still exists and carries a lock retention that covers the control. A retention setting with no object that old means the archive does not yet have the history the policy claims. The gap is recorded as a short archive.
What is the difference between governance and compliance mode?
Compliance mode blocks deletion and shortening of the retention for everyone until the retain-until date. Governance mode allows a principal with bypass permission to override it. The collector lists those principals. A control that says logs cannot be deleted during the window needs a mode and a principal list that match that sentence.
How do flow logs and application logs fit?
They are separate sources on the inventory. A flow log that only lives in a short-lived log group is hot_only. An application log that only lives on instance disk is not_shipped. Each stays a gap until a copy lands in the locked archive and a sample object ages into the window.
Does this file mean the SOC 2 exam is done?
It is evidence for the retention part of the logging control, regenerated from the live configuration. It is not an attestation and it does not cover access reviews, change management, or the rest of the exam. The auditor compares it to the policy you actually wrote.
Ask for an evidence diagnostic of log sources, their configured retention, and whether an object from the start of the window is still locked. Contact Rutagon at rutagon.com/contact, 907-841-8407, or contact@rutagon.com.