Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -699,6 +699,7 @@ defaults:
ssh_key: ~/.ssh/id_rsa
parallel: 10
timeout: 300 # Command timeout in seconds (0 for unlimited)
jump_host: bastion.example.com # Global default jump host (optional)

# Global interactive mode settings (optional)
interactive:
Expand Down Expand Up @@ -726,21 +727,58 @@ clusters:
- [email protected]:2222
ssh_key: ~/.ssh/prod_key
timeout: 600 # Override default timeout for this cluster
jump_host: prod-bastion.example.com # Cluster-specific jump host
# Cluster-specific interactive settings (overrides global)
interactive:
default_mode: single_node
prompt_format: "prod> "
work_dir: /var/www

staging:
nodes:
- host: staging1.example.com
port: 2200
user: deploy
jump_host: staging-bastion:2222 # Node-specific jump host
- staging2.example.com
user: staging_user
jump_host: "" # Explicitly disable jump host for this cluster
```

### Jump Host Configuration in config.yaml

bssh supports configuring jump hosts at three levels in your configuration file, with environment variable support:

**Priority Order** (highest to lowest):
1. **CLI `-J` option** - Always takes precedence
2. **Node-level** - Per-node `jump_host` in detailed node config
3. **Cluster-level** - `jump_host` in cluster defaults
4. **Global default** - `jump_host` in top-level defaults

**Example:**
```yaml
defaults:
jump_host: ${BASTION_HOST} # Environment variables supported

clusters:
production:
nodes:
- host: prod1.internal
- host: prod2.internal
jump_host: "" # Explicitly disable for this node
jump_host: prod-bastion.example.com

direct-access:
nodes:
- host: direct.example.com
jump_host: "" # Empty string disables inheritance
```

**Notes:**
- Empty string (`""`) explicitly disables jump host inheritance at any level
- Environment variables (`${VAR}` or `$VAR`) are expanded in jump_host values
- Node-level jump_host requires detailed node syntax (not simple hostname strings)

## SSH Configuration Support

bssh fully supports OpenSSH-compatible configuration files via the `-F` flag or default SSH config locations (`~/.ssh/config`, `/etc/ssh/ssh_config`). In addition to standard SSH directives, bssh supports advanced options for certificate-based authentication and port forwarding control.
Expand Down
93 changes: 72 additions & 21 deletions docs/architecture/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,39 +74,90 @@ The configuration system uses the following core data structures:

```rust
pub struct Config {
pub clusters: HashMap<String, Cluster>,
pub default_cluster: Option<String>,
pub ssh_config: SshConfig,
pub defaults: Defaults,
pub clusters: HashMap<String, Cluster>,
pub default_cluster: Option<String>,
pub ssh_config: SshConfig,
}

pub struct Defaults {
pub user: Option<String>,
pub port: Option<u16>,
pub ssh_key: Option<PathBuf>,
pub parallel: Option<usize>,
pub jump_host: Option<String>, // Global default jump host
}

pub struct Cluster {
pub nodes: Vec<Node>,
pub ssh_key: Option<PathBuf>,
pub user: Option<String>,
pub nodes: Vec<NodeConfig>,
pub defaults: ClusterDefaults,
pub interactive: Option<InteractiveConfig>,
}

pub struct ClusterDefaults {
pub user: Option<String>,
pub port: Option<u16>,
pub ssh_key: Option<PathBuf>,
pub jump_host: Option<String>, // Cluster-level jump host
}

// Node can be simple string or detailed config
pub enum NodeConfig {
Simple(String), // "host" or "user@host:port"
Detailed {
host: String,
port: Option<u16>,
user: Option<String>,
jump_host: Option<String>, // Node-level jump host
},
}
```

### Jump Host Resolution

Jump hosts are resolved with the following priority (highest to lowest):
1. **CLI `-J` option** - Always takes precedence
2. **SSH config `ProxyJump`** - From `~/.ssh/config`
3. **Node-level config** - Per-node `jump_host` field
4. **Cluster-level config** - Cluster `defaults.jump_host`
5. **Global defaults** - Top-level `defaults.jump_host`

An empty string (`""`) explicitly disables jump host inheritance.

### Configuration File Example

```yaml
default_cluster: production

defaults:
user: admin
port: 22
ssh_key: ~/.ssh/id_rsa
jump_host: global-bastion.example.com # Default for all clusters

clusters:
production:
nodes:
- host: node1.example.com
port: 22
user: admin
- host: node2.example.com
port: 22
user: admin
ssh_key: ~/.ssh/id_rsa

staging:
nodes:
- host: staging1.example.com
- host: staging2.example.com
user: deploy
production:
nodes:
- host: node1.example.com
port: 22
user: admin
- host: node2.example.com
port: 22
user: admin
jump_host: node2-bastion.example.com # Node-specific override
ssh_key: ~/.ssh/id_rsa
jump_host: prod-bastion.example.com # Cluster-level jump host

staging:
nodes:
- host: staging1.example.com
- host: staging2.example.com
user: deploy

direct_access:
nodes:
- host: external.example.com
jump_host: "" # Explicitly disable jump host for this cluster
```

---
Expand Down
85 changes: 57 additions & 28 deletions docs/architecture/ssh-jump-hosts.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,38 +395,67 @@ bssh -H db.internal "uptime" # Uses db-gateway.example.com
- Each operation establishes fresh tunnel
- **Rationale:** russh session limitations prevent connection reuse

**YAML Configuration File Support:**
- Jump hosts via YAML cluster config not yet implemented
- Only CLI `-J` and SSH config `ProxyJump` are supported
- **Future Enhancement:** Add `jump_hosts` field to cluster configuration
### YAML Configuration File Support (Issue #115 - Implemented)

**Implementation:** `src/config/types.rs`, `src/config/resolver.rs`

Jump hosts can now be configured in the YAML configuration file at three levels:

**Configuration Levels (priority order):**
1. **Node-level** (highest) - Per-node `jump_host` field
2. **Cluster-level** - Cluster `defaults.jump_host` or inline `jump_host`
3. **Global defaults** - Top-level `defaults.jump_host`

**Example Configuration:**
```yaml
defaults:
jump_host: global-bastion.example.com

clusters:
production:
nodes:
- host: web1.internal
jump_host: special-bastion.example.com # Node-level override
- host: web2.internal # Uses cluster jump_host
- host: direct.example.com
jump_host: "" # Disabled (direct connection)
jump_host: prod-bastion.example.com # Cluster-level

direct_cluster:
nodes:
- external.example.com
jump_host: "" # Cluster disables inherited global jump_host
```

**Special Values:**
- Empty string (`""`) - Explicitly disables jump host inheritance
- Environment variables - Supports `${VAR}` and `$VAR` syntax

**Resolution Methods:**
- `config.get_jump_host(cluster_name, node_index)` - Get effective jump host for a node
- `config.get_cluster_jump_host(Some(cluster_name))` - Get cluster-level jump host

**Priority with CLI and SSH Config:**
1. CLI `-J` option (highest)
2. SSH config `ProxyJump` directive
3. YAML config (node → cluster → global)

### Future Enhancements

1. **YAML Configuration File Support:**
```yaml
clusters:
production:
jump_hosts: "bastion1.example.com,bastion2.example.com"
nodes:
- internal-host1
- internal-host2
```

2. **Jump Host Connection Pooling:**
- Reuse jump host connections across multiple target nodes
- Significant performance improvement for cluster operations
- Requires russh session lifecycle improvements

3. **Smart Timeout Calculation:**
- Measure actual round-trip times per hop
- Adjust timeouts dynamically based on observed latency
- Provide faster failures for genuinely unreachable hosts

4. **Parallel Jump Host Establishment:**
- When connecting to multiple targets through same jump hosts
- Establish jump chain once, multiplex to targets
- Reduces connection overhead for cluster operations
1. **Jump Host Connection Pooling:**
- Reuse jump host connections across multiple target nodes
- Significant performance improvement for cluster operations
- Requires russh session lifecycle improvements

2. **Smart Timeout Calculation:**
- Measure actual round-trip times per hop
- Adjust timeouts dynamically based on observed latency
- Provide faster failures for genuinely unreachable hosts

3. **Parallel Jump Host Establishment:**
- When connecting to multiple targets through same jump hosts
- Establish jump chain once, multiplex to targets
- Reduces connection overhead for cluster operations

---

Expand Down
46 changes: 46 additions & 0 deletions docs/man/bssh.1
Original file line number Diff line number Diff line change
Expand Up @@ -425,6 +425,7 @@ defaults:
port: 22
ssh_key: ~/.ssh/id_rsa
parallel: 10
jump_host: bastion.example.com # Global default jump host

# Global interactive mode settings (optional)
interactive:
Expand All @@ -443,6 +444,7 @@ clusters:
- web2.example.com
- [email protected]:2222
ssh_key: ~/.ssh/prod_key
jump_host: prod-bastion.example.com # Cluster-level jump host
# Cluster-specific interactive settings (overrides global)
interactive:
default_mode: single_node
Expand All @@ -454,8 +456,52 @@ clusters:
- host: staging1.example.com
port: 2200
user: deploy
jump_host: staging-bastion.example.com # Node-level jump host
- staging2.example.com
user: staging_user
jump_host: "" # Empty string disables jump host for this cluster
.fi

.SS Jump Host Configuration in YAML
Jump hosts can be configured at three levels with the following priority:

.IP 1. 4
\fBNode-level\fR (highest priority) - applies to specific node only
.IP 2. 4
\fBCluster-level\fR - applies to all nodes in the cluster
.IP 3. 4
\fBGlobal defaults\fR - applies to all clusters without explicit jump_host

.PP
The CLI \fB-J\fR option always takes precedence over configuration file settings.

.PP
Special values:
.IP \[bu] 2
Empty string (\fB""\fR) - explicitly disables jump host inheritance
.IP \[bu] 2
Environment variables supported: \fB${VAR}\fR or \fB$VAR\fR syntax

.PP
Example with all levels:
.nf
defaults:
jump_host: global-bastion.example.com

clusters:
production:
nodes:
- host: web1.internal
jump_host: special-bastion.example.com # Uses special-bastion
- host: web2.internal # Uses prod-bastion
- host: direct.example.com
jump_host: "" # Direct connection (no jump)
jump_host: prod-bastion.example.com

direct_cluster:
nodes:
- host: external.example.com
jump_host: "" # Cluster disables inherited global jump_host
.fi

.SH SSH CONFIGURATION OPTIONS
Expand Down
Loading