Skip to content

Configuration Reference

Ryan edited this page Jul 18, 2026 · 1 revision

Configuration Reference

Exhaustive documentation of every configurable constant, enum value, regex pattern, per-backend option, and CLI flag in the Apotropaios framework.

Table of Contents


Runtime Configuration

Apotropaios reads built-in defaults from code constants in core/constants.py at import time, and additionally loads an optional INI-format configuration file at startup. Because a framework running as root that modifies kernel firewall rules must not act on a file that could be tampered with, every candidate file passes a trust gate before use: it must be owned by root or the current effective user and must not be group- or world-writable. Files failing the gate are skipped entirely with a warning -- never partially applied.

The search order is: /etc/apotropaios/apotropaios.conf (system-wide), then conf/apotropaios.conf under the framework base directory, then the copy shipped inside the package. The first trusted match wins. Setting precedence is: command line > configuration file > built-in defaults. The configuration file currently drives the console log level ([logging] log_level, applied only when --log-level is not passed) and the default firewall backend ([firewall] default_backend, applied only when --backend is not passed); remaining sections are parsed and reserved for framework use. The APOTROPAIOS_BASE_DIR environment variable overrides the framework base directory when it names an existing directory, relocating the data/ tree (logs, rules, backups) and the project-local configuration lookup without touching the installation; an invalid override emits a warning and falls back to the default.

Override at runtime via CLI flags:

Flag Overrides Default Example
--log-level LEVEL Console log verbosity warning --log-level trace
--backend NAME Active firewall backend auto-detect --backend firewalld
--interactive Operation mode CLI --interactive
--non-interactive Prompt behavior interactive --non-interactive

Security Constants

Defined in Security class (core/constants.py):

Constant Value Type Implication
UMASK 0o077 int New files/dirs have no group/world access. Set via os.umask() during init_security().
FILE_PERMS 0o600 int All created files: owner read/write only. Applied via os.chmod().
DIR_PERMS 0o700 int All created directories: owner-only access.
EXEC_PERMS 0o700 int Executable files: owner-only.
MAX_INPUT_LENGTH 4096 int sanitize_input() truncates beyond this. Prevents DoS via regex on long strings.
MAX_PATH_LENGTH 4096 int File path validation rejects paths exceeding this.
MAX_RULE_DESCRIPTION_LENGTH 256 int validate_description() rejects longer descriptions.
MAX_LOG_FILE_SIZE_BYTES 104,857,600 int 100MB. _SecureRotatingHandler triggers rotation at this threshold.
MAX_LOG_FILES_RETAINED 10 int Number of rotated log files kept. Oldest deleted on rotation.
LOCK_TIMEOUT_SECONDS 30 int FileLock.acquire() gives up after this many seconds. Raises LockTimeoutError.
LOCK_RETRY_INTERVAL 1 int Seconds between lock acquisition retry attempts.

Performance Constants

Defined in Performance class:

Constant Value Type Implication
SUBPROCESS_TIMEOUT 30 int Every subprocess.run() call times out after 30 seconds. Prevents hanging on stuck firewall commands (e.g., firewalld D-Bus hang).
EXPIRY_CHECK_INTERVAL 30 int ExpiryMonitor daemon thread wakes this often (seconds). TTL precision is ±30 seconds.
MAX_CONCURRENT_OPERATIONS 4 int ThreadPoolExecutor worker count for parallel_exec(). Used in backup export.
OPERATION_TIMEOUT_SECONDS 300 int 5 minutes. Overall operation timeout for long-running tasks.
BATCH_SIZE 50 int Rules per batch in bulk operations (import).

Backup Constants

Defined in Backup class:

Constant Value Implication
PREFIX apotropaios_backup Archive filename prefix. Full name: apotropaios_backup_<label>_<timestamp>.tar.gz
EXTENSION .tar.gz Archive format (gzip-compressed tar)
MANIFEST_FILE manifest.json Metadata file inside each archive. Contains: timestamp, version, label, backends, file checksums.
MAX_RETAINED 20 Maximum backup archives before pruning. _enforce_retention() deletes oldest.
INTEGRITY_ALGORITHM sha256 Algorithm for .sha256 sidecar files and .integrity files in immutable snapshots.

TTL Limits

Defined in TTLLimits class:

Constant Value Human-Readable
MIN_SECONDS 60 1 minute -- minimum temporary rule duration
MAX_SECONDS 2,592,000 30 days -- maximum temporary rule duration

validate_ttl() rejects values outside this range.


Error Codes

Defined as ErrorCode(IntEnum). Usable directly as sys.exit() arguments.

Code Name Category When Raised
0 SUCCESS General Operation completed successfully
1 GENERAL General Unspecified error (catch-all)
2 USAGE General Invalid CLI arguments, mutually exclusive flags
3 PERMISSION General Not running as root (euid != 0)
10 OS_UNSUPPORTED Detection OS not in SUPPORTED_OS list
11 FW_NOT_FOUND Detection No firewall binary found on PATH
12 FW_NOT_RUNNING Detection Firewall installed but systemd service not active
13 FW_INSTALL_FAIL Detection apt/dnf/pacman package installation failed
20 RULE_INVALID Rules Parameter validation failed (any of 27 validators)
21 RULE_EXISTS Rules Duplicate UUID already in index
22 RULE_NOT_FOUND Rules UUID not in index
23 RULE_APPLY_FAIL Rules Backend subprocess returned non-zero
24 RULE_REMOVE_FAIL Rules Backend failed to delete rule
25 RULE_IMPORT_FAIL Rules Import file parse error or validation failure
30 BACKUP_FAIL Backup Archive creation failed (disk space, permissions)
31 RESTORE_FAIL Backup Restore failed (checksum mismatch, path traversal)
32 BACKUP_NOT_FOUND Backup Specified archive file does not exist
40 VALIDATION_FAIL Security Input validation rejected parameter
41 INPUT_SANITIZE_FAIL Security sanitize_input() detected dangerous content
50 LOG_FAIL Logging Logger initialization failed (disk, permissions)
51 LOG_HANDLE_LOST Logging File handler lost during operation
60 LOCK_FAIL Locking Lock acquisition failed (non-timeout)
61 LOCK_TIMEOUT Locking Lock not acquired within LOCK_TIMEOUT_SECONDS
70 INTEGRITY_FAIL Integrity SHA-256 checksum mismatch
71 MEMORY_FAIL Integrity Memory allocation or scrubbing failure
80 SIGNAL_RECEIVED Signals SIGTERM/SIGINT/SIGHUP received
81 CLEANUP_FAIL Signals CleanupStack handler raised exception

Log Levels

Defined as LogLevel(IntEnum):

Level Numeric stdlib Mapping Console Default? Description
TRACE 0 5 (custom) No Ultra-verbose: cleanup registration, security init, validation steps
DEBUG 1 10 No Development diagnostics: function entry/exit, variable values
INFO 2 20 No Normal operations: init complete, rule created, backend selected
WARNING 3 30 Yes (default) Non-fatal issues: backend removal partially failed, stale lock detected
ERROR 4 40 Yes Operation failures: backend rejected rule, index save failed
CRITICAL 5 50 Yes Fatal: framework cannot continue, security violation
NONE 99 100 -- Suppress all console output (log file still captures everything)

Key behavior: The log FILE always captures all levels (TRACE and above). The --log-level flag only controls the CONSOLE handler threshold. This means full diagnostic information is always available in the log file for post-mortem analysis.


Rule Actions

Defined as RuleAction(StrEnum):

Action Type Backend Translation
accept Terminal iptables: -j ACCEPT. nft: accept. firewalld: accept. ufw: allow.
drop Terminal iptables: -j DROP. nft: drop. firewalld: drop. ufw: deny.
reject Terminal iptables: -j REJECT. nft: reject. firewalld: reject. ufw: reject.
log Non-terminal iptables: -j LOG --log-prefix. nft: log prefix. firewalld: log prefix=. ufw: ufw logging on.
masquerade Terminal iptables: -j MASQUERADE. nft: masquerade. firewalld: masquerade.
snat Terminal iptables: -j SNAT. nft: snat.
dnat Terminal iptables: -j DNAT. nft: dnat.
return Terminal iptables: -j RETURN. nft: return.

Compound actions: log,drop combines non-terminal + terminal. Maximum one terminal per compound. drop,accept is rejected (double-terminal).

Frozensets for classification:

  • TERMINAL_ACTIONS: {accept, drop, reject, masquerade, snat, dnat, return}
  • NON_TERMINAL_ACTIONS: {log}
  • ALL_ACTIONS: union of both

Rule Directions

Defined as RuleDirection(StrEnum):

Direction iptables Chain nftables Chain firewalld ufw
inbound INPUT input Rich rule (inbound) ufw allow in
outbound OUTPUT output Rich rule (outbound) ufw allow out
forward FORWARD forward Rich rule (forward) ufw route allow

Rule States

Defined as RuleState(StrEnum):

State Meaning Transitions
active Rule applied in backend and tracked in index → inactive (deactivate), → expired (TTL), → removed (delete)
inactive Removed from backend, retained in index → active (re-activate)
pending Being created (transient state) → active
expired TTL expired, auto-deactivated -- (terminal state, can be removed)

Duration Types

Defined as DurationType(StrEnum):

Type Behavior
permanent Rule persists until explicitly removed or deactivated. No TTL.
temporary Rule has a TTL (60-2,592,000 seconds). ExpiryMonitor auto-deactivates when expired.

Connection Tracking States

Defined as ConnState(StrEnum):

State Kernel Module Description Common Use
new conntrack First packet of a new connection Rate limiting new connections
established conntrack Packet in an existing tracked connection Stateful allow rules
related conntrack New connection related to existing (e.g., FTP data channel) Stateful allow rules
invalid conntrack Does not match any known connection Drop suspicious traffic
untracked conntrack Explicitly excluded from tracking High-performance bypass

Multiple states comma-separated: --conn-state new,established,related


Syslog Levels

Defined as SyslogLevel(StrEnum). Used with --log-level on firewall LOG actions (distinct from framework LogLevel):

Level Severity When to Use
emerg 0 -- Emergency System unusable
alert 1 -- Alert Immediate action required
crit 2 -- Critical Critical conditions
err 3 -- Error Error conditions
warning 4 -- Warning Warning conditions (default for LOG actions)
notice 5 -- Notice Normal but significant
info 6 -- Informational Informational messages
debug 7 -- Debug Debug-level messages

Validation Patterns

Precompiled regex patterns in Pattern class. All use re.fullmatch() (whitelist -- reject anything that doesn't match completely):

Pattern Regex Validates
IPV4 ^([0-9]{1,3}\.){3}[0-9]{1,3}$ IPv4 format (octet range checked separately)
IPV6 ^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}$ IPv6 format (supports :: compression)
CIDR_V4 ^([0-9]{1,3}\.){3}[0-9]{1,3}/[0-9]{1,2}$ IPv4 CIDR (prefix range checked separately)
CIDR_V6 ^([0-9a-fA-F]{0,4}:){2,7}[0-9a-fA-F]{0,4}/[0-9]{1,3}$ IPv6 CIDR
PORT ^[0-9]{1,5}$ Port number format (range checked separately: 1-65535)
PORT_RANGE ^[0-9]{1,5}[-:][0-9]{1,5}$ Port range: 8080-8090 or 8080:8090
PROTOCOL ^(tcp|udp|icmp|icmpv6|sctp|all)$ Allowed protocols
HOSTNAME RFC 1123 pattern Labels ≤63 chars, alphanumeric + hyphens
INTERFACE ^[a-zA-Z][a-zA-Z0-9._-]{0,14}$ Network interface: starts with letter, ≤15 chars
ZONE ^[a-zA-Z][a-zA-Z0-9_-]{0,31}$ Firewalld zone: starts with letter, ≤32 chars
CHAIN ^[a-zA-Z][a-zA-Z0-9_-]{0,63}$ Chain name: starts with letter, ≤64 chars
TABLE ^[a-zA-Z][a-zA-Z0-9_]{0,31}$ Table name: starts with letter, ≤32 chars
IPSET_NAME ^[a-zA-Z][a-zA-Z0-9_-]{0,30}$ ipset name: starts with letter, ≤31 chars
RULE_ID ^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$ UUID v4 format
SAFE_PATH ^[a-zA-Z0-9/_. ~:+\-]+$ Safe file path characters
NUMERIC ^[0-9]+$ Unsigned integer
ALNUM_SAFE ^[a-zA-Z0-9_-]+$ Safe identifier

Shell Metacharacters

SHELL_METACHARACTERS frozenset: ; | & \ $ ( ) { } \ < > ! #`

These 15 characters are rejected by _contains_shell_meta() using frozenset intersection (O(1) per character). Any input containing these characters is rejected by validators that call this function (ports, chains, tables, zones, interfaces, ipset names, descriptions, hostnames).


Backend: iptables

Tables

IPTABLES_TABLES frozenset: {filter, nat, mangle, raw, security}

Table Purpose Default Chains
filter Packet filtering (default) INPUT, OUTPUT, FORWARD
nat Network address translation PREROUTING, POSTROUTING, OUTPUT
mangle Packet alteration PREROUTING, INPUT, OUTPUT, FORWARD, POSTROUTING
raw Pre-conntrack processing PREROUTING, OUTPUT
security SELinux/AppArmor integration INPUT, OUTPUT, FORWARD

Built-in Chains

IPTABLES_BUILTIN_CHAINS frozenset: {INPUT, OUTPUT, FORWARD, PREROUTING, POSTROUTING}

Direction → Chain Mapping

Direction Chain Table
inbound INPUT filter
outbound OUTPUT filter
forward FORWARD filter

Compound Action Handling

iptables LOG is a non-terminating target. log,drop creates two separate kernel rules:

  1. iptables -A INPUT ... -j LOG --log-prefix "apotropaios:UUID: " --log-level info
  2. iptables -A INPUT ... -j DROP

Both rules share identical match criteria. Removal deletes both rules.

Match Arguments (_build_match_args)

Rule Parameter iptables Arguments
protocol -p tcp
src_ip --source 10.0.0.1 or --source 10.0.0.0/24
dst_ip --destination 192.168.1.0/24
src_port --sport 8080 (requires -p tcp or -p udp)
dst_port --dport 443 (requires -p tcp or -p udp)
interface (inbound) -i eth0
interface (outbound) -o eth0
conn_state -m conntrack --ctstate NEW,ESTABLISHED
limit -m limit --limit 5/minute
limit_burst --limit-burst 10
comment -m comment --comment "apotropaios:UUID"
log_prefix --log-prefix "PREFIX: "
log_level --log-level warning

Block/Allow/Reset Operations

Operation iptables Commands
block_all() iptables -P INPUT DROP, iptables -P OUTPUT DROP, iptables -P FORWARD DROP
allow_all() iptables -F (flush all rules), then iptables -P INPUT/OUTPUT/FORWARD ACCEPT
reset() For each table in {filter, nat, mangle, raw, security}: iptables -t TABLE -F, iptables -t TABLE -X. Then set all policies to ACCEPT.

Backend: nftables

Table Families

NFTABLES_TABLE_FAMILIES frozenset: {inet, ip, ip6, arp, bridge, netdev}

Family Description Default for Framework
inet IPv4 + IPv6 combined Yes (used by default)
ip IPv4 only No
ip6 IPv6 only No
arp ARP protocol No
bridge Ethernet bridging No
netdev Ingress/egress hook No

Auto-Created Resources

Apotropaios auto-creates the nftables table and chain if they don't exist:

  • Table: nft add table inet apotropaios
  • Chain: nft add chain inet apotropaios input { type filter hook input priority 0 \; policy accept \; }

Compound Action Handling

nftables combines compound actions in a single expression:

nft add rule inet apotropaios input tcp dport 443 log prefix "apotropaios:UUID: " drop

Direction → Chain Mapping

Direction Chain Hook
inbound input hook input priority 0
outbound output hook output priority 0
forward forward hook forward priority 0

Backend: firewalld

Zone-Aware Operations

firewalld uses zones to group network interfaces with trust levels. All rule operations include the --zone parameter (default: public).

Common Zone Trust Level Description
drop Lowest All incoming dropped, no reply
block Low Incoming rejected with icmp-host-prohibited
public Low Default zone. Selected incoming allowed.
external Low For external-facing interfaces with masquerading
dmz Low For DMZ servers with limited access
work Medium Trusted work network
home Medium Trusted home network
internal Medium Internal network
trusted Highest All traffic accepted

Rich Rule Syntax

_build_rich_rule() constructs rich rules:

rule family="ipv4" source address="10.0.0.1" port port="443" protocol="tcp" accept
rule family="ipv4" source address="10.0.0.0/24" port port="22" protocol="tcp" log prefix="SSH: " level="info" accept

Persistence

All firewalld operations use --permanent followed by --reload:

firewall-cmd --zone=public --add-rich-rule='...' --permanent
firewall-cmd --reload

Reset Behavior

reset() iterates ALL zones (not just the default). For each zone, removes all rich rules and reloads:

firewall-cmd --zone=<z> --list-rich-rules  # Get current rules
firewall-cmd --zone=<z> --remove-rich-rule='...' --permanent  # Remove each
firewall-cmd --reload

Backend: UFW

Action Mapping

