06.2-credentials.yml.md•14.8 kB
# 6.2 credentials.yml
**Purpose:** Configure SSH authentication methods, manage secrets, and define credential resolution for mcp-ssh-orchestrator.
## Overview
The `credentials.yml` file defines **SSH authentication methods** and **secret management** for connecting to target hosts. It supports both key-based and password-based authentication with secure secret resolution.
## File Structure
```yaml
# credentials.yml
entries:
- name: "prod_admin"
username: "ubuntu"
key_path: "id_ed25519"
key_passphrase_secret: "prod_key_passphrase"
password_secret: ""
- name: "legacy_password"
username: "admin"
key_path: ""
password_secret: "legacy_password"
```
## Configuration Fields
### Required Fields
| Field | Type | Description | Example |
|-------|------|-------------|---------|
| `name` | string | Unique credential identifier | `"prod_admin"` |
| `username` | string | SSH username | `"ubuntu"` |
### Optional Fields
| Field | Type | Default | Description | Example |
|-------|------|---------|-------------|---------|
| `key_path` | string | `""` | SSH private key file path | `"id_ed25519"` |
| `key_passphrase_secret` | string | `""` | Passphrase secret name | `"prod_key_passphrase"` |
| `password_secret` | string | `""` | Password secret name | `"admin_password"` |
## Authentication Methods
### Key-Based Authentication (Recommended)
**SSH Key Authentication:**
```yaml
entries:
- name: "prod_admin"
username: "ubuntu"
key_path: "id_ed25519"
key_passphrase_secret: "prod_key_passphrase"
password_secret: "" # Empty = no password auth
```
**Key without Passphrase:**
```yaml
entries:
- name: "dev_admin"
username: "developer"
key_path: "dev_key"
key_passphrase_secret: "" # Empty = no passphrase
password_secret: ""
```
### Password-Based Authentication
**Password Authentication:**
```yaml
entries:
- name: "legacy_admin"
username: "admin"
key_path: "" # Empty = no key auth
password_secret: "legacy_password"
```
**Mixed Authentication (Key + Password):**
```yaml
entries:
- name: "mixed_auth"
username: "ubuntu"
key_path: "id_ed25519"
key_passphrase_secret: "key_passphrase"
password_secret: "user_password"
```
## Secret Resolution
### Secret Resolution Order
Secrets are resolved in this order:
1. **Environment variable**: `MCP_SSH_SECRET_<NAME>` (uppercase)
2. **Docker secret file**: `/app/secrets/<name>`
3. **Empty string**: If not found
### Path Traversal Protection
**Security Feature:** Secret resolution includes path traversal protection to prevent unauthorized file access.
### Input Length Limits
All string parameters in credentials configuration have length limits:
- **Secret Names**: Maximum 100 characters
- Validated when resolving secrets via `password_secret`, `key_passphrase_secret`
- Names exceeding limit are rejected with security event logging
- **SSH Key Paths**: Maximum 500 characters
- Validated when resolving key paths
- Paths exceeding limit are rejected with security event logging
**Security**: Length limits prevent resource exhaustion attacks via oversized inputs.
#### Secret Name Validation
- **Allowed characters**: Alphanumeric (a-z, A-Z, 0-9), dash (-), underscore (_)
- **Rejected**: Special characters, path separators, traversal patterns
- **Examples**:
```yaml
# ✅ Valid
password_secret: "prod_password"
password_secret: "key-passphrase"
# ❌ Invalid (rejected)
password_secret: "../etc/passwd" # Path traversal
password_secret: "/absolute/path" # Absolute path
password_secret: "secret.name" # Special characters
```
#### Path Resolution Security
1. **Relative paths only**: Secrets must use relative paths (no absolute paths)
2. **Directory confinement**: All resolved paths must stay within `/app/secrets`
3. **Normalization**: Paths are normalized to handle encoded traversal attempts
4. **File type validation**: Only regular files are accepted (directories and symlinks rejected)
5. **Security logging**: Path traversal and file validation failures are logged as security events
**File Type Requirements:**
- ✅ Regular files within secrets directory
- ❌ Directories (must be files, not directories)
- ❌ Symbolic links (rejected for security)
**Effect**: Prevents accessing files outside the secrets directory via path traversal attacks and blocks access to directories or symlinks that could pose security risks.
### Environment Variables
**Setting secrets via environment:**
```bash
# Set secret via environment variable
export MCP_SSH_SECRET_PROD_KEY_PASSPHRASE="my-passphrase"
export MCP_SSH_SECRET_ADMIN_PASSWORD="admin-password"
# Use in Docker
docker run -i --rm \
-e MCP_SSH_SECRET_PROD_KEY_PASSPHRASE="my-passphrase" \
-e MCP_SSH_SECRET_ADMIN_PASSWORD="admin-password" \
ghcr.io/samerfarida/mcp-ssh-orchestrator:0.1.0
```
**Claude Desktop configuration:**
```json
{
"mcpServers": {
"ssh-orchestrator": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_SSH_SECRET_PROD_PASSWORD=your-password",
"-v", "/Users/YOUR_USERNAME/mcp-ssh/config:/app/config:ro",
"-v", "/Users/YOUR_USERNAME/mcp-ssh/keys:/app/keys:ro",
"ghcr.io/samerfarida/mcp-ssh-orchestrator:0.1.0"
]
}
}
}
```
### Docker Secrets
**Creating Docker secrets:**
```bash
# Create secret
echo "my-passphrase" | docker secret create ssh_key_passphrase -
# Use in Docker Compose
services:
mcp-ssh:
image: ghcr.io/samerfarida/mcp-ssh-orchestrator:0.1.0
secrets:
- ssh_key_passphrase
volumes:
- ./config:/app/config:ro
- ./keys:/app/keys:ro
secrets:
ssh_key_passphrase:
external: true
```
**File-based secrets:**
```bash
# Create secrets directory
mkdir -p ~/mcp-ssh/secrets
chmod 0700 ~/mcp-ssh/secrets
# Add secret files
echo "passphrase" > ~/mcp-ssh/secrets/key_passphrase
echo "password" > ~/mcp-ssh/secrets/admin_password
# Set permissions
chmod 0400 ~/mcp-ssh/secrets/*
```
## SSH Key Management
### Key Generation
**Ed25519 Keys (Recommended):**
```bash
# Generate Ed25519 key pair
ssh-keygen -t ed25519 -f ~/.ssh/mcp_orchestrator -C "mcp-ssh-orchestrator"
# Copy to keys directory
cp ~/.ssh/mcp_orchestrator ~/mcp-ssh/keys/id_ed25519
cp ~/.ssh/mcp_orchestrator.pub ~/mcp-ssh/keys/id_ed25519.pub
# Set permissions
chmod 0400 ~/mcp-ssh/keys/id_ed25519
chmod 0444 ~/mcp-ssh/keys/id_ed25519.pub
```
**RSA Keys (Legacy):**
```bash
# Generate RSA 4096-bit key pair
ssh-keygen -t rsa -b 4096 -f ~/.ssh/mcp_orchestrator_rsa -C "mcp-ssh-orchestrator"
# Copy to keys directory
cp ~/.ssh/mcp_orchestrator_rsa ~/mcp-ssh/keys/id_rsa
cp ~/.ssh/mcp_orchestrator_rsa.pub ~/mcp-ssh/keys/id_rsa.pub
# Set permissions
chmod 0400 ~/mcp-ssh/keys/id_rsa
chmod 0444 ~/mcp-ssh/keys/id_rsa.pub
```
### Key Deployment
**Deploy public key to target hosts:**
```bash
# Copy public key to target host
ssh-copy-id -i ~/mcp-ssh/keys/id_ed25519.pub ubuntu@10.0.0.11
# Or manually add to authorized_keys
cat ~/mcp-ssh/keys/id_ed25519.pub | ssh ubuntu@10.0.0.11 "mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys"
```
### Key Rotation
**Rotate SSH keys:**
```bash
# Generate new key pair
ssh-keygen -t ed25519 -f ~/.ssh/mcp_orchestrator_new -C "mcp-ssh-orchestrator-new"
# Deploy new public key to all hosts
for host in $(ssh_list_hosts); do
ssh-copy-id -i ~/.ssh/mcp_orchestrator_new.pub ubuntu@$host
done
# Update configuration
cp ~/.ssh/mcp_orchestrator_new ~/mcp-ssh/keys/id_ed25519
chmod 0400 ~/mcp-ssh/keys/id_ed25519
# Remove old key from hosts
for host in $(ssh_list_hosts); do
ssh ubuntu@$host "sed -i '/mcp-ssh-orchestrator/d' ~/.ssh/authorized_keys"
done
```
## Environment-Specific Configurations
### Development Environment
```yaml
# credentials.yml - Development
entries:
- name: "dev_admin"
username: "developer"
key_path: "dev_key"
key_passphrase_secret: "" # No passphrase for dev
password_secret: ""
- name: "dev_root"
username: "root"
key_path: "dev_root_key"
key_passphrase_secret: ""
password_secret: ""
```
### Staging Environment
```yaml
# credentials.yml - Staging
entries:
- name: "staging_admin"
username: "ubuntu"
key_path: "staging_key"
key_passphrase_secret: "staging_key_passphrase"
password_secret: ""
- name: "staging_service"
username: "service"
key_path: "staging_service_key"
key_passphrase_secret: "staging_service_passphrase"
password_secret: ""
```
### Production Environment
```yaml
# credentials.yml - Production
entries:
- name: "prod_admin"
username: "ubuntu"
key_path: "prod_key"
key_passphrase_secret: "prod_key_passphrase"
password_secret: ""
- name: "prod_service"
username: "service"
key_path: "prod_service_key"
key_passphrase_secret: "prod_service_passphrase"
password_secret: ""
- name: "prod_monitoring"
username: "monitoring"
key_path: "prod_monitoring_key"
key_passphrase_secret: "prod_monitoring_passphrase"
password_secret: ""
```
## Multi-User Configurations
### Different Users per Host Type
```yaml
entries:
# Web server credentials
- name: "web_admin"
username: "ubuntu"
key_path: "web_key"
key_passphrase_secret: "web_key_passphrase"
password_secret: ""
# Database server credentials
- name: "db_admin"
username: "postgres"
key_path: "db_key"
key_passphrase_secret: "db_key_passphrase"
password_secret: ""
# Monitoring server credentials
- name: "monitor_admin"
username: "monitoring"
key_path: "monitor_key"
key_passphrase_secret: "monitor_key_passphrase"
password_secret: ""
```
### Service Account Credentials
```yaml
entries:
# Application service account
- name: "app_service"
username: "app"
key_path: "app_service_key"
key_passphrase_secret: "app_service_passphrase"
password_secret: ""
# Backup service account
- name: "backup_service"
username: "backup"
key_path: "backup_service_key"
key_passphrase_secret: "backup_service_passphrase"
password_secret: ""
# Monitoring service account
- name: "monitoring_service"
username: "monitoring"
key_path: "monitoring_service_key"
key_passphrase_secret: "monitoring_service_passphrase"
password_secret: ""
```
## Path Traversal Protection for Keys
**Security Feature:** SSH key path resolution includes path traversal protection.
### Key Path Validation
- **Relative paths**: Resolved relative to `keys_dir`, validated to stay within directory
- **Absolute paths**: Must be within `keys_dir` (rejected if outside)
- **Traversal patterns**: Paths containing `..` or `..\\` are rejected
- **File type validation**: Only regular files accepted (directories and symlinks rejected)
- **Security logging**: Path traversal and file validation failures are logged
**Examples**:
```yaml
# ✅ Valid key paths
key_path: "id_ed25519" # Relative, within keys_dir
key_path: "/app/keys/id_ed25519" # Absolute, within keys_dir
# ❌ Invalid (rejected)
key_path: "../outside_key" # Path traversal
key_path: "/etc/passwd" # Outside keys_dir
key_path: "../../root/.ssh/id_rsa" # Traversal attempt
key_path: "subdirectory" # Points to directory, not file
key_path: "symlink_key" # Points to symlink, not regular file
```
**File Type Requirements:**
- ✅ Regular files within keys_dir (or non-existent files - validated when used)
- ❌ Directories
- ❌ Symbolic links (rejected for security)
**Effect**: Prevents accessing SSH keys from unauthorized locations and blocks access to directories or symlinks that could pose security risks.
## Security Best Practices
### Key Security
1. **Use Ed25519 keys** for new deployments
2. **Set private key permissions** to 0400
3. **Use passphrases** for private keys
4. **Rotate keys quarterly**
5. **Use separate keys** for different environments
### Secret Security
1. **Never hardcode secrets** in YAML files
2. **Use Docker secrets** for production
3. **Use environment variables** for development
4. **Rotate secrets regularly**
5. **Use strong, unique secrets**
### Access Control
1. **Use least-privilege usernames**
2. **Separate service accounts** from admin accounts
3. **Use different credentials** per environment
4. **Monitor credential usage**
5. **Revoke unused credentials**
## Validation and Testing
### Configuration Validation
```bash
# Validate credentials.yml syntax
python -c "import yaml; yaml.safe_load(open('config/credentials.yml'))"
# Validate credential references
python -c "
from mcp_ssh.config import Config
config = Config('config/')
print('Credential validation:', config.validate_credentials())
"
```
### Authentication Testing
```bash
# Test SSH key authentication
ssh -i keys/id_ed25519 ubuntu@10.0.0.11 "echo 'Key auth successful'"
# Test password authentication
ssh ubuntu@10.0.0.11 "echo 'Password auth successful'"
# Test via mcp-ssh-orchestrator
ssh_ping # Health check
ssh_describe_host --alias "web1" # Get host details
```
### Secret Resolution Testing
```bash
# Test secret resolution
python -c "
from mcp_ssh.config import Config
config = Config('config/')
cred = config.get_credentials('prod_admin')
print('Key path:', cred.key_path)
print('Username:', cred.username)
"
```
## Troubleshooting
### Common Issues
1. **Invalid YAML syntax**
```bash
# Check syntax
python -c "import yaml; yaml.safe_load(open('config/credentials.yml'))"
```
2. **Missing secret files**
```bash
# Check secret files
ls -la ~/mcp-ssh/secrets/
```
3. **Wrong key permissions**
```bash
# Fix key permissions
chmod 0400 ~/mcp-ssh/keys/*
```
4. **SSH connection failures**
```bash
# Test SSH connection
ssh -v -i keys/id_ed25519 ubuntu@10.0.0.11
```
### Authentication Issues
1. **Key authentication failed**
```bash
# Check key format
ssh-keygen -l -f keys/id_ed25519
# Test key manually
ssh -i keys/id_ed25519 ubuntu@10.0.0.11
```
2. **Password authentication failed**
```bash
# Check password secret
echo $MCP_SSH_SECRET_ADMIN_PASSWORD
# Test password manually
ssh ubuntu@10.0.0.11
```
3. **Passphrase authentication failed**
```bash
# Check passphrase secret
echo $MCP_SSH_SECRET_KEY_PASSPHRASE
# Test passphrase manually
ssh -i keys/id_ed25519 ubuntu@10.0.0.11
```
## Next Steps
- **[policy.yml](06.3-policy.yml)** - Security policy configuration
- **[Usage Cookbook](08-Usage-Cookbook)** - Practical credential examples
- **[Deployment](09-Deployment)** - Production credential management
- **[Troubleshooting](12-Troubleshooting)** - Common credential issues