Policy Engine
Define allow/deny rules for commands and file paths to enforce operational guardrails.
The policy engine defines guardrails that control which commands can be executed and which file paths can be accessed. Rules apply equally to human operators and AI agents connected via the MCP server.
Policy Modes
| Mode | Behavior |
|---|---|
off | Policy evaluation is disabled. All operations are allowed. |
warn | Violations are logged to the audit log but not blocked. Useful for testing new rules. |
enforce | Violations are blocked and the operation is rejected with an error. |
Configuration
Policies are defined in nefia.yaml under the policy key:
policy:
mode: enforce
deny_commands:
- "^rm\\s+-rf\\s+/"
- "^(shutdown|reboot|halt|poweroff)"
- "^mkfs\\."
- "^dd\\s+if=.+of=/dev/"
allow_commands:
- "systemctl\\s+(status|restart|reload)"
- "journalctl"
- "docker\\s+(ps|logs|inspect)"
deny_paths:
- "/etc/shadow"
- "/etc/sudoers"
- "\\.ssh/.*private"
allowed_roots:
- /var/www
- /home/deploy
- /etc/nginxAll command and path rules use Go regular expressions matched against the full command string or file path. Patterns without ^ (start) or $ (end) anchors match anywhere in the string — for example, rm also matches format and chromium. Use ^rm to match only commands starting with rm.
Input Length Limit (ReDoS Defense)
To prevent Regular Expression Denial of Service (ReDoS) attacks via pathologically crafted input, the policy engine enforces a maximum input length of 8,192 bytes (2× Linux PATH_MAX) on all evaluated strings — commands, paths, and roots.
Inputs exceeding this limit are denied unconditionally, even in warn mode. This is intentional: relaxing the limit in warn mode would defeat the protection entirely by allowing regex evaluation on arbitrarily large inputs.
Evaluation Order
Deny rules are checked first. If the command matches any pattern in deny_commands (or the path matches deny_paths), the operation is blocked.
Allow rules are checked second. If allow_commands is non-empty and the command does not match any allow pattern, the operation is blocked.
Allowed roots are checked for file operations. The resolved file path must fall within one of the directories listed in allowed_roots.
If no rules match, the operation is allowed. An empty policy permits everything.
RBAC Roles
For more granular control, define named roles with host-specific command and path rules:
policy:
mode: enforce
roles:
- name: read-only
hosts: [".*"]
allow_commands: ["cat|head|tail|less|grep|find|ls|stat", "systemctl\\s+status"]
deny_commands: ["^.*"] # deny everything not explicitly allowed
- name: deploy
hosts: ["^web-", "^worker-"]
allow_commands: ["systemctl\\s+(restart|reload)", "docker\\s+(pull|up|down|restart)"]
deny_commands: ["^rm\\s+-rf", "^(shutdown|reboot)"]
allowed_roots: [/var/www, /home/deploy]Roles are selected from the target host's role field. roles[].hosts is evaluated as a host ID regex, not a group selector and not an operator-identity rule.
MCP Server Integration
When the MCP server is running (nefia mcp serve), the policy engine evaluates every tool call from AI agents using the same rules. There is no privilege escalation path for MCP clients.
[MCP] Tool call: exec command="rm -rf /tmp/*" target="web-01"
[MCP] Policy violation: command matches deny rule "^rm\s+-rf\s+/"
[MCP] Result: DENIED (policy: enforce)Testing Policies
Use nefia plan exec to dry-run an operation against the policy engine without executing it:
nefia plan exec --target my-server -- rm -rf /tmp/cacheCommand: rm -rf /tmp/cache Target: my-server (10.99.0.2) Policy: DENIED — matches deny_commands pattern: "^rm\s+-rf\s+/"
No commands were executed.
MCP Tools for Policy Testing
AI agents can test policies programmatically:
| Tool | Description |
|---|---|
nefia.policy.test | Test whether a specific command or path would be allowed or denied by the policy engine. |
nefia.policy.test_batch | Test up to 50 command/path combinations in a single call for efficient pre-flight checks. |
nefia.policy.capabilities | List all allowed operations for a given host, showing what commands and paths the current policy permits. |
Practical Examples
Read-only monitoring access
policy:
mode: enforce
roles:
- name: monitoring
hosts: [".*"]
allow_commands: ["uptime|free|df|top -bn1", "systemctl\\s+status", "cat\\s+/var/log/"]
deny_commands: ["^.*"]Restrict file access to application directories
policy:
mode: enforce
deny_paths: ["/etc/(shadow|passwd|sudoers)", "\\.ssh/", "\\.env"]
allowed_roots: [/var/www/myapp, /var/log/myapp]Block destructive commands globally
policy:
mode: enforce
deny_commands:
- "^rm\\s+-rf\\s+/"
- "^(shutdown|reboot|halt|poweroff)"
- "^mkfs\\."
- "^dd\\s+if=.+of=/dev/"
- "^chmod\\s+777"
- "^curl.*\\|\\s*(bash|sh)"Related
Understand Nefia's defense-in-depth security architecture.
Track policy violations and all operations with tamper-evident logs.