How to Add an Additional Layer of Security to your Services
This is a small addition to the previous guide I had created earlier.
The previous guide showed how you can add a iptables firewall that will work with your docker containers, while it may not seem complicated, and really it isn’t, it does take a little bit of reading and understanding for it to “click”, at least it did for me.
What this modification will do is modify your iptables rules to allow a dynamic IP to only be allowed access to your secure services. This may not be ideal for everyone, but for me it works great, since I can set it to my home IP address. This means I can only connect via SSH and the docker service via Portainer.
You may say, how do you connect if you are not at home? Well I just VPN to my home connection and then connect to my secure services.
Also if your looking for a way to securely connect to your docker service remotely, check out this awesome guide.
Step 1: Only a Minor Modification Needed
So there only needs to be a minor modification needed to start off.
For simplicity sake, I am going to assume you already have dynamic IP setup for your home, or where ever it is you want to setup access.
The script that we will use to detect our dynamic IP will use the host
command. If you are using Debian, which is my flavour of server, you may need to install dnsutils
. It can be installed with apt install dnsutils
.
Find out what your current IP is as you will need it to modify the iptables config file /etc/iptables.conf
that was created in the prior guide.
*filter
:INPUT ACCEPT [0:0]
:FORWARD DROP [0:0]
:OUTPUT ACCEPT [0:0]
:FILTERS - [0:0]
:DOCKER-USER - [0:0]
-F INPUT
-F DOCKER-USER
-F FILTERS
-A INPUT -i lo -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-A INPUT -j FILTERS
-A DOCKER-USER -i eth0 -j FILTERS
-A FILTERS -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FILTERS -m conntrack --ctstate NEW -p tcp -m multiport --dports 80 -j ACCEPT
-A FILTERS -m conntrack --ctstate NEW -p tcp -m multiport --dports 443 -j ACCEPT
-A FILTERS -m conntrack --ctstate NEW -p tcp -m multiport --src <YOUR.DYNAMIC.I.P> --dports 22 -m comment --comment "secure ssh" -j ACCEPT
-A FILTERS -j REJECT --reject-with icmp-port-unreachable
COMMIT
You will notice that the ssh iptables line has been modified.
Now before you restart the iptables service, make sure you have a way to connect to your server in case something goes wrong. Once you have a way to reconnect, go ahead and restart the service. If all goes well, nothing will happen.
Step 2: Grab your Dynamic IP and Update iptables
Create a new folder and executable file to store your new script:
root@server:[~]> mkdir /etc/dyndns
root@server:[~]> touch /etc/dyndns/dyndns.sh
root@server:[~]> chmod +x /etc/dyndns/dyndns.sh
Edit the new file /etc/dyndns/dyndns.sh
with your favourite editor and paste/modify the following script. Be sure to change the HOSTNAME
to your actual dynamic domain. Also if you have additional ports you want to secure, be sure to add additional lines, modifying them to your needs. The principle behind what we are doing is replacing the line located in our /etc/iptables.conf
file based on the comment we have for the iptables rule anytime the dynamic IP does is not found in the iptables.
#!/bin/bash
HOSTNAME=your.dynamic.domain.com
DYNIP=$(host $HOSTNAME | grep -iE "[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+" | cut -f4 -d' ' | head -n 1)
IPTABLESCONF=/etc/iptables.conf
# Exit if invalid IP address is returned
case $DYNIP in
0.0.0.0 )
echo "invalid IP";
exit 1 ;;
255.255.255.255 )
echo "invalid IP";
exit 1 ;;
esac
# Exit if IP address not in proper format
if ! [[ $DYNIP =~ (([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]) ]]; then
echo "invalid IP";
exit 1
fi
if ! iptables-nft -n -L FILTERS | grep -iE "$DYNIP" >/dev/null 2>&1 ; then
sed -i "/secure ssh/c\-A FILTERS -m conntrack --ctstate NEW -p tcp -m multiport --src $DYNIP --dports 22 -m comment --comment \"secure ssh\" -j ACCEPT" $IPTABLESCONF
systemctl restart iptables
fi
I didn’t come up with the above script, I found it thanks to this nice little stackexchange.
Once you have it configured, just add a new cron rule to run the script every 5 minutes, or however long you want the check to occur.