Linux Security / Intermediate: service, policy, and lifecycle boundaries / Lesson 11
Use logs as bounded security evidence
Preserve source context and denial categories without logging secrets or treating missing events as success.
On this page
Lesson goals
- Distinguish structured source fields from free-form message interpretation.
- Design useful diagnostic records and retain unknown causes.
Choose the security question before collecting detail
A report worker may fail because of application validation, DAC, service filesystem restrictions, mandatory policy, or a dependency. A generic permission denied message does not uniquely identify the layer. Define the operation, resource category, trusted process context, and expected result before interpreting diagnostics. Logs support investigation only within their source visibility, retention, and reliability. This course uses invented records and reads no journal, audit log, process metadata, or host configuration. It neither enables auditing nor changes collection settings. The goal is precise use of evidence rather than maximum payload collection.
Retain explicit known and unknown denial categories
The first program groups declared classroom denial facts and keeps unknown causes visible. It does not infer a real kernel cause from human text. Actual systemd journal fields have documented meanings, and MESSAGE is human-readable content rather than a stable metadata parser target. Fields supplied by applications and fields added by the logging system have different trust context. Even trusted collection metadata does not prove every application claim is true. Preserve source identifiers and the method used to assign a category, including whether it came from reviewed diagnostics or only a hypothesis.
events = [{"id":"e1","layer":"dac"}, {"id":"e2","layer":"mandatory"}, {"id":"e3","layer":"unknown"}]
groups = {layer:[e["id"] for e in events if e["layer"] == layer] for layer in ("dac", "mandatory", "unknown")}
assert groups["dac"] == ["e1"]
assert groups["mandatory"] == ["e2"]
assert groups["unknown"] == ["e3"]
print("known denial layers and uncertainty remain separate")
known denial layers and uncertainty remain separate
The complete program organizes three invented dictionaries. It reads no journal or audit record and validates no real denial source. The categories are exercise data rather than exact Linux error messages.
Use minimal diagnostic projections
A diagnostic record should preserve the operation, outcome, case id, and relevant nonsecret context while excluding credentials and private payloads. The second program uses an allowlist to exclude an inert classroom marker. It is not a guarantee that every logging path is safe. Review nested objects, exception messages, environment dumps, and third-party libraries in an actual approved design. Access, retention, transport, and integrity of logs are separate controls. A debugging failure should not become a reason to copy complete account, request, or configuration data into a broadly visible record.
event = {"operation":"write-summary", "result":"denied", "case":"lab-3", "credentialMarker":"PUBLIC-INERT-MARKER"}
allowed = {"operation", "result", "case"}
diagnostic = {k:v for k,v in event.items() if k in allowed}
assert set(diagnostic) == allowed
assert "credentialMarker" not in diagnostic
assert "PUBLIC-INERT-MARKER" not in str(diagnostic)
print("diagnostic projection excludes the inert marker")
diagnostic projection excludes the inert marker
The complete program uses public invented strings and writes no log. It reads or transmits no credential and proves only this projection’s field selection. Real logging coverage, privacy, and storage protections remain unverified.
Treat missing logs as a coverage question
An absent event can reflect retention, disabled collection, rate limiting, buffering, a different source, or no relevant action. It is not automatic evidence of successful enforcement or deliberate deletion. Time semantics and source clock quality also matter when correlating events. Review the approved logging architecture and known gaps before drawing frequency or absence conclusions. A log label naming a uid, unit, or executable needs its documented source context and is not by itself a human attribution. The course performs no live collection, privileged audit configuration, or forensic acquisition to resolve those questions.
Connect diagnostics to actual protected effects
An approved test should compare the public outcome, protected state, and relevant diagnostic category for a controlled legitimate and denied case. Verify that a refusal creates no unintended output or notification under the contract. Keep logs as supporting evidence rather than the sole proof that no mutation occurred. Record source, version, time basis, and unexecuted boundaries. The local examples check data organization and field selection only. They establish no host detection coverage, alert quality, policy enforcement, or incident conclusion. Clear evidence boundaries make the next diagnostic action more useful and less intrusive.
Common errors and fixes
A generic message identifies the denial layer
- Why it happens
- Human text is treated as a unique causal signal.
- How to fix it
- Use documented structured context and corroborating state.
- Prevent it next time
- Keep unknown causes visible until supported.
Missing logs prove no event occurred
- Why it happens
- Collection coverage and retention are ignored.
- How to fix it
- Describe the supplied source and its gaps.
- Prevent it next time
- Review absence claims against logging architecture.
Debug output includes complete credentials
- Why it happens
- Convenience bypasses field and audience review.
- How to fix it
- Use minimal reviewed projections and inert test markers.
- Prevent it next time
- Validate relevant diagnostic paths without real secrets.
Check your understanding
1. The event is labeled unknown. Should it be counted as an AppArmor denial?
Show worked solution
No. Preserve unknown until supported source context identifies the layer. A nearby policy message may be related but does not automatically explain this event. The local grouping model is deliberately based on declared facts and performs no host inspection.
2. Why compare protected state as well as a denial log?
Show worked solution
A log can be missing, misleading, or written after an unintended mutation. The contract needs the actual permitted or unchanged state and relevant side effects. In a separate authorized environment, corroborate the diagnostic with the operation’s observed outcome; do not infer enforcement solely from a message string.
Key takeaways
- Logs have source, coverage, and interpretation limits.
- Structured context and state support causal diagnosis.
- Minimal projections reduce unnecessary disclosure.