Log centralization and integrity verification is implemented
Why it matters
PCI-DSS 4.0 Req 10.3 requires that audit logs are protected from destruction and unauthorized modifications; Req 10.4 mandates that log content is reviewed at least once daily. Logs stored only on the same server they monitor can be deleted by an attacker to cover their tracks. CWE-778 (Insufficient Logging) combined with writable log storage means a compromised host can silence its own forensic record. NIST AU-9 requires protection of audit information. S3 Object Lock (WORM) combined with KMS encryption satisfies Req 10.3 — an attacker with application-level access cannot delete an Object Lock-protected log archive.
Severity rationale
Medium because logs stored in mutable, non-centralized locations can be deleted by a compromised component, eliminating forensic evidence and violating PCI-DSS 4.0 Req 10.3's tamper-evidence requirement.
Remediation
Forward logs from at least two sources (application, database) to a centralized log group, then export to an S3 bucket with Object Lock enabled so logs are write-once and cannot be deleted. Encrypt the archive with a KMS key that is managed separately from the CDE application credentials.
resource "aws_s3_bucket_object_lock_configuration" "log_archive" {
bucket = aws_s3_bucket.log_archive.id
rule {
default_retention {
mode = "GOVERNANCE"
days = 365
}
}
}
Add a CloudWatch Subscription Filter to stream CDE log groups into the central archive log group. Document the centralization topology in docs/pci-compliance.md — a QSA will ask to see how Req 10.3 tamper protection is implemented.
Detection
-
ID:
log-centralization -
Severity:
medium -
What to look for: Count all log sources in the project (application logs, database logs, infrastructure logs, access logs). For each source, check whether logs are forwarded to a central location. Count the number of integrity verification mechanisms: HMAC/hash signing, immutable storage (S3 Object Lock, WORM), checksums, or audit trail services. Enumerate all log stream/subscription/forwarding configurations.
-
Pass criteria: At least 2 log sources are forwarded to a central location (CloudWatch, ELK, Splunk, Datadog, or equivalent). At least 1 log integrity verification mechanism exists (cryptographic signing, immutable storage with object lock, or checksum validation). Report: "X log sources centralized, Y integrity verification mechanisms."
-
Fail criteria: Logs stored in isolated locations without centralization (each service logs locally), or centralized but no integrity verification (0 signing, hashing, or immutable storage configs).
-
Skip (N/A) when: Payment processing fully delegated to third-party (no local CDE logs generated, no infrastructure logging needed).
-
Detail on fail: Describe the centralization gap. Example:
"Application logs written to local stdout only. 0 of 3 log sources forwarded to central location. No integrity verification."or"2 log sources centralized to CloudWatch but 0 integrity verification mechanisms (no HMAC, no immutable storage)." -
Remediation: Implement log centralization with integrity checks. Using AWS CloudWatch + S3 + Athena:
# Central log group resource "aws_cloudwatch_log_group" "central_audit" { name = "/audit/central" retention_in_days = 365 tags = { Name = "central-audit-logs" } } # Log stream from multiple sources resource "aws_cloudwatch_log_stream" "cde_db" { name = "cde-database" log_group_name = aws_cloudwatch_log_group.central_audit.name } # S3 export for immutable storage resource "aws_s3_bucket" "log_archive" { bucket = "audit-log-archive-${data.aws_caller_identity.current.account_id}" tags = { Name = "immutable-log-archive" } } # Prevent object deletion resource "aws_s3_bucket_object_lock_configuration" "log_archive" { bucket = aws_s3_bucket.log_archive.id rule { default_retention { mode = "GOVERNANCE" days = 2555 # ~7 years } } } # KMS key for encryption resource "aws_kms_key" "log_key" { description = "Key for log encryption" deletion_window_in_days = 10 enable_key_rotation = true } resource "aws_s3_bucket_server_side_encryption_configuration" "log_archive" { bucket = aws_s3_bucket.log_archive.id rule { apply_server_side_encryption_by_default { sse_algorithm = "aws:kms" kms_master_key_id = aws_kms_key.log_key.arn } } }For log integrity verification, use a log signing service:
// src/app/api/audit-log/route.ts import crypto from 'crypto'; export async function POST(req) { const { event } = await req.json(); // Create HMAC signature for integrity const hmac = crypto .createHmac('sha256', process.env.LOG_SIGNING_KEY) .update(JSON.stringify(event)) .digest('hex'); const signedLog = { ...event, signature: `sha256:${hmac}`, timestamp: new Date().toISOString(), }; // Store in database and export to immutable storage await logCentralService.store(signedLog); return new Response(JSON.stringify({ signed: true })); }
External references
- pci-dss:4.0 · Req 10.3 — Audit logs are protected from destruction and unauthorized modifications
- pci-dss:4.0 · Req 10.4 — Audit logs are reviewed to identify anomalies or suspicious activity
- nist:rev5 · AU-9 — Protection of Audit Information
- cwe · CWE-778 — Insufficient Logging
Taxons
History
- 2026-04-18·v1.0.0·Initial import from ecommerce-pci·automated