audit

package
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Mar 23, 2026 License: Apache-2.0 Imports: 18 Imported by: 0

Documentation

Overview

Package audit provides security audit functionality for OPNsense configurations against industry-standard compliance frameworks through a plugin-based architecture.

Package audit provides security audit functionality for OPNsense configurations against industry-standard compliance frameworks through a plugin-based architecture.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrModeConfigNil is returned when the mode configuration is nil.
	ErrModeConfigNil = errors.New("mode config cannot be nil")
	// ErrUnsupportedMode is returned when an unsupported report mode is specified.
	ErrUnsupportedMode = errors.New("unsupported report mode")
	// ErrPluginNotFound is returned when a requested compliance plugin cannot be found.
	ErrPluginNotFound = errors.New("plugin not found")
	// ErrConfigurationNil is returned when the OPNsense configuration is nil.
	ErrConfigurationNil = errors.New("configuration cannot be nil")
	// ErrDuplicatePlugin is returned when the same plugin appears more than once in the selection.
	ErrDuplicatePlugin = errors.New("duplicate plugin in selection")
)

Static errors for better error handling.

Functions

func GetGlobalPlugin

func GetGlobalPlugin(name string) (compliance.Plugin, error)

GetGlobalPlugin retrieves a plugin from the global registry.

func ListGlobalPlugins

func ListGlobalPlugins() []string

ListGlobalPlugins returns all plugins in the global registry.

func RegisterGlobalPlugin

func RegisterGlobalPlugin(p compliance.Plugin) error

RegisterGlobalPlugin registers a compliance plugin with the global singleton registry. All calls to RegisterGlobalPlugin should occur during sequential application startup before the registry is accessed concurrently for reads. While the underlying PluginRegistry.RegisterPlugin is mutex-protected and technically safe to call concurrently, the application's intended pattern is register-at-startup, read-during-operation.

Note: PluginManager.InitializePlugins() populates the manager's own PluginRegistry, not this global singleton. Callers that need plugins in the global registry must call RegisterGlobalPlugin() directly.

Types

type AttackSurface

type AttackSurface struct {
	Type            string   `json:"type"`
	Ports           []int    `json:"ports"`
	Services        []string `json:"services"`
	Vulnerabilities []string `json:"vulnerabilities"`
}

AttackSurface represents attack surface information for red team findings.

type ComplianceResult

type ComplianceResult struct {
	Findings       []compliance.Finding            `json:"findings"`
	PluginFindings map[string][]compliance.Finding `json:"pluginFindings"`
	Compliance     map[string]map[string]bool      `json:"compliance"`
	Summary        *ComplianceSummary              `json:"summary"`
	PluginInfo     map[string]PluginInfo           `json:"pluginInfo"`
}

ComplianceResult represents the complete result of compliance checks.

type ComplianceSummary

type ComplianceSummary struct {
	TotalFindings    int                         `json:"totalFindings"`
	CriticalFindings int                         `json:"criticalFindings"`
	HighFindings     int                         `json:"highFindings"`
	MediumFindings   int                         `json:"mediumFindings"`
	LowFindings      int                         `json:"lowFindings"`
	PluginCount      int                         `json:"pluginCount"`
	Compliance       map[string]PluginCompliance `json:"compliance"`
}

ComplianceSummary provides summary statistics.

type Finding

type Finding struct {
	analysis.Finding

	AttackSurface *AttackSurface `json:"attackSurface,omitempty"`
	ExploitNotes  string         `json:"exploitNotes,omitempty"`
	Control       string         `json:"control,omitempty"`
}

Finding represents a security finding or audit result. It embeds analysis.Finding for the common fields (Title, Severity, Description, Recommendation, Component, Tags, etc.) and adds audit-specific extensions.

type LoadResult added in v1.3.0

type LoadResult struct {
	Loaded   int
	Failures []PluginLoadError
}

LoadResult summarises the outcome of a LoadDynamicPlugins call, reporting how many plugins loaded successfully, how many failed, and the individual failure details. The zero value represents "no dynamic plugins attempted".

func (LoadResult) Failed added in v1.3.0

func (r LoadResult) Failed() int

Failed returns the number of plugins that failed to load.

type ModeConfig

type ModeConfig struct {
	Mode            ReportMode
	Comprehensive   bool
	SelectedPlugins []string
	TemplateDir     string
}

ModeConfig holds configuration options for report generation.

type ModeController

type ModeController struct {
	// contains filtered or unexported fields
}

ModeController manages the generation of different types of audit reports based on the selected mode and configuration.

func NewModeController

func NewModeController(registry *PluginRegistry, logger *logging.Logger) *ModeController

NewModeController creates a new mode controller with the given plugin registry and logger.

func (*ModeController) GenerateReport

func (mc *ModeController) GenerateReport(
	ctx context.Context,
	device *common.CommonDevice,
	config *ModeConfig,
) (*Report, error)

GenerateReport generates an audit report based on the specified mode and configuration.

func (*ModeController) ValidateModeConfig

func (mc *ModeController) ValidateModeConfig(config *ModeConfig) error

ValidateModeConfig validates the mode configuration.

type Options added in v1.3.0

type Options struct {
	// AuditMode specifies the audit reporting mode (blue, red).
	AuditMode string

	// SelectedPlugins specifies which compliance plugins to run.
	SelectedPlugins []string

	// PluginDir is the directory from which dynamic .so plugins are loaded.
	// When non-empty, LoadDynamicPlugins scans this path during InitializePlugins.
	PluginDir string

	// ExplicitPluginDir indicates that PluginDir was explicitly configured by
	// the user (via CLI flag). When true and the directory does not exist,
	// LoadDynamicPlugins returns an error instead of silently continuing.
	ExplicitPluginDir bool
}

Options contains configuration for audit report generation. Options is separate from converter.Options because audit concerns (mode selection, compliance plugins) are orthogonal to conversion concerns (format, theme, wrapping).

type PluginCompliance

type PluginCompliance struct {
	Compliant    int `json:"compliant"`
	NonCompliant int `json:"nonCompliant"`
	Total        int `json:"total"`
}

PluginCompliance represents compliance statistics for a single plugin.

type PluginInfo

type PluginInfo struct {
	Name        string               `json:"name"`
	Version     string               `json:"version"`
	Description string               `json:"description"`
	Controls    []compliance.Control `json:"controls"`
}

PluginInfo contains metadata about a plugin.

type PluginLoadError added in v1.3.0

type PluginLoadError struct {
	Name string
	Err  error
}

PluginLoadError records a single dynamic plugin that failed to load, capturing the .so filename and the underlying error. It implements the error interface for use with errors.Join.

func (PluginLoadError) Error added in v1.3.0

func (f PluginLoadError) Error() string

Error returns a human-readable description of the load failure.

func (PluginLoadError) Unwrap added in v1.3.0

func (f PluginLoadError) Unwrap() error

Unwrap returns the underlying error that caused the plugin load to fail. This allows consumers to use errors.Is and errors.As with PluginLoadError, including when these errors are combined via errors.Join.

type PluginManager

type PluginManager struct {
	// contains filtered or unexported fields
}

PluginManager manages the lifecycle of compliance plugins.

func NewPluginManager

func NewPluginManager(logger *logging.Logger) *PluginManager

NewPluginManager creates a new plugin manager.

func (*PluginManager) GetLoadResult added in v1.3.0

func (pm *PluginManager) GetLoadResult() LoadResult

GetLoadResult returns the result of the most recent LoadDynamicPlugins call performed during InitializePlugins. If no dynamic plugin directory was configured, or InitializePlugins has not been called, the zero-value LoadResult is returned. The Failures slice is copied so callers cannot mutate the manager's internal slice state; error values within each PluginLoadError are shared references.

func (*PluginManager) GetPluginControlInfo

func (pm *PluginManager) GetPluginControlInfo(pluginName, controlID string) (*compliance.Control, error)

GetPluginControlInfo returns detailed information about a specific control.

func (*PluginManager) GetPluginStatistics

func (pm *PluginManager) GetPluginStatistics() map[string]any

GetPluginStatistics returns statistics about plugin usage and plugin.

func (*PluginManager) GetRegistry

func (pm *PluginManager) GetRegistry() *PluginRegistry

GetRegistry returns the plugin registry.

func (*PluginManager) InitializePlugins

func (pm *PluginManager) InitializePlugins(ctx context.Context) error

InitializePlugins registers all built-in compliance plugins (STIG, SANS, Firewall) with the manager's own PluginRegistry. This method is the sequential initialization entrypoint and must be called during application startup before the manager's registry is used concurrently. All built-in plugin registration for this manager happens here, ensuring the manager's registry is fully populated before any concurrent audit operations begin. Callers must not invoke this method concurrently.

Dynamic plugin loading: if SetPluginDir was called before this method, dynamic .so plugins are loaded from the configured directory. Per-plugin load failures are non-fatal — they do NOT cause InitializePlugins to return an error. Callers must inspect GetLoadResult() after this method returns to detect and surface dynamic plugin load failures.

Note: this populates pm.registry only, not the global singleton returned by GetGlobalRegistry(). If plugins need to be available via the global registry, callers must use RegisterGlobalPlugin() separately.

func (*PluginManager) ListAvailablePlugins

func (pm *PluginManager) ListAvailablePlugins(ctx context.Context) []PluginInfo

