Skip to content

Instantly share code, notes, and snippets.

@syonfox
Created January 28, 2023 01:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save syonfox/bf51638d0e7b28148264b326e1ca4720 to your computer and use it in GitHub Desktop.
Save syonfox/bf51638d0e7b28148264b326e1ca4720 to your computer and use it in GitHub Desktop.
Managing your SSH config can be a hassle, but with the new lib_ssh_config library, it's never been easier. This powerful library allows you to create, delete, and add hosts to your SSH config file with just a few simple commands. With built-in safety features like automatic backups and user prompts, you can rest easy knowing your data is safe. I…
#!/bin/bash
########################################################################################################################
# This function will check if the ssh config file located at ~/.ssh/config exists. If it does not exist, it will create
# it and write some default content and settings to it. It will also set the correct permissions for the ssh config file
# to be user readable and writable, but not writable by others (700 for the .ssh directory, and 600 for the config file).
# This function can be used to initialize a new ssh config file if one doesn't already exist, or to reset the config file
# to default settings.
########################################################################################################################
#A function to initialize an ssh config file with basic settings and permissions
#Inputs: None
#Outputs: None, creates or modifies a file at ~/.ssh/config with basic settings and permissions
#Side Effects: creates or modifies a file at ~/.ssh/config, creates a directory at ~/.ssh if it doesn't exist
########################################################################################################################
function ssh_config_init() {
# check if ssh config file exists
if [ -f ~/.ssh/config ]; then
read -p "Config already exists, do you want to delete it? (y/n) " choice
case "$choice" in
y|Y ) rm ~/.ssh/config;;
n|N ) echo "Aborting config initialization."; return;;
* ) echo "Invalid input. Aborting config initialization."; return;;
esac
fi
touch ~/.ssh/config
chmod 700 $HOME/.ssh
chmod 600 $HOME/.ssh/config
cat >> ~/.ssh/config << EOF
# SSH Config configuration details https://www.ateam-oracle.com/post/simplify-your-day-with-ssh-config-file-entries-and-self-closing-tunnels
#
# Host, an alias for the entry
# User, the expected and always present opc user
# Hostname, the address to the host you want to connect to
# Port, the ssh port
# IdentityFile, the location of your private keyfile
# UseKeychain, if your ssh key have a password you only need to enter it the first time and then it will be saved in the macos keychain or Gnome keyring
# ProxyJump, describes the chain of hosts to connect via (jump through) to get to the remote host. Multiple hosts can be specified separated by a comma. ProxyJump is a simplification of the older ProxyCommand.
# LocalForward, the directive on what port to forward to your local machine from the remote host.
# ie. LocalForward 9906 127.0.0.1:3306 # This will forward all local port 9906 traffic to port 3306 on the remote database.example.com server,
# letting me point my desktop GUI to localhost (127.0.0.1:9906) and have it behave exactly as if I had exposed port 3306 on the remote server
# and connected directly to it.
# $HOME/.ssh/config
#
# Permissions: User R/W, NOT Writable by others
# chmod 700 $HOME/.ssh
# chmod 600 $HOME/.ssh/config
# First some generic settings that applies to all specific hosts below unless specified otherwise
Host *
IdentityFile ~/.ssh/id_rsa
ServerAliveInterval 240
ServerAliveCountMax 2
TCPKeepAlive yes
# Examples of additional settings:
# Host myserver
# Hostname example.com
# Port 22
# User myusername
# IdentityFile ~/.ssh/id_rsa_myserver
# ServerAliveInterval 240
# ServerAliveCountMax 2
# TCPKeepAlive yes
# UseKeychain yes
EOF
}
########################################################################################################################
#This function is used to delete a specific "Host" block in the ssh config file, based on the provided hostname.
#It first creates a backup of the original config file to ensure data safety, then creates a new config file with
#the desired "Host" block removed, and finally overwrites the original config file with the new config file.
#Inputs:
#host_name (string): the name of the host to delete from the ssh config file
#Outputs:
#None, creates a new file at ~/.ssh/config.new with the host removed and backs up the original file to ~/.ssh/config.bak
#Side Effects:
#Modifies the original ssh config file by creating a new file with the host removed and backing up the original file
########################################################################################################################
ssh_config_delete_host() {
if [ -z "$1" ]; then
echo "Error: hostname not provided."
return
fi
host_name=$1
if [ -f ~/.ssh/config ]; then
cp ~/.ssh/config ~/.ssh/config.$(date +%FT%T).bak
awk '
/^Host $host_name$/ {
while (getline && $0 !~ /^Host/) {}
}
{ print }
' ~/.ssh/config > ~/.ssh/config.new
mv ~/.ssh/config.new ~/.ssh/config
else
echo "Error: ssh config file not found"
fi
}
########################################################################################################################
# This function is used to delete a specific "Host" block in the ssh config file. It first makes a backup of the original
# config file to config.data.bak, then creates a new config file with the desired "Host" block removed, and finally
# overwrites the original config file with the new config file.
#A function to delete a specific host from an ssh config file
#Inputs: host_name, the name of the host to delete from the ssh config file
#Outputs: None, creates a new file at ~/.ssh/config.new with the host removed and backs up the original file to ~/.ssh/config.bak
#Side Effects: modifies the original ssh config file by creating a new file with the host removed and backing up the original file
########################################################################################################################
ssh_config_delete_host() {
if [ -z "$1" ]; then
echo "Error: host_name argument not set"
return
fi
host_name="$1"
if [ -f ~/.ssh/config ]; then
cp ~/.ssh/config ~/.ssh/config.$(date +%FT%T).bac
awk -v host_name="$host_name" '
$1 == "Host" && $2 == host_name {
while (getline && $0 !~ /^Host/) {}
}
{ print }
' ~/.ssh/config > ~/.ssh/config.new
mv ~/.ssh/config.new ~/.ssh/config
else
echo "Error: ssh config file not found"
fi
}
########################################################################################################################
# Append a host to the sshconfig with
# inputs: hostname user ip port port1 port2 ...portn with each port allowing a singler number or remote:local
# out`puts: appends ssh config and creates it if necessary, if there is already a config with the hostname ask user if they want overwrite rename or cancel
# after this is ran you should be able to run ssh hostname.
# @example ssh_config_host goat root 1.2.3.4 4222 5432 80:6047 3000 proxy1 proxy2 proxyn 1234:2222
#
########################################################################################################################
ssh_config_add_host() {
# assign input variables
host_name=$1
user=$2
ip=$3
port=$4
args=("${@:5}")
# check if ssh config file exists
if [ ! -f ~/.ssh/config ]; then
ssh_config_init
fi
# check if hostname already exists in ssh config
if grep -q "^Host $host_name" ~/.ssh/config; then
# prompt user to overwrite, rename, or cancel
read -p "Host $host_name already exists in ssh config. Overwrite, rename, or cancel? [o/r/c] " choice
case $choice in
o)
# overwrite existing hostname
ssh_config_delete_host $host_name
;; #it deletes the entire block of the ssh config for the hostname passed as an argument. It doesn't delete only the first line but the entire block of configs for that hostname.
r)
# prompt user for new hostname
read -p "Enter new hostname: " new_hostname
host_name=$new_hostname
;;
c)
# cancel operation
echo "Cancelled operation."
return
;;
esac
fi
echo "Host $host_name" >> ~/.ssh/config
echo " User $user" >> ~/.ssh/config
echo " HostName $ip" >> ~/.ssh/config
echo " Port $port" >> ~/.ssh/config
# append ports
for arg in "${args[@]}"; do
echo "handeling remaining arg: $arg"
if [[ $arg =~ ^[0-9]+([:][0-9]+)?$ ]]; then
local_port=$(echo $arg | cut -d: -f1)
remote_port=$(echo $arg | cut -d: -f2)
echo "Valid number or number:number format $local_port -> $remote_port"
echo " LocalForward $host_name:$local_port localhost:$remote_port" >> ~/.ssh/config
# echo "Valid number or number:number format"
# echo " LocalForward $host_name:$local_port localhost:$remote_port" >> ~/.ssh/config
else
echo "Invalid number or number:number format assuming this is a proxyJump definitions"
echo " ProxyJump $arg" >> ~/.ssh/config
fi
done
#todo make sure the proxyJump is valid.
# if [[ $1 =~ ^[a-zA-Z0-9_]+@[a-zA-Z0-9_]+([:][0-9]+)?$ ]]; then
# echo "Valid ProxyJump"
# else
# echo "Invalid ProxyJump"
# fi
#
# if ssh -q -o ConnectTimeout=5 -o BatchMode=yes -o StrictHostKeyChecking=no -o ProxyJump="$1" -o LogLevel=ERROR exit; then
#
# echo "Valid ProxyJump"
#
# else
#
# echo "Invalid ProxyJump"
#
# fi
}
function test_lib_ssh_config() {
mv ~/.ssh/config ~/.ssh/config.test.bac
# Initialize the ssh config file
ssh_config_init
cat ~/.ssh/config
# Add some hosts to the ssh config file
ssh_config_add_host "host1" "user" "host1.com" 22
cat ~/.ssh/config
ssh_config_add_host "host2" "user" "host2.com" 4222 host1
cat ~/.ssh/config
ssh_config_add_host "host3" "user" "host3.com" 4222 5432 88:8888
cat ~/.ssh/config
# Delete a host from the ssh config file
ssh_config_delete_host "host2"
cat ~/.ssh/config
ssh_config_add_host "host3" "user" "host3.com" 4222 5432 "host2" 55:1234 host1
# Confirm that the host was deleted
cat ~/.ssh/config
mv ~/.ssh/config.test.bac ~/.ssh/config
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment