Architecture
How infraudit is designed internally.
Overview
infraudit follows a modular architecture where each security check is a self-contained unit that implements a common interface. The CLI layer (cobra) handles user interaction, while the check engine handles discovery, execution, and result collection.
main.go → cmd.Execute() → cobra routing → check engine → individual checks
↓
report formatter → console / JSON / YAML
Project Structure
infraudit/
├── cmd/
│ ├── root.go # Root command, flags, version
│ ├── audit.go # audit subcommand — runs checks
│ └── list.go # list subcommand — shows available checks
├── internal/
│ ├── version/ # Version constants
│ ├── check/ # Check interface, Result, Registry
│ ├── checks/
│ │ ├── auth/ # SSH, users, sudoers, UIDs
│ │ ├── pam/ # Password quality, lockout, PAM config
│ │ ├── network/ # Firewall, ports, DNS, SNMP
│ │ ├── services/ # Daemons, NTP, MTA, desktop
│ │ ├── filesystem/ # SUID, permissions, partitions, /tmp
│ │ ├── logging/ # Syslog, auditd, AIDE, log rotation
│ │ ├── packages/ # Updates, repos, kernel
│ │ ├── hardening/ # Kernel params, modules, ASLR
│ │ ├── boot/ # GRUB, Secure Boot, SELinux/AppArmor
│ │ ├── cron/ # Cron/at permissions, job review
│ │ ├── crypto/ # TLS, certificates, ciphers, FIPS
│ │ ├── secrets/ # Exposed credentials, history
│ │ ├── container/ # Docker/Podman security
│ │ ├── rlimit/ # Resource limits, disk, inodes
│ │ ├── nfs/ # NFS exports, Samba, rpcbind
│ │ ├── malware/ # Rootkit detection, antimalware
│ │ └── backup/ # Backup schedule, encryption
│ ├── report/ # Output formatting (console, JSON, YAML, HTML, SARIF)
│ ├── osinfo/ # OS detection (family, distro, pkg manager, init system)
│ ├── compliance/ # CIS Benchmark control mappings
│ ├── plugin/ # YAML-based custom check loader
│ ├── policy/ # Policy-as-code enforcement
│ └── remote/ # SSH remote scanning
└── main.go # Entry point
Check Interface
Every check implements the Check interface:
type Check interface {
ID() string // e.g. "AUTH-001"
Name() string // e.g. "SSH root login disabled"
Category() string // e.g. "auth"
Severity() Severity // CRITICAL, HIGH, MEDIUM, LOW, INFO
Description() string // What this check validates
Run() Result // Execute and return result
}
Result Model
type Result struct {
Status Status // PASS, WARN, FAIL, ERROR, SKIPPED
Message string // What was found
Remediation string // How to fix it
Details map[string]string // Additional context
}
Platform-Aware Checks
Checks can optionally implement platform interfaces to declare compatibility:
type OSAware interface {
SupportedOS() []string // ["debian", "redhat", "suse", "alpine", "arch"]
}
type InitAware interface {
RequiredInit() string // "systemd", "openrc", "sysvinit"
}
type PkgAware interface {
RequiredPkgManager() string // "apt", "dnf", "yum", "apk", "zypper", "pacman"
}
If a check implements these interfaces and the detected OS doesn't match, the check returns SKIPPED instead of running. Skipped checks are excluded from scoring. The OS is detected at startup via /etc/os-release by the osinfo package.
Check Registry
Checks self-register via init() functions. The registry supports:
- Auto-discovery of all registered checks
- Filtering by category
- Filtering by severity
- Skip list from configuration
- Profile-based selection
Execution Flow
1. User runs: sudo infraudit audit --category auth,network
2. Cobra parses flags, calls audit handler
3. OS detected via /etc/os-release (family, pkg manager, init system)
4. Registry filters checks by requested categories
5. Engine runs each check (or skips if OS-incompatible)
6. Reporter formats output (console/JSON/YAML/HTML/SARIF)
7. Exit code set based on highest severity found
Dependencies
| Package | Purpose |
|---|---|
github.com/spf13/cobra | CLI framework |
Command Execution
All external commands are executed via check.RunCmd(), which wraps exec.CommandContext with a timeout (DefaultCmdTimeout = 30s, LongCmdTimeout = 60s for filesystem scans). This prevents indefinite blocking on hung commands or unresponsive mounts.
Build & Tooling
| File | Purpose |
|---|---|
Makefile | Build, test, lint, release, cover, docker targets |
Dockerfile | Multi-stage build (golang:1.25-alpine → alpine:3.21) |
.golangci.yml | Linter config: gosec, errcheck, staticcheck, gocritic |
.github/workflows/ci.yml | CI: test, lint, race detector, release with SBOM and cosign signing |
infraudit deliberately minimizes dependencies. Checks use only the Go standard library to read files, parse configs, and execute system commands.