Last active
October 3, 2025 03:43
-
-
Save jpalala/77414a580aadd9891b2cbda3a05dea3d to your computer and use it in GitHub Desktop.
Simple helper to SSH into private VPC hosts via a bastion jump server.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
# bastion-connector.sh | |
# Simple helper to SSH into private VPC hosts via a bastion jump server. | |
# Usage: | |
# ./bastion-connector.sh <TARGET_PRIVATE_IP> [USERNAME] | |
# | |
# Example: | |
# ./bastion-connector.sh 10.15.3.42 ubuntu | |
# ./bastion-connector.sh 10.15.7.10 root | |
# --- Configurable Variables --- | |
BASTION_HOST="bastion.vpc.example.com" # Change to your real bastion hostname/IP | |
TARGET_IP="$1" | |
TARGET_USER="${2:-ubuntu}" # Default username if not provided | |
# --- Validation --- | |
if [ -z "$TARGET_IP" ]; then | |
echo "Usage: $0 <TARGET_PRIVATE_IP> [USERNAME]" | |
exit 1 | |
fi | |
echo "🔌 Connecting to $TARGET_IP via bastion $BASTION_HOST ..." | |
ssh -J "$TARGET_USER@$BASTION_HOST" "$TARGET_USER@$TARGET_IP" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# ============================================================================== | |
# SSH History Selection Utility (ssh_history.sh) | |
# | |
# This script reads the user's bash history, filters for SSH connections, | |
# and presents a unique list in an interactive numbered menu for selection. | |
# | |
# Dependencies: grep, awk, tac, uniq (standard Unix utilities) | |
# ============================================================================== | |
# Define the history file path. Adjust this if you use zsh (~/.zsh_history). | |
HISTORY_FILE="$HOME/.bash_history" | |
# --- Setup and Filtering --- | |
if [ ! -f "$HISTORY_FILE" ]; then | |
echo "Error: History file not found at $HISTORY_FILE" >&2 | |
exit 1 | |
fi | |
# 1. Generate the unique, reversed list of hosts and store it in a temporary variable. | |
HOST_LIST=$(grep -h "^ssh " "$HISTORY_FILE" | | |
awk '{print $2}' | | |
tac | | |
uniq) | |
# Check if any SSH hosts were found | |
if [ -z "$HOST_LIST" ]; then | |
echo "No unique SSH commands found in history." | |
exit 0 | |
fi | |
# 2. Convert the newline-separated list into a Bash array. | |
readarray -t HOST_ARRAY <<< "$HOST_LIST" | |
echo "--- Select SSH Host (Enter the number, or 'q' to quit) ---" | |
echo "" | |
# --- Interactive Selection using 'select' --- | |
# PS3 is the prompt string for the select loop | |
PS3='Enter number to connect or "q" to quit: ' | |
# 'select host_choice in "${HOST_ARRAY[@]}"' creates a numbered menu. | |
# The selected value is stored in 'host_choice'. | |
select host_choice in "${HOST_ARRAY[@]}" "Quit"; do | |
# If the user selected an item (host_choice is not empty) | |
if [[ -n "$host_choice" ]]; then | |
if [[ "$host_choice" == "Quit" ]]; then | |
echo "Selection cancelled." | |
break # Exit the select loop | |
fi | |
# 4. Connect to the selected host by replacing the current shell process with SSH | |
echo "Connecting to: $host_choice..." | |
# Use 'exec' so when SSH exits, the script exits immediately without | |
# returning to the 'select' loop or requiring another 'break'. | |
exec ssh "$host_choice" | |
# Handle invalid input (e.g., entering text or an invalid number) | |
else | |
echo "Invalid selection. Please enter a number from the list or 'q' to quit." | |
fi | |
done | |
echo "" | |
echo "-----------------------------------------------------" | |
exit 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
import re | |
import subprocess | |
import sys | |
def get_ssh_history(): | |
"""Reads ~/.bash_history and extracts unique SSH host strings.""" | |
# NOTE: This assumes Bash history. Adjust for Zsh (~/.zsh_history) if needed. | |
history_file = os.path.expanduser("~/.bash_history") | |
# Regex to capture the host part of an SSH command: 'ssh user@host [options]' | |
SSH_REGEX = re.compile(r"^\s*ssh\s+([^-@\s]+(?:@\S+)?)") | |
hosts = [] | |
try: | |
# Read history file in reverse (newest first) | |
with open(history_file, 'r') as f: | |
for line in reversed(f.readlines()): | |
match = SSH_REGEX.search(line) | |
if match: | |
host_string = match.group(1).split()[0] # Take only the first word after 'ssh' | |
# Deduplicate the list | |
if host_string not in hosts: | |
hosts.append(host_string) | |
except FileNotFoundError: | |
print(f"Error: History file not found at {history_file}", file=sys.stderr) | |
sys.exit(1) | |
return hosts | |
def run_fzf_selection(hosts): | |
"""Pipes the list of hosts to fzf and returns the selected host.""" | |
if not hosts: | |
print("No SSH commands found in history.", file=sys.stderr) | |
return None | |
try: | |
# 1. Join hosts with newlines for piping | |
input_data = "\n".join(hosts) | |
# 2. Call fzf via subprocess | |
# --no-sort ensures the history order (newest first) is maintained | |
# --prompt sets a helpful prompt text | |
process = subprocess.run( | |
['fzf', '--no-sort', '--prompt=Select SSH Host: '], | |
input=input_data, | |
capture_output=True, | |
text=True, | |
check=True # Raise an exception for non-zero exit codes (e.g., fzf not installed) | |
) | |
# fzf prints the selected line to stdout | |
return process.stdout.strip() | |
except FileNotFoundError: | |
print("Error: 'fzf' is not installed or not in your PATH.", file=sys.stderr) | |
print("Please install fzf (e.g., 'brew install fzf' or 'sudo apt install fzf').", file=sys.stderr) | |
sys.exit(1) | |
except subprocess.CalledProcessError: | |
# User canceled fzf (e.g., pressed Esc) | |
sys.exit(0) | |
def main(): | |
history_hosts = get_ssh_history() | |
selected_host = run_fzf_selection(history_hosts) | |
if selected_host: | |
print(f"Connecting to: {selected_host}...") | |
# Crucial step: Use os.execvp to replace the current Python process | |
# with the SSH process, passing control to the SSH client. | |
try: | |
os.execvp("ssh", ["ssh", selected_host]) | |
except FileNotFoundError: | |
print("Error: 'ssh' command not found.", file=sys.stderr) | |
sys.exit(1) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment