Removing UFW rule remotely through SSH

I am trying to remove UFW rules through SSH using the following bash script:

#!/bin/bash
ip=$(dig @resolver4.opendns.com myip.opendns.com +short)
sshpass -p 'password' ssh -tt -p 22 root@192.168.1.20 ufw show added | awk -v ipm="$ip" '$0 ~ ipm{ gsub("ufw","ufw delete",$0); system($0)}'

It connects successfully on the remote host but somehow the command

ufw show added | awk -v ipm="$ip" '$0 ~ ipm{ gsub("ufw","ufw delete",$0); system($0)}'

is not executed correctly because I receive the following error:

Connection to 192.168.1.20 closed. 'RROR: Bad port '3306 The IP is whitelisted only for port 3306.

I assume it gives this error because I use sshpass utility On the host it works perfectly. Somehow the UFW rule to remove the IP is not interpreted correctly through ssh. I don’t know how to debug this. Thanks!

You are seeing lots of nasty subshell quoting issues. If possible avoid sshpass. Instead configure password less ssh key login for root. This should help solve your problem.

I am aware of the security risks using sshpass. I want to make the bash script work with sshpass. Thanks for reply.

This is the best I think might work provided that ip you want is for 192.168.1.20 as we are running everything after connection:

sshpass -p 'password' ssh -t -p 22 root@192.168.1.20<<-\SSH
  ip=$(dig @resolver4.opendns.com myip.opendns.com +short)
  ufw show added > /tmp/rules 
  awk -v ipm="$ip" '$0 ~ ipm{ gsub("ufw","ufw delete",$0); system($0) }' /tmp/rules
  rm /tmp/rules 
  exit
SSH

I don’t have ufw to test. So test in dev environment.

The only part of the script which is not executed is the awk removal command. The file rules shows only the rules from UFW but not the awk command which removes the IP.

P.S: I do not know if this message Pseudo-terminal will not be allocated because stdin is not a terminal. is something good or bad.

it means $ip/ipm not matching. Do you see your ip when you run the command (replace original awk with this one)?

echo | awk -v ipm="$ip" '{ print ipm}'

If not, look into ip=$(dig @resolver4.opendns.com myip.opendns.com +short)

The echo command prints the IP address of the remote server.

The concept of the script should be like this:

A - local machine
B- remote host

I am getting the IP address with dig command from A and remove it through ssh from B.

I am pretty sure this sorts out your issue as we are getting local ip and building that in a script. Once script is locally build, we upload it to the remote and execute it.

#!/bin/bash
# set variables
payload="/tmp/ufwscript"
# ssh login for remote
s_server="192.168.2.25"
s_user="root"
password='password'

# get the current local ip
ip=$(dig @resolver4.opendns.com myip.opendns.com +short)

# init 
echo "DEBUG: Local ip $ip. Local shell script $payload."

echo '#!/bin/bash' > "$payload"
echo "export ip='$ip'" >> "$payload"
cat <<'EOF'>> "$payload"
  ufw show added | awk -v ipm="$ip" '$0 ~ ipm{ gsub("ufw","ufw delete",$0); system($0) }'
EOF
chmod +x "$payload"

echo "DEBUG: Sending script $payload to ${s_user}@${s_server}" 

# upload the script to remote and exec it
sshpass -p "$password" scp "$payload" ${s_user}@${s_server}:/tmp/
sshpass -p "$password" ssh -tt -p 22 ${s_user}@${s_server} bash -c "$payload; rm -v $payload"
1 Like

Great approach! It works like a charm! Thank you so much for helping me!

Ansilbe got UFW model and you can give root password in it.

I agree, Ansible would be better, but OP wanted shell script.


Linux sysadmin blog - Linux/Unix Howtos and Tutorials - Linux bash shell scripting wiki