ssh proxy
4 TopicsSSH forward proxy
Is it possible to use a single Virtual Server to proxy multiple connections to back end servers. I was considering whether it would be possible to read the hostname in the SSH stream or other identifying information to direct the SSH session to the correct server. The other alternative is port multiplexing eg server 1 connects to virtual server 10.0.0.15:4567 server2 connects on 10.0.0.15:4568 etc. Thanks for an helpSolved153Views0likes8CommentsSSH Brute Force Protection with SSH Proxy
This script is designed to add brute force protection for SSH services on a virtual server. It makes use of the Protocol Security feature called SSH Proxy which makes it possible to look into the ssh session and see the actual logon results. Documentation for setting up SSH Proxy can be found here: https://techdocs.f5.com/en-us/bigip-14-1-0/big-ip-network-firewall-policies-and-implementations-14-1-0/ssh-proxy-security.html The script basically looks in the ltm log for these lines: Jun 8 11:40:57 f5-01 info tmm[12656]: 23003164 "Jun 08 2025 11:40:57","ssh_serverside_auth_fail","10.1.0.2","10.10.9.64","49862","22","4092","TCP","root","Password authentication failure" and counts the number of failed attempts for each IP. When a threshold has been reached that IP goes into a AFM address-list. This address-list needs to be part of a rule and policy, and attached to the SSH VS. This way be can block access for that source. The name of the address-list is specified in a variable in the script, so you can adjust it easily for your needs. You should use iCall to run the script periodically: sys icall script ssh_bf { app-service none definition { exec /shared/scripts/ban_failed_ssh.sh > /var/log/ssh_log.log } description none events none } sys icall handler periodic ssh_bf { interval 300 script ssh_bf } Make sure that the location of the script matches the exec statement in the iCall script, and that the script is executable. If you are having an HA, you also need to make sure you have it on both units. You can consume the above config by running this command: tmsh load sys config merge from-terminal and simply paste it in and on an empty line hit CTRL-d. Next you need to have a logging profile configured with these settings: It is important you have that particular publisher set as it is sending the failures to the ltm log. You should be aware of the limitations of logging locally before you make use of this solution. If it is a very busy unit the disk might not be happy with some extra writing. In a perfect world you could log these failures to a remote logging server, but then you need to have the counting logic running elsewhere and have the script use the API to ingest the IPs. Or make use of a IP Intelligence feed which can load the IPs from a webserver. This is however out of scope for this solution, but I might make a follow up article on this if time allows it. With the AFM policy on the SSH VS and the logging profile attached, you now only need to save this script to your favorite script location on the BigIP: #!/bin/bash # # ban_failed_ssh.sh - Detect and ban IPs with repeated SSH login failures from /var/log/ltm # # This script uses AFM address lists and maintains a state file with banned IPs and expiry timestamps. # Author: Thomas Domingo Dahlmann # # --- Configuration --- LOG_FILE="/var/log/ltm" STATE_FILE="/var/tmp/ssh_ban_state.csv" AFM_ADDR_LIST="/Common/ssh_banned_ips" DUMMY_IP="192.0.2.254" BAN_THRESHOLD=3 BAN_WINDOW_SECONDS=300 # 5 minutes BAN_DURATION_SECONDS=1800 # 1 hour TMP_LOG="/var/tmp/ssh_ban_tmp.log" DEBUG=1 # Set to 1 for verbose debug logging, 0 to disable # --- Logging helper --- log_debug() { [[ "$DEBUG" -eq 1 ]] && echo "[DEBUG] $(date '+%F %T') - $*" >&2 } # --- Ensure state file and dummy IP exists --- ensure_state_file() { touch "$STATE_FILE" if ! grep -q "^$DUMMY_IP," "$STATE_FILE"; then echo "$DUMMY_IP,9999999999" >> "$STATE_FILE" log_debug "Adding dummy IP $DUMMY_IP to state file and AFM list" tmsh modify security firewall address-list "$AFM_ADDR_LIST" { addresses add { "$DUMMY_IP" } } 2>/dev/null else log_debug "Dummy IP $DUMMY_IP already present in state" fi } # --- Remove expired IPs from state and AFM --- cleanup_expired_bans() { local now now=$(date +%s) local new_state=() log_debug "Cleaning up expired bans at epoch time $now" while IFS=',' read -r ip expiry; do [[ -z "$ip" || -z "$expiry" ]] && continue if [[ "$ip" == "$DUMMY_IP" ]]; then new_state+=("$ip,9999999999") continue fi if (( expiry > now )); then log_debug "Keeping active ban for $ip (expires at $expiry)" new_state+=("$ip,$expiry") else log_debug "Unbanning expired IP $ip (expired at $expiry)" tmsh modify security firewall address-list "$AFM_ADDR_LIST" { addresses delete { "$ip" } } 2>/dev/null fi done < "$STATE_FILE" printf "%s\n" "${new_state[@]}" > "$STATE_FILE" log_debug "State file rewritten with ${#new_state[@]} active entries" } # --- Add or update ban for IP --- ban_ip() { local ip=$1 local expiry=$(( $(date +%s) + BAN_DURATION_SECONDS )) log_debug "Initiating ban for IP $ip until $(date -d "@$expiry") [$expiry]" # Remove old entry grep -v "^$ip," "$STATE_FILE" > "${STATE_FILE}.tmp" && mv "${STATE_FILE}.tmp" "$STATE_FILE" log_debug "Removed previous entry for $ip (if any)" # Add new ban echo "$ip,$expiry" >> "$STATE_FILE" log_debug "Added $ip,$expiry to $STATE_FILE" # Add to AFM list tmsh modify security firewall address-list "$AFM_ADDR_LIST" { addresses add { "$ip" } } 2>/dev/null log_debug "Added IP $ip to AFM address list $AFM_ADDR_LIST" } # --- Check recent log entries for violations --- check_for_new_violations() { local now start_epoch now=$(date +%s) start_epoch=$(( now - BAN_WINDOW_SECONDS )) log_debug "Checking for new violations between $start_epoch and $now" > "$TMP_LOG" awk -v threshold="$start_epoch" ' match($0, /"([A-Z][a-z]{2} [ 0-9][0-9] [0-9]{4} [0-9]{2}:[0-9]{2}:[0-9]{2})","ssh_.*auth_fail","([0-9]+\.[0-9]+\.[0-9]+\.[0-9]+)"/, m) { cmd = "date -d \"" m[1] "\" +%s" cmd | getline epoch close(cmd) if (epoch >= threshold) { print epoch, m[2] } } ' "$LOG_FILE" > "$TMP_LOG" log_debug "Parsed entries written to $TMP_LOG:" [[ "$DEBUG" -eq 1 ]] && cat "$TMP_LOG" >&2 awk '{count[$2]++} END { for (ip in count) if (count[ip] >= '"$BAN_THRESHOLD"') print ip }' "$TMP_LOG" | while read -r ip; do log_debug "Found IP with threshold violations: $ip" if grep -q "^$ip," "$STATE_FILE"; then log_debug "IP $ip already in state file, skipping ban" else ban_ip "$ip" fi done } # --- Main --- log_debug "==== SSH Ban Monitor Started ====" ensure_state_file cleanup_expired_bans check_for_new_violations log_debug "==== SSH Ban Monitor Finished ====" Happy hunting 😄64Views1like0CommentsSSH Proxy - What do I need?
Greetings and thank you for your time. I have a server with an application which uses SSH to communicate with clients. That server can't be updated and presents vulnerabilities in the way it communicates with clients. I need to proxy that service on Big IP and be able to select/restrict ciphers and such so the security scans are clean. I do not need all the functionality of per-user control and such of the SSH_Proxy feature, just a proxy of the SSH connectivity so that proper security is presented client side while keeping the server side "insecure". My questions: Do I need AFM to do this or can this be done strictly through LTM? I watched the F5 Wednesday Whiteboard video on SSH proxy and it mentions that the initial handshake is done from client to server directly and that BigIP kicks in as a man-in-the-middle afterwards. Wouldn't that defeat my requriement of presenting a clean security exchange with the client? Can client authentication (simple username/password, no client cert) be passed through to the backend server or does the SSH user authenticate to BigIP? Essentially I'm looking for a way to do a simply proxy termination for an SSH service with the capability of presenting different ciphers to the client than those received from the server. I don't need to look inside the SSH stream. What would be the best way to accomplish that? Thank you much :) Ben479Views0likes1CommentLimit text-copy in SSHproxy
I have suggested to my employer, that we use SSHproxy in AFM to access network managment tools and devices, instead of the current 2xRDP via jumpstations and then SSH via SecureCRT, but the Security Officer says no on the basis that you could paste files into a text-editor on the receiving end and that way transfer files. Is there a way to limit the amount of data that can be transferred that way? I can see that it is possible to apply an iRule, so perhaps something is possible that way? My suggested setup is: client --vpn--> mgmt-net --> SSHproxy --> mgmt-server --> network-equipment.304Views0likes2Comments