ListAvailablePlugins returns information about all available plugins.

func (*PluginManager) RunComplianceAudit

func (pm *PluginManager) RunComplianceAudit(
	ctx context.Context,
	device *common.CommonDevice,
	pluginNames []string,
) (*ComplianceResult, error)

RunComplianceAudit runs compliance checks using specified plugins.

func (*PluginManager) SetPluginDir added in v1.3.0

func (pm *PluginManager) SetPluginDir(dir string, explicit bool)

SetPluginDir configures the directory from which dynamic .so plugins are loaded during InitializePlugins. The explicit flag controls the behavior when the directory does not exist: true means the user explicitly configured this path (returns an error), false means it is a default/optional path (logs at Debug and continues).

func (*PluginManager) ValidatePluginConfiguration

func (pm *PluginManager) ValidatePluginConfiguration(pluginName string) error

ValidatePluginConfiguration validates the configuration of a specific plugin.

type PluginRegistry

type PluginRegistry struct {
	// contains filtered or unexported fields
}

PluginRegistry manages the registration and retrieval of compliance plugins.

func GetGlobalRegistry added in v1.1.0

func GetGlobalRegistry() *PluginRegistry

GetGlobalRegistry returns the global plugin registry singleton, initializing it on first access via sync.Once. It is safe to call concurrently from multiple goroutines; the sync.Once guarantee ensures the initialization completes and its writes are visible before any caller receives the pointer. Subsequent calls return the same *PluginRegistry instance without further synchronization overhead.

func NewPluginRegistry

func NewPluginRegistry() *PluginRegistry

NewPluginRegistry creates a new plugin registry with the default plugin loader.

func (*PluginRegistry) GetPlugin

func (pr *PluginRegistry) GetPlugin(name string) (compliance.Plugin, error)

GetPlugin retrieves a plugin by name.

func (*PluginRegistry) ListPlugins

func (pr *PluginRegistry) ListPlugins() []string

ListPlugins returns all registered plugin names.

func (*PluginRegistry) LoadDynamicPlugins

func (pr *PluginRegistry) LoadDynamicPlugins(
	ctx context.Context,
	dir string,
	explicitDir bool,
	logger *logging.Logger,
) (LoadResult, error)

LoadDynamicPlugins loads .so plugins from the specified directory and registers them. When explicitDir is false, a missing directory is silently ignored (Debug log). When explicitDir is true, a missing directory returns an error because the user explicitly configured the path. A nil logger returns an error immediately. Per-plugin failures are collected in the returned LoadResult and aggregated into the returned error via errors.Join.

func (*PluginRegistry) RegisterPlugin

func (pr *PluginRegistry) RegisterPlugin(p compliance.Plugin) error

RegisterPlugin registers a compliance plugin.

func (*PluginRegistry) RunComplianceChecks

func (pr *PluginRegistry) RunComplianceChecks(
	device *common.CommonDevice,
	pluginNames []string,
	logger *logging.Logger,
) (*ComplianceResult, error)

RunComplianceChecks runs compliance checks for specified plugins. Each plugin's RunChecks call is wrapped in a panic recovery boundary so that a misbehaving (especially dynamically-loaded) plugin cannot crash the entire audit. Panicking plugins are logged and retained in the result with zero findings, ensuring downstream consumers can see they were requested and evaluated.

type Report

type Report struct {
	Mode          ReportMode                  `json:"mode"`
	Comprehensive bool                        `json:"comprehensive"`
	Configuration *common.CommonDevice        `json:"configuration"`
	Findings      []Finding                   `json:"findings"`
	Compliance    map[string]ComplianceResult `json:"compliance"`
	Metadata      map[string]any              `json:"metadata"`
}

Report represents a comprehensive audit report with findings and analysis.

func (*Report) TotalFindingsCount added in v1.3.0

func (r *Report) TotalFindingsCount() int

TotalFindingsCount returns the aggregate number of findings across both direct security findings (report.Findings) and per-plugin compliance findings (report.Compliance[*].Summary.TotalFindings). This ensures the top-level summary reflects the same totals as the per-plugin sections.

type ReportMode

type ReportMode string

ReportMode represents the different types of audit reports that can be generated.

const (
	// ModeBlue represents a defensive audit report with security findings and recommendations.
	ModeBlue ReportMode = "blue"
	// ModeRed represents an attacker-focused recon report highlighting attack surfaces.
	ModeRed ReportMode = "red"
)

Report mode constants that determine the perspective and focus of audit output.

func ParseReportMode

func ParseReportMode(s string) (ReportMode, error)

ParseReportMode parses a string into a ReportMode, returning an error if invalid.

func (ReportMode) String

func (rm ReportMode) String() string

String returns the string representation of the ReportMode.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL