# example-policy.yml
#
# Example security policy configuration for mcp-ssh-orchestrator.
# Copy this to config/policy.yml and customize for your security requirements.
#
# This file defines:
# - Command allow/deny rules (deny-by-default)
# - Execution limits (timeouts, output caps, async TTLs)
# - Network controls (IP allowlists/blocklists)
# - Per-host and per-tag overrides
#
# IMPORTANT:
# - Host key verification is always enforced. `host_key_auto_add: true` and
# `require_known_host: false` are deprecated and ignored for security (CWE-295).
# - Maintain a known_hosts file and mount it read-only into /app/keys.
# Strict host-key validation file (mount read-only)
known_hosts_path: "/app/keys/known_hosts"
# Global execution limits (overrides can change these per alias/tag)
limits:
max_seconds: 60
max_output_bytes: 1048576
host_key_auto_add: false # kept for backwards compatibility (ignored)
require_known_host: true # keep this enabled to enforce strict host key verification
task_result_ttl: 300 # seconds; async results retained for 5 minutes
task_progress_interval: 5 # seconds between progress notifications
# Hard-blocked command substrings (checked before rule evaluation)
deny_substrings:
# Destructive commands
- "rm -rf /"
- ":(){ :|:& };:"
- "mkfs "
- "dd if=/dev/zero"
- "shutdown -h"
- "reboot"
- "userdel "
- "passwd "
# Lateral movement / egress tools
- "ssh "
- "scp "
- "rsync -e ssh"
- "curl "
- "wget "
- "nc "
- "nmap "
- "telnet "
- "kubectl "
- "aws "
- "gcloud "
- "az "
# Network egress controls
network:
# Allow only RFC1918 ranges by default (empty list = allow all)
allow_ips: []
allow_cidrs:
- "10.0.0.0/8"
- "172.16.0.0/12"
- "192.168.0.0/16"
# Explicit denies win over allows
block_ips: []
block_cidrs: []
# Require known_hosts entry before connection (enforced in code)
require_known_host: true
# Command allow/deny rules (deny-by-default) - Version 2 schema
rules:
# 1) Bulk allow: simple, mostly-read-only inspection binaries on all hosts
- action: "allow"
aliases: ["*"]
tags: []
simple_binaries:
- uname
- uptime
- whoami
- ls
- echo
- id
- hostname
- date
simple_max_args: 6
# 2) Structured rules for commands with specific arguments
# df -h (show human-readable disk usage)
- action: "allow"
aliases: ["*"]
tags: []
binary: "df"
arg_prefix: ["-h"]
allow_extra_args: false
# free -m (show memory in MB)
- action: "allow"
aliases: ["*"]
tags: []
binary: "free"
arg_prefix: ["-m"]
allow_extra_args: false
# cat readonly config files
- action: "allow"
aliases: ["*"]
tags: []
binary: "cat"
allow_extra_args: false
path_args:
indices: [1]
patterns:
- "/etc/os-release"
- "/etc/*release"
# Package inventory on Linux hosts
# dpkg -l
- action: "allow"
aliases: ["*"]
tags: ["linux"]
binary: "dpkg"
arg_prefix: ["-l"]
allow_extra_args: false
# rpm -qa
- action: "allow"
aliases: ["*"]
tags: ["linux"]
binary: "rpm"
arg_prefix: ["-qa"]
allow_extra_args: false
# apt list --installed
- action: "allow"
aliases: ["*"]
tags: ["linux"]
binary: "apt"
arg_prefix: ["list", "--installed"]
allow_extra_args: false
# Service status checks (read-only)
# systemctl status <unit>
- action: "allow"
aliases: ["*"]
tags: []
binary: "systemctl"
arg_prefix: ["status"]
allow_extra_args: true
# journalctl --no-pager -n 200
- action: "allow"
aliases: ["*"]
tags: []
binary: "journalctl"
arg_prefix: ["--no-pager", "-n", "200"]
allow_extra_args: true
# docker ps
- action: "allow"
aliases: ["*"]
tags: []
binary: "docker"
arg_prefix: ["ps"]
allow_extra_args: false
# docker inspect
- action: "allow"
aliases: ["*"]
tags: []
binary: "docker"
arg_prefix: ["inspect"]
allow_extra_args: true
# Network diagnostics on non-production environments
# ping
- action: "allow"
aliases:
- "stg-*"
- "lab-*"
- "dev-*"
tags:
- "staging"
- "lab"
- "dev"
simple_binaries:
- ping
- traceroute
- netstat
simple_max_args: 8
# ss -tulpn
- action: "allow"
aliases:
- "stg-*"
- "lab-*"
- "dev-*"
tags:
- "staging"
- "lab"
- "dev"
binary: "ss"
arg_prefix: ["-tulpn"]
allow_extra_args: false
# Controlled service restarts on staging only
# sudo systemctl restart <unit>
- action: "allow"
aliases: ["stg-*"]
tags: ["staging"]
binary: "sudo"
arg_prefix: ["systemctl"]
allow_extra_args: true
# Explicit denies (redundant with deny_substrings, but explicit for clarity)
- action: "deny"
aliases: ["*"]
tags: []
simple_binaries:
- rm
- chmod
- chown
- shutdown
- reboot
# Per-alias and per-tag limit overrides
overrides:
aliases:
# Production hosts: tighter timeouts/output limits
prod-web-1:
max_seconds: 30
max_output_bytes: 524288
prod-db-1:
max_seconds: 20
max_output_bytes: 262144
tags:
# Production: apply stricter defaults automatically
production:
max_seconds: 30
max_output_bytes: 524288
# Lab: relaxed timeout for experimentation (host key rules still enforced)
lab:
max_seconds: 90
# Long-running operations: extend async result TTL for post-run inspection
longrun:
max_seconds: 180
task_result_ttl: 1800 # 30 minutes