74 lines
3.1 KiB
YAML
74 lines
3.1 KiB
YAML
---
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
# TEMPLATE: File Permission / Ownership Check
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
#
|
|
# Uses ansible.builtin.stat — no shell command needed.
|
|
# Prefer this over shelling out to stat(1) for file attribute checks.
|
|
# The stat module returns a structured dict with typed values, which
|
|
# makes the 'passed' expression straightforward and readable.
|
|
#
|
|
# Useful stat attributes:
|
|
# stat.exists — bool: file is present
|
|
# stat.mode — string: octal permissions, e.g. '0640'
|
|
# stat.pw_name — string: owning user name, e.g. 'root'
|
|
# stat.gr_name — string: owning group name, e.g. 'shadow'
|
|
# stat.size — int: file size in bytes
|
|
# stat.isreg — bool: is a regular file
|
|
# stat.isdir — bool: is a directory
|
|
# stat.islnk — bool: is a symlink
|
|
#
|
|
# Common 'passed' expression patterns:
|
|
#
|
|
# # File exists with exact owner/group/mode:
|
|
# 'passed': (
|
|
# _stat.stat.exists and
|
|
# _stat.stat.pw_name == 'root' and
|
|
# _stat.stat.gr_name == 'root' and
|
|
# _stat.stat.mode == '0640'
|
|
# ),
|
|
#
|
|
# # File must NOT exist:
|
|
# 'passed': not _stat.stat.exists,
|
|
#
|
|
# # File must be a regular file (not a symlink) with tight permissions:
|
|
# 'passed': (
|
|
# _stat.stat.exists and
|
|
# _stat.stat.isreg and
|
|
# not _stat.stat.islnk and
|
|
# _stat.stat.mode in ['0400', '0440', '0600']
|
|
# ),
|
|
#
|
|
# ══════════════════════════════════════════════════════════════════════
|
|
|
|
# ── SUITE_ID: SHORT_DESCRIPTION ─────────────────────────────────────
|
|
|
|
- block:
|
|
- name: "Gather: Stat /path/to/file"
|
|
ansible.builtin.stat:
|
|
path: /path/to/file
|
|
register: _stat
|
|
|
|
- name: "Evaluate: TEST_ID"
|
|
ansible.builtin.set_fact:
|
|
test_results: "{{ test_results + [{
|
|
'test_id': 'TEST_ID',
|
|
'category': 'FR_NUMBER — CATEGORY_NAME',
|
|
'requirement': 'SR X.Y — REQUIREMENT_NAME',
|
|
'description': '/path/to/file shall be owned by root:root with mode 0640',
|
|
'passed': (
|
|
_stat.stat.exists and
|
|
_stat.stat.pw_name == 'root' and
|
|
_stat.stat.gr_name == 'root' and
|
|
_stat.stat.mode == '0640'
|
|
),
|
|
'expected': 'root:root 0640',
|
|
'actual': (
|
|
(_stat.stat.pw_name + ':' + _stat.stat.gr_name + ' ' + _stat.stat.mode)
|
|
if _stat.stat.exists else 'FILE NOT FOUND'
|
|
),
|
|
'severity': 'high',
|
|
'remediation': 'chown root:root /path/to/file && chmod 0640 /path/to/file'
|
|
}] }}"
|
|
ignore_errors: yes
|