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:

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

PackagePurpose
github.com/spf13/cobraCLI 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

FilePurpose
MakefileBuild, test, lint, release, cover, docker targets
DockerfileMulti-stage build (golang:1.25-alpine → alpine:3.21)
.golangci.ymlLinter config: gosec, errcheck, staticcheck, gocritic
.github/workflows/ci.ymlCI: 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.