06 Configuration - samerfarida/mcp-ssh-orchestrator GitHub Wiki
Purpose: Overview of the configuration system and how the three main configuration files work together to define hosts, credentials, and security policies.
mcp-ssh-orchestrator uses a three-file configuration system that separates concerns and enables secure, flexible deployment:
- servers.yml - Host inventory and network configuration
- credentials.yml - SSH authentication and secrets management
- policy.yml - Security policies and access controls
graph TB
subgraph "Configuration Files"
SERVERS[servers.yml<br/>Host Inventory]
CREDS[credentials.yml<br/>SSH Authentication]
POLICY[policy.yml<br/>Security Policies]
end
subgraph "Configuration Loader"
CONFIG_LOADER[config.py]
end
subgraph "Policy Engine"
POLICY_ENGINE[policy.py]
end
subgraph "SSH Client"
SSH_CLIENT[ssh_client.py]
end
SERVERS --> CONFIG_LOADER
CREDS --> CONFIG_LOADER
POLICY --> CONFIG_LOADER
CONFIG_LOADER --> POLICY_ENGINE
CONFIG_LOADER --> SSH_CLIENT
POLICY_ENGINE --> POLICY
mcp-ssh-orchestrator/
├── config/
│ ├── servers.yml # Host inventory
│ ├── credentials.yml # SSH credentials
│ └── policy.yml # Security policies
├── keys/ # SSH private keys (chmod 0400)
└── secrets/ # Docker secrets (passwords, passphrases)
The configuration loader searches for files in this order:
- Command-line arguments (if specified)
-
Environment variables (
MCP_SSH_CONFIG_DIR) -
Default paths (
/app/config/in container,./config/locally)
Each configuration file is validated for:
- YAML syntax correctness
- Required fields presence
- Data type validation
- Cross-file references validity
The system merges configurations with this precedence:
- servers.yml - Host definitions and network settings
- credentials.yml - Authentication methods and secrets
- policy.yml - Security policies and access controls
Relationship: Hosts reference credential entries by name.
# servers.yml
hosts:
- alias: "web1"
host: "10.0.0.11"
credentials: "prod_admin" # References credentials.yml
# credentials.yml
entries:
- name: "prod_admin" # Referenced by servers.yml
username: "ubuntu"
key_path: "id_ed25519"Relationship: Policy rules can target hosts by alias or tags.
# servers.yml
hosts:
- alias: "prod-web-1"
tags: ["production", "web"] # Used by policy rules
# policy.yml
rules:
- action: "allow"
aliases: ["prod-*"] # Matches prod-web-1
tags: ["production"] # Matches production tag
commands: ["uptime*"]Relationship: Policy can enforce credential requirements.
# credentials.yml
entries:
- name: "prod_admin"
username: "ubuntu"
key_path: "id_ed25519"
# policy.yml
limits:
require_known_host: true # Enforces host key verification# Validate YAML syntax
python -c "import yaml; yaml.safe_load(open('config/servers.yml'))"# Check credential references
python -c "
from mcp_ssh.config import Config
config = Config('config/')
print('Valid configuration:', config.validate())
"# Test policy rules
python -c "
from mcp_ssh.policy import Policy
policy = Policy('config/policy.yml')
print('Policy valid:', policy.validate())
"Security Enhancement: mcp-ssh-orchestrator includes built-in path traversal protection for all file path resolution.
- Secret names are validated to contain only safe characters (alphanumeric, dash, underscore)
- Absolute paths are rejected for secrets (relative paths only)
- All paths are normalized and validated to stay within
/app/secrets - Path traversal attempts (e.g.,
../,..\\) are blocked and logged
- Key paths can be relative or absolute
- Absolute paths must be within the configured
keys_dir - Traversal patterns (
..,..\\) are detected and rejected - Paths are normalized and validated before access
- Only regular files are accepted (directories and symlinks are rejected)
All resolved file paths are validated to ensure security:
- Directories: Rejected (paths must point to files, not directories)
- Symbolic Links: Rejected (symlinks can be security risks)
- Regular Files: Accepted (must exist for secrets, optional for keys)
- Non-existent files: Allowed for keys (validated when actually used)
Security Events: All path traversal attempts and file validation failures are logged as security events for monitoring and incident response.
All YAML configuration files are protected against resource exhaustion attacks:
-
Maximum File Size: 10MB per YAML file (applies to
servers.yml,credentials.yml,policy.yml) - Size Validation: File size is checked before parsing to prevent loading oversized files
- Security Impact: Prevents resource exhaustion attacks via maliciously large configuration files
- Logging: Size limit violations are logged as security events
Effect: Protects against memory exhaustion and processing time attacks while allowing legitimate large configurations.
# Secure configuration files
chmod 0600 config/servers.yml
chmod 0600 config/credentials.yml
chmod 0600 config/policy.yml
chmod 0400 keys/*.pem
chmod 0400 keys/id_ed25519# credentials.yml - Use secrets, not plaintext
entries:
- name: "prod_admin"
username: "ubuntu"
key_path: "id_ed25519"
key_passphrase_secret: "prod_key_passphrase" # Docker secret
password_secret: "" # Empty = no password# Override configuration via environment
export MCP_SSH_CONFIG_DIR="/custom/config"
export MCP_SSH_SECRET_PROD_PASSWORD="secret-password"# servers.yml - Development hosts
hosts:
- alias: "dev-web-1"
host: "192.168.1.10"
port: 22
credentials: "dev_admin"
tags: ["development", "web"]
# credentials.yml - Development credentials
entries:
- name: "dev_admin"
username: "developer"
key_path: "dev_key"
key_passphrase_secret: "dev_passphrase"
# policy.yml - Permissive development policy
limits:
max_seconds: 120
require_known_host: true # Always enforced for security (CWE-295)
rules:
- action: "allow"
aliases: ["dev-*"]
commands: ["*"] # Allow all commands in dev# servers.yml - Production hosts
hosts:
- alias: "prod-web-1"
host: "10.0.0.11"
port: 22
credentials: "prod_admin"
tags: ["production", "web"]
# credentials.yml - Production credentials
entries:
- name: "prod_admin"
username: "ubuntu"
key_path: "prod_key"
key_passphrase_secret: "prod_passphrase"
# policy.yml - Strict production policy
limits:
max_seconds: 30
require_known_host: true
deny_substrings:
- "rm -rf /"
- "shutdown*"
- "reboot*"
rules:
- action: "allow"
aliases: ["prod-*"]
commands: ["uptime*", "df -h*", "systemctl status *"]# Reload configuration without restart
ssh_reload_config# Backup configuration
tar -czf config-backup-$(date +%Y%m%d).tar.gz config/ keys/# Track configuration changes
git add config/
git commit -m "Update production policy for new hosts"-
YAML Syntax Errors
# Check YAML syntax python -c "import yaml; yaml.safe_load(open('config/servers.yml'))"
-
Missing Credential References
# Validate credential references python -c " from mcp_ssh.config import Config config = Config('config/') for host in config.list_hosts(): print(f'{host}: {config.get_host(host).credentials}') "
-
Policy Rule Conflicts
# Test policy rules ssh_plan --alias "web1" --command "uptime"
# Validate all configuration files
python -m mcp_ssh.config validate config/
# Test policy rules
python -m mcp_ssh.policy test config/policy.yml
# Check credential references
python -m mcp_ssh.config check-refs config/- servers.yml - Host inventory configuration
- credentials.yml - SSH authentication setup
- policy.yml - Security policy configuration
- Deployment - Production configuration examples