Framework Action UFW Verb Notes
accept allow ufw allow <port>/tcp
drop deny ufw deny <port>/tcp
reject reject ufw reject <port>/tcp
log,drop deny + logging Terminal action becomes ufw verb; ufw logging on enables logging
log,accept allow + logging Same approach

Force Mode

All UFW commands include --force to suppress interactive confirmation prompts. Without this, ufw enable asks "Proceed with operation (y|n)?" which hangs in non-interactive mode.

Direction Syntax

Direction UFW Syntax
inbound ufw allow in <port>/tcp or ufw allow in from <ip> to any port <port>
outbound ufw allow out <port>/tcp

Backend: ipset

Set Types

IPSET_TYPES frozenset:

Set Type Entry Format Use Case
hash:ip Single IP address Blocklists, allowlists
hash:net CIDR network Network-based filtering
hash:ip,port IP + protocol + port Service-specific filtering
hash:net,port Network + protocol + port Network + service filtering
hash:net,iface Network + interface Interface-specific network rules
list:set Set of sets Hierarchical set organization

Cross-Reference with iptables

ipset creates the set, then creates an iptables rule referencing it:

ipset create blocklist hash:ip
ipset add blocklist 10.0.0.50
iptables -A INPUT -m set --match-set blocklist src -j DROP

Removal reverses: remove iptables rule first (_remove_iptables_refs()), then destroy set.

Entry Validation

_validate_entry() validates entries against the set type:

  • hash:ipvalidate_ip()
  • hash:netvalidate_cidr()
  • hash:ip,port → IP + protocol:port format validation

Supported Operating Systems

SUPPORTED_OS tuple of OSInfo NamedTuples:

os_id Display Name Package Manager Family
ubuntu Ubuntu apt debian
kali Kali Linux apt debian
debian Debian 12 apt debian
rocky Rocky Linux 9 dnf rhel
almalinux AlmaLinux 9 dnf rhel
arch Arch Linux pacman arch

Family Resolution

OS_FAMILY_MAP maps os_id and id_like values to families:

Key Family
ubuntu, debian, kali debian
rhel, centos, fedora, rocky, almalinux rhel
opensuse suse
arch arch

Directory Paths

DirPath class (relative to framework base directory):

Constant Value Purpose
CONF conf Configuration files
DATA data Runtime data root
LOGS data/logs Per-execution log files
RULES data/rules Rule index and state files
BACKUPS data/backups Backup archives
TEMP data/.tmp Temporary staging

File Names

FileName class:

Constant Value Purpose
CONF apotropaios.conf Framework configuration
RULE_INDEX rule_index.dat Pipe-delimited rule index (27 fields)
RULE_STATE rule_state.dat TTL and lifecycle state tracking
LOCK apotropaios.lock Advisory lock file
PID apotropaios.pid Process ID file

CLI Commands

CLI_COMMANDS tuple (18 commands):

Command Help Bypass Init? Requires Root? Description
menu No Yes Launch interactive menu
help Yes No Show global help
detect No Yes OS and firewall detection
status No Yes Service state display
add-rule No Yes Create and apply rule
remove-rule No Yes Remove rule by UUID
activate-rule No Yes Re-activate deactivated rule
deactivate-rule No Yes Deactivate (keep in index)
list-rules No Yes Show Apotropaios-tracked rules
system-rules No Yes Dump native backend rules
block-all No Yes Drop all traffic
allow-all No Yes Allow all traffic
import No Yes Import rules from file
export No Yes Export rules to file
backup No Yes Create backup archive
restore No Yes Restore from archive
install No Yes Install firewall package
update No Yes Update firewall package

Per-command help (COMMAND --help) also bypasses framework initialization.


CLI Global Options

Flag Position Requires Init? Description
--help, -h Any No Global or per-command help
--version, -v Any No Version and exit
--interactive Before command Yes Launch menu (mutually exclusive with commands)
--non-interactive Any Yes Disable prompts (mutually exclusive with --interactive)
--log-level LEVEL Any Yes Console verbosity: trace/debug/info/warning/error/critical/none
--backend NAME Any Yes Select backend: iptables/nftables/firewalld/ufw/ipset

All flags are position-independent (work before or after the command name).


Cancel Keywords

CANCEL_KEYWORDS frozenset: {q, quit, cancel, back, b}

Type any of these at any interactive menu prompt to cancel the current operation and return to the previous menu. Case-insensitive, whitespace-trimmed.

Apotropaios -- Python Variant

Getting Started

Architecture

Operations

Project


35 files · 14,545 lines · 322 tests

Clone this wiki locally