-
-
Save Zorono/0cc865097d3e6548d39adb0e74b95048 to your computer and use it in GitHub Desktop.
This file contains 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 | |
# | |
# Author: Peter Maloney | |
# License: GPLv2 | |
backed_up=false | |
now=$(date +%s) | |
file=/etc/ssh/sshd_config | |
support_applications=() | |
pubkeyonly=false | |
update=false | |
dry_run=false | |
while [ "$#" != 0 ]; do | |
if [ "$1" = "-f" ]; then | |
file="$2" | |
shift | |
elif [ "$1" = "-n" -o "$1" = "--dry-run" ]; then | |
dry_run=true | |
elif [ "$1" = "-u" ]; then | |
update=true | |
elif [ "$1" = "-a" ]; then | |
shift | |
support_applications=($(echo "$1" | tr ',' ' ')) | |
elif [ "$1" = "-p" ]; then | |
pubkeyonly=true | |
else | |
echo "ERROR: unknown option: $1" | |
exit 1 | |
fi | |
shift | |
done | |
do_backup() { | |
if [ "$backed_up" = false ]; then | |
echo "INFO: doing backup" | |
cp "${file}" "${file}.backup.${now}" | |
backed_up=true | |
fi | |
} | |
# for each of these, comment out the line in the config | |
# regex must match a whole line with "^" and "$" added by this function. | |
disable_config() { | |
regex="$1" | |
# DSA is 1024 bits... obsolete long ago | |
#HostKey /etc/ssh/ssh_host_dsa_key | |
# ecdsa uses NIST... weak prng | |
#HostKey /etc/ssh/ssh_host_ecdsa_key | |
line=$(grep -E "^${regex}$" "$file") | |
if [ -n "$line" ]; then | |
if [ "$dry_run" = true ]; then | |
echo "INFO: (DRY RUN) disabling: $line" | |
else | |
do_backup "$file" | |
echo "INFO: disabling: $line" | |
sed -i -r "s|^(${regex})$|#\1|" "$file" | |
fi | |
else | |
echo "INFO: config matching regex \"$regex\" is already disabled" | |
fi | |
} | |
# Append the config if it isn't already in config. If it's there but different value, warn. | |
append_config() { | |
line="$1" | |
first_col=$(awk '{print $1}' <<< "$line") | |
if ! grep -Eq "^[ \t]*${first_col}" "$file"; then | |
if [ "$dry_run" = true ]; then | |
echo "INFO: (DRY RUN) modifying config... adding $line" | |
else | |
do_backup "$file" | |
echo "INFO: modifying config... adding $line" | |
echo "$line" >> "$file" | |
fi | |
elif [ "${first_col}" != "HostKey" ]; then | |
old_content=$(grep -E "^[ \t]*${first_col}" "$file") | |
if [ -n "$old_content" -a "$old_content" != "$line" ]; then | |
if [ "$update" = true ]; then | |
if [ "$dry_run" = true ]; then | |
echo "INFO: (DRY RUN) modifying config... updating $line" | |
else | |
do_backup "$file" | |
echo "INFO: modifying config... updating $line" | |
sed -i "s|${old_content}|$line|" "$file" | |
fi | |
else | |
echo "WARNING: old config has the config option but content does not match (use -u to update anyway):" | |
echo "- $old_content" | |
echo "+ $line" | |
return 1 | |
fi | |
fi | |
echo "INFO: config is already set: $line" | |
fi | |
} | |
# example versions seen by ssh -V | |
# Ubuntu 12.04.5 LTS | |
# OpenSSH_5.9p1 Debian-5ubuntu1.10, OpenSSL 1.0.1 14 Mar 2012 | |
# Ubuntu 14.04.5 LTS | |
# OpenSSH_6.6.1p1 Ubuntu-2ubuntu2.8, OpenSSL 1.0.1f 6 Jan 2014 | |
# Ubuntu 16.04.2 LTS | |
# OpenSSH_7.2p2 Ubuntu-4ubuntu2.2, OpenSSL 1.0.2g 1 Mar 2016 | |
match_version() { | |
local version=$(ssh -V 2>&1 | awk '{print $1}' | grep -Eo "[0-9]+\.[0-9]+") | |
local major="${version%.*}" | |
local minor="${version#*.}" | |
if [ "$major" -gt "7" ]; then | |
echo "7.3" | |
elif [ "$major" -ge "7" ]; then | |
if [ "$minor" -ge "3" ]; then | |
echo "7.3" | |
elif [ "$minor" -ge "2" ]; then | |
echo "7.2" | |
else | |
echo "6.5" | |
fi | |
elif [ "$major" -ge "6" ]; then | |
if [ "$minor" -ge "5" ]; then | |
echo "6.5" | |
else | |
echo "5.9" | |
fi | |
else | |
echo "5.9" | |
fi | |
} | |
restart_sshd() { | |
echo "INFO: restarting sshd" | |
if [ -e /etc/init.d/sshd -o -e /lib/systemd/system/sshd.service ]; then | |
service sshd restart | |
elif [ -e /etc/init.d/ssh -o -e /lib/systemd/system/ssh.service ]; then | |
service ssh restart | |
else | |
service ssh restart || service sshd restart | |
fi | |
return $? | |
} | |
# ======================================================================================= | |
# Main | |
# ======================================================================================= | |
support_version=$(match_version) | |
echo "INFO: supporting version $support_version" | |
# =========================== | |
# handling applications | |
# =========================== | |
array_to_csv() { | |
str=$(echo "$@" | tr ' ' '\n' | sort -u | xargs echo | tr ' ' ',') | |
if [ -n "$str" ]; then | |
echo ",${str}" | |
fi | |
} | |
more_kex=() | |
more_macs=() | |
for application in "${support_applications[@]}"; do | |
if [ "$application" = "paramiko" ]; then | |
more_kex+=("diffie-hellman-group-exchange-sha256") | |
more_macs+=("hmac-sha2-512") | |
elif [ "$application" = "jsch" ]; then | |
more_kex+=("diffie-hellman-group-exchange-sha256") | |
more_macs+=("hmac-sha2-256") | |
fi | |
done | |
more_kex_str=$(array_to_csv "${more_kex[@]}") | |
more_macs_str=$(array_to_csv "${more_macs[@]}") | |
echo "INFO: supporting applications = ${support_applications[@]}, with more_kex_str = \"${more_kex_str}\", more_macs_str = \"${more_macs_str}\"" | |
# =========================== | |
# applying config | |
# =========================== | |
disable_config "HostKey .*ssh_host_dsa_key" | |
disable_config "HostKey .*ssh_host_ecdsa_key" | |
# at least one of these is required or ssh automatically enables all, including the insecure DSA (except with 7.2 and HostKeyAlgorithms set) | |
append_config "HostKey /etc/ssh/ssh_host_rsa_key" | |
if [ "$pubkeyonly" = true ]; then | |
append_config "PasswordAuthentication no" | |
append_config "ChallengeResponseAuthentication no" | |
append_config "PubkeyAuthentication yes" | |
# NOTE: we aren't changing "UsePAM" which has some influence on password auth, and "PermitRootLogin" which ought to be either no or prohibit-password (which can be pubkey related), but we don't check | |
fi | |
# our goal is: | |
# - enable the new good stuff from the newest versions | |
# - enable the minimal stuff to be compatible with 6.5 clients | |
# - enable the 5.9 and older stuff only on server versions that old | |
if [ "$support_version" = "7.3" ]; then | |
#on newer machines (7.3) (still compatible with 6.5, but not 5.9): | |
append_config "KexAlgorithms curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512,diffie-hellman-group14-sha256${more_kex_str}" | |
append_config "Ciphers aes256-gcm@openssh.com,aes256-ctr,chacha20-poly1305@openssh.com" | |
append_config "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com${more_macs_str}" | |
append_config "HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa" | |
elif [ "$support_version" = "7.2" ]; then | |
#on newer machines (7.2) (still compatible with 6.5, but not 5.9): | |
append_config "KexAlgorithms curve25519-sha256@libssh.org${more_kex_str}" | |
append_config "Ciphers aes256-gcm@openssh.com,aes256-ctr,chacha20-poly1305@openssh.com" | |
append_config "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com${more_macs_str}" | |
append_config "HostKeyAlgorithms ssh-ed25519-cert-v01@openssh.com,ssh-rsa-cert-v01@openssh.com,ssh-ed25519,ssh-rsa" | |
elif [ "$support_version" = "6.5" ]; then | |
#on older machines (6.5): | |
append_config "KexAlgorithms curve25519-sha256@libssh.org${more_kex_str}" | |
append_config "Ciphers aes256-gcm@openssh.com,aes256-ctr,chacha20-poly1305@openssh.com" | |
append_config "MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com${more_macs_str}" | |
elif [ "$support_version" = "5.9" ]; then | |
#on older machines (5.9) (has ssh-audit warnings): | |
append_config "KexAlgorithms diffie-hellman-group14-sha1${more_kex_str}" | |
append_config "Ciphers aes256-ctr" | |
append_config "MACs hmac-sha2-256,hmac-sha2-512${more_macs_str}" | |
else | |
echo "ERROR: invalid support version: $support_version" | |
fi | |
if [ "$backed_up" = true ]; then | |
if ! restart_sshd; then | |
echo "ERROR: sshd failed with new config... reverting to backup" | |
mv "${file}" "${file}.failed.${now}" | |
mv "${file}.backup.${now}" "${file}" | |
if ! restart_sshd; then | |
echo "ERROR: uh oh... old config doesn't work either" | |
fi | |
fi | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment