Tag Archives: Debian

A Free SSL Web Hosting Solution

Introduction

SSL Web Hosting has been made free by a number of providers such as Let’s Encrypt and ZeroSSL for years now. I wrote this blog because I truly believe web administrators and developers should leverage this if they aren’t already.

I’ve personally come across an amazing tool called Dehydrated which I used to leverage this. The best part about Dehydrated is that it even operates using the MIT license, meaning it’s also completely free to use!

Dehydrated Setup

An ideal SSL Web Hosting solution comes with the perfect tool to do all of the work for you…

Installation

#
# Make sure curl is installed:
#
# RedHat/CentOS v5,6, and 7 Users
sudo yum install -y curl

# RedHat/CentOS v8+ and Fedora Systems:
sudo dnf install -y curl

# Debian/Ubuntu Systems
sudo apt update && sudo apt get curl

# Download Dehydrated (as root)
curl https://raw.githubusercontent.com/dehydrated-io/dehydrated/master/dehydrated \
   --output /usr/bin/dehydrated

# Set proper permissions
chmod 755 /usr/bin/dehydrated

# Make a wellknown directory for the acme-challenge strings
mkdir -p /var/www/dehydrated

# SELinux Proof it (for those that use it - and you should!)
semanage fcontext -a -t httpd_sys_content_t \
          '/var/www/dehydrated/(/.*)?'

Initial Preparation

Next we need to just prepare some basic configuration needed by Dehydrated:

mkdir -p /etc/pki/dehydrated
pushd /etc/pki/dehydrated

# SSL Hosting Configuration; Identify your hosts
#
# Below shows how I set up nuxref.com; you will want to
# identify ALL of the SSL hostnames you plan on supporting
# here:
cat << _EOF > domains.txt
# nuxref Hosts; swap these with your own:
# syntax:
#   domain sub1.domain sub2.domain subx.domain > output_file
nuxref.com www.nuxref.com repo.nuxref.com > nuxref_com
_EOF

# Create ourselves a config file:
cat << _EOF > config
# our wellknown directory
WELLKNOWN=/var/www/dehydrated
_EOF

# First time use only
/usr/bin/dehydrated --register --accept-terms

Nginx Configuration

You’ll want to create the the following parameter file that you can source in all of your domain configuration files:

cat << _EOF > /etc/nginx/dehydrated_params
location ^~ /.well-known/acme-challenge {
   alias /var/www/dehydrated;
}
_EOF

The sourcing part is really easy now. You must add this entry in all of your configuration files that you’ve defined in your /etc/pki/dehydrated/domains.txt file (above).

# Place this in all of your NginX files in the server{} block(s):
include        dehydrated_params;

You’ll want to make sure once you got all of the include statements in place, and that you reload NginX so that it can take on your new configuration:

sudo systemctl reload nginx

Generating our SSL Keys

We’re now at the part of the blog where we test to see if all of our setup (defined above) was correctly put into place.

# We must always run Dehydrated from within this directory
pushd /etc/pki/dehydrated

# Force an initial update
dehydrated -c

The above command will run against all of the domains you defined in /etc/pki/dehydrated/domains.txt and attempt to verify them (in order to generate an SSL key for you). If it fails, it’s most likely because of the following:

  1. You’re not correctly hosting that domain on port 80 on this server we just set up together.
  2. You have an error in your NginX configuration and/or you forgot to add an include dehydrated_params; within one of your domain configuration(s).

If everything went smoothly, you’ll now have new SSL keys you can add to your NginX configuration. This allows you to host your website secured now using your own set of registered SSL keys. You’re almost home free now! You need to dive back into NginX and prepare yourself a new server block of code that listens on port 443 with SSL turned on.

server {
  # SSL
  listen 443;
  ssl on;

  #
  # your security setup and location entries here
  # See https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html
  # for some ideas

  # Don't forget to point to your newly generated SSL Keys:
  # swap nuxref_com
  ssl_certificate /etc/pki/dehydrated/certs/nuxref_com/cert.pem;
  ssl_certificate_key /etc/pki/dehydrated/certs/nuxref_com/privkey.pem;
}

Set It and Forget It

Free SSL Web Hosting keys being free do however come with a catch: they don’t last long. They don’t expire in 2-3 years like a normal paid key would – these ones expire in 30 days in some cases. So it’s up to you to either remember to run dehydrated -c often, OR just automated it like so:

# next add a cronjob so it updates automatically
cat << _EOF > /etc/cron.d/dehydrated
# at 14:20 every day update SSL certificates
20 14 * * * root cd /etc/pki/dehydrated/ && dehydrated -c &>/dev/null && systemctl reload nginx &>/dev/null
_EOF

Sources

Permanently Ban Those Caught By Fail2Ban

Introduction

Fail2ban is probably one of the best intrusive detection based tools an administrator can deploy onto their system. This is especially the case if your system is connected to the internet. If you aren’t already using it; consider reading my blog entry here that talks about it.

In this blog, I provide a scripted solution that will capture the current list of banned users from Fail2Ban and make their ban permanent. This allows us to limit the constant emails one might receive about the same people trying to compromise our system(s). For those who aren’t using the emailing portion of Fail2Ban; this script still greatly takes the load off of Fail2Ban because it no longer has to manage the constant repeat offenders. Our logs are less cluttered too.

The script will address several things:

  1. It will handle multiple attacks from people within the same Class C type netmask.
  2. It will allow for the permanent bans to stick even after your system is rebooted. Unlike Fail2Ban’s list of blocked perpetrators, which is lost if the system (or iptables) is restarted.
  3. It will enforce the use of iptable’s DROP directive instead of REJECT. This is a slightly more secure approach in handling those who aren’t ever allowed to come back.
  4. It will support the fact that over time, you may want to add and remove from this new ban list I keep speaking of. Basically you can re-run the steps outlined in this blog again (and again) and not lose the addresses you’ve already blocked.
  5. The script maintains a global list of addresses in a simple delimited format. You can then choose to share this list with other systems (or colleagues) to block the same unwanted users on these systems too.

Script Dependencies and Requirements

For this script to work, you can virtually use any Linux/FreeBSD/Unix operating system as long as you’re also using fail2ban in conjunction with iptables.

The script makes use of sed, and gawk to massage the data. These tools are common an available to all operating systems. But not all of them necessarily have them installed by default. Make sure you’ve got them before proceeding:

# Fedora / CentOS 4,5,6 / RedHat 4,5,6
yum -i install gawk sed

# Ubuntu / Debian
apt-get install gawk sed

The Goods

Without further ado, the below code is documented quite heavily so that you can just copy the sections into your terminal screen as the systems root user. Don’t try the next section until you’re done with the previous.

Although this code works for me, I still must caution you all the same: I will not be held liable for any loss, damage or expense as a result of the actions taken by my script. I’ve only used it without problem with CentOS 6.x. That said, the simplicity of it should make it work with any other *nux based OS as well.

# Author: Chris Caron
# Date: Tue, Apr 7th, 2015
########################################
# Environment Variables
########################################
# YOU MUST CORRECTLY SET THESE OR THE REMAINING FUNCTIONS OF
# THIS CODE WILL NOT WORK CORRECTLY.
#
# THIS SCRIPT ASSUMES YOU ARE RUNNING AS 'root'
#
# Public Ethernet Device
# For my home system, i have this set to ppp0; You'll want to
# set this to the Ethernet device that harm can venture from.
# such as the internet.
PUBDEV=eth0

# The name of the iptables chain to manage the permanent bans
# within. The name doesn't matter so long that it doesn't
# collide with a chain you're already managing.
# Also, Do not change this value in the future because that
# will hinder the ability to upgrade/append new bans easily.
# It is doubtful that it's current set value will conflict
# with anything. Therefore just leave the name the way it is
# now:
FILTER=nuxref-perm-ban

# The script makes an effort to detect IP Addresses all
# coming from the same Class C type network.  Rather then
# have an entry per IP like fail2ban manages; we group
# them into 1 to speed the look-ups iptables preforms.
# You'll want to identify the minimum number of IP
# addresses matched within the same alike (Class C) network
# before this grouping takes place.
CLASSCGRP_MIN=2

# IP Tables configuration file read during your system
# startup.
IPTABLES_CFG=/etc/sysconfig/iptables

# IPTables Chain Index
# Identify where you want your ban list to be applied
# To reduce overhead, the banlist should be processed 'after'
# some core checks you do.  For example I have a series of other
# checks i do first such as allowing already established
# connections to pass through.  I didn't want the ban list
# being applied to these, so for my system, i set this to 11.
# Setting it to 1 is safe because it guarantees it's at least
# processed first on systems who don't actively maintain their
# own custom firewall list.
CHAINID=1

########################################
# Preparation
########################################

# First we built a massive sorted and unique list of
# already banned IP addresses.
# The below is clever enough to include previous content
# you've banned from before (if any exists):
(
   # carry over old master list
   iptables -L -n | awk "/Chain $FILTER/, $NF ~ /RETURN/" | 
    egrep DROP | sed -e 's/^[^0-9.]*([0-9]+.[0-9]+.[0-9]+).([0-9/]+).*/1 .2/g'
   # update master list with new data
   iptables -L -n | egrep REJECT | 
    sed -e 's/^[^0-9.]*([0-9]+.[0-9]+.[0-9]+).([0-9]+).*/1 .2/g'
) | sort -n | uniq > list
 
# Now we build a separate list (in memory) that will track
# all of the ip addresses that met our $CLASSCGRP_MIN flag.
CLASSC_LIST=$(cat list | cut -f1 -d' ' | uniq -c | 
    sed 's/^ *//g' | sort -n | 
    awk "int($1)>=$CLASSCGRP_MIN" | cut -f2 -d' ')
 
# We eliminate the duplicates already pulled into memory
# from the master list of IPs
for NW in $CLASSC_LIST; do sed -i -e "/^$NW /d" list; done

# Now we scan our list and repopulate them into our master
# list. We place these entries at the head of the file so
# that they'll be added to our iptable ban chain first.
for NW in $CLASSC_LIST; do sed -i "1s/^/$NW .0/24n/" list; done

# Using our list of banned IP addresses, we now generate
# the actual iptable entries (into a file called
# 'commands':
(
   # Creates the chain
   echo iptables -N $FILTER
 
   # Build List of Addresses using our list file
   while read line; do           
      IP=$(echo $line | tr -d '[:space:]')
      echo iptables -A $FILTER -s $IP -j DROP;
   done < list
 
   # Allow future iptable processing to continue 
   # after reading through this chain by appending
   # the RETURN action.
   echo iptables -A $FILTER -j RETURN
 
   # Add chain to INPUT
   echo iptables -t filter -I INPUT $CHAINID -i $PUBDEV -j $FILTER
) > commands

########################################
# IPTables (Temporary Instalment)
########################################

# Have a look at our commands if you want:
cat commands

# Apply these new rules now with the following command:
sh commands

# The commands generated in the 'commands' text file 
# are only temporary; they will be lost if your
# machine (or iptables) is ever restarted

########################################
# IPTables (Permanent Installation)
########################################
# Consider making a backup of your configuration in case you
# need to roll back
/bin/cp -f $IPTABLES_CFG $IPTABLES_CFG.backup

# Now we generate all of the commands needed to place
# into our iptables configuration file:
sed -e 's/^iptables[ ]*//g' commands | 
    egrep "^-A $FILTER -s " > commands-iptables
# Clean up old configuration
sed -i -e "/^:$FILTER -/d" "$IPTABLES_CFG"
sed -i -e "/^-A INPUT .* $FILTER$/d" "$IPTABLES_CFG"
sed -i -e "/^-A $FILTER -/d" "$IPTABLES_CFG"
 
# Now push all of our new ban entries into the iptables file
sed -i -e "/:OUTPUT .*/a:$FILTER - [0:0]" "$IPTABLES_CFG"
sed -i -e "/:$FILTER - .*/a-A INPUT -i $PUBDEV -j $FILTER" "$IPTABLES_CFG"
sed -i -e "/-A INPUT -i $PUBDEV -j $FILTER.*/r commands-iptables" "$IPTABLES_CFG"

# Now preform the following to reset all of the fail2ban
# jails you've got as well load your new permanent ban setup
service fail2ban stop
service iptables restart
service fail2ban start

# If you have a problem; just roll back your backup you
# created and rerun the 3 commands above again. You can
# have a look at the table with the following command:
iptables -L -n -v

########################################
# IPTables (Optional Tiding)
########################################
# the above will insert the banlist at the top
# The below will just correct this and move it
# clean entry(s) from INPUT
(
   while [ 1 -eq 1 ]; do
      ID=$(iptables -nL --line-numbers | 
           egrep "^[0-9]+[ t]+$FILTER " | 
           head -n 1 | 
           sed -e 's/^([0-9]+).*/1/g')
      [ -z "$ID" ] && break;
      iptables -D INPUT $ID
   done
   # Re insert at the correct $CHAINID
   iptables -t filter -I INPUT $CHAINID -i $PUBDEV -j $FILTER
)

# have another look if you want (if you tidied)
iptables -L -n -v

########################################
# Cleanup (Optional)
########################################
# Remove temporary files when your done; or save them if you
# want to port this data to another server:
rm -f list commands commands-iptables

You can undo and destroy the new entries an any time using the following:

# disassociate filter from INPUT
while [ 1 -eq 1 ]; do
   ID=$(iptables -nL --line-numbers | 
        egrep "^[0-9]+[ t]+$FILTER " | 
        head -n 1 | 
        sed -e 's/^([0-9]+).*/1/g')
   [ -z "$ID" ] && break;
   iptables -D INPUT $ID
done
# flush filter
iptables -F $FILTER
# remove filter
iptables -X $FILTER

Credit

This blog took some time to put together and test! If you like what you see and wish to copy and paste this HOWTO, please reference back to this blog post at the very least. It’s really all I ask.

Sources

There were not many sources used to make this entry. Most of it is just shell scripting knowledge I’ve adopted over the years mixed with some iptable commands. Here are some sources anyway that are applicable: