I have a number of digital ocean droplets and AWS instances that I use for personal projects. For convenience I leave SSH open to the world so I can access these systems wherever I’m at. This DEFINITELY isn’t a best practice but my personal instances don’t contain anything sensitive and can be rebuilt in minutes with ansible. A wide open TCP port 22 doesn’t come without issues though. If you leave your SSH daemon open to the world you are going to see a myriad of failed log attempts in /var/log/secure:
***Jan 25 16:10:35 oscar sshd[10450]: Failed password for root from 116.31.116.46 port 23476 ssh2***
To enhance the security of my SSH daemon I enforce key-based authentication, update openssh hourly w/ an ansible playbook and enable fail2ban to blacklist IPs that try to log into my servers too many times. Setting up fail2ban on a CentOS 7 Linux host is extremely easy. First, you need to install the packages:
$ yum -y install fail2ban fail2ban-systemd jwhois
Once the packages are installed you will should review the default fail2ban configuration settings in /etc/fail2ban/jail.conf. This file shouldn’t be edited directly since system updates will replace it and flush away any changes you made. Customizations should go into /etc/fail2ban/jail.local. Changes made to this file will override the system defaults. Here is a sample /etc/fail2ban/jail.local file to get you started:
[DEFAULT]
# Ban hosts for one hour:
bantime = 3600
# Use the multiport iptables action
banaction = iptables-multiport
# Who to send e-mail to when an IP is banned
destemail = EMAIL_ADDRESS_TO_SEND_TO
sendername = fail2ban@oscar
mta = sendmail
# Where to send info if an IP is banned (e-mail, logs, etc.)
action = %(action_mwl)s
[sshd]
enabled = true
Once this file is in place you will need to enable and start the service:
$ systemctl enable fail2ban
$ systemctl enable fail2ban
If you didn’t encounter an error the fail2ban-client should list the jail it created for the SSH service:
$ fail2ban-client status
Status
|- Number of jail: 1
`- Jail list: sshd
To see IPs that are being blacklisted you can grep for Ban in /var/log/fail2ban.log:
$ grep Ban fail2ban.log
2017-01-25 15:57:25,365 fail2ban.actions [10213]: NOTICE [sshd] Ban 116.31.116.46
Or run iptables to list the IPs it added to the f2b-sshd chain:
$ sudo iptables -S f2b-sshd
-N f2b-sshd
-A f2b-sshd -s 116.31.116.46/32 -j REJECT --reject-with icmp-port-unreachable
-A f2b-sshd -j RETURN
If e-mail notifications are configured via the “action” directive you will receive an e-mail each time fail2ban blacklists an IP. Now that you see how easy it is to set this up I would like to provide a bit more detail on the terminology I used above. A fail2ban “jail” is a combination of filters and actions. Filters are the criteria fail2ban uses to figure out if something bad is happening and are defined in /etc/fail2ban/filter.d/.conf. Actions describe what to do (add an iptables rule to reject traffic from a source IP, add a blackhole route, etc.) if a filter matches. All of the actions are defined in /etc/fail2ban/action.d. The manual pages are terrific and all of the files in /etc/fail2ban are THOROUGHLY commented. If you use ansible you can automate the fail2ban installation with a fail2ban.yml playbook. This is a great utility and super easy to use!
I like to keep PS1 pretty simple. I like to see the host I’m working on, the directory I’m in, the user I’m currently logged in as and the return code from teh last command I executed. This is easy to cobble together with bash escape sequences:
PS1='[\u@\h][RC:$?][\w]$ '
The other day I was testing some new ansible playbooks and saw a return code of 130. Several years ago I read learning the bash shell and recalled something about the magic number 128. A quick search of the bash man page provided this gem:
“The return value of a simple command is its exit status, or 128+n if the command is terminated by signal n”
So a return code of 130 represents a process that is terminated by
signal 2 which kill -l
lists as SIGINT:
$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
Noting this here so I have it handy for the future.
Last weekend while I was waiting for several ansible playbooks to apply I thought it would be fun to play around with cowsay and fortune. If you aren’t familiar with these tools cowsay gives you an ASCII cow which says whatever is passed to it as an argument. Here is a example:
$ fortune | cowsay
________________________________
< Tomorrow, you can be anywhere. >
--------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
To have a cowtastic time each time I open a shell I added the following to my bashrc:
# Have some fun
if [ -x /bin/cowsay ] && [ -x /bin/fortune ] || [ -x /usr/games/cowsay ] && [ /usr/games/fortune ]; then
fortune | cowsay
fi
I guess the old saying is right. All work and no play makes an admin mooooooooo. :)
I am a long time bash user and have found numerous aliases and shell functions that allow me to be more productive at the prompt. Depending on how you manage (configuration management, NFS mounted home directories, etc.) ${HOME} making sure your bashrc gets updated when you find a cool new feature can be a pain. I was tinkering around last weekend and thought about adding a block of code to my bashrc to run curl to grab the latest version of my bashrc from github. The following short code block works for my needs:
# Location to pull bashrc from
bashrc_source="https://raw.githubusercontent.com/Matty9191/bashrc/master/bashrc"
# Take precaution when playing with temp files
temp_file=$(mktemp /tmp/tmp.XXXXXXXX)
touch ${temp_file}
curl -s -o ${temp_file} ${bashrc_source}
RC=$?
if [ ${RC} -eq 0 ]; then
version=$(head -1 ${temp_file} | awk -F'=' '/VERSION/ {print $2}')
if [ "${version}" -gt "${VERSION}" ]; then
echo "Upgrading bashrc from version ${VERSION} to ${version}"
cp ${HOME}/.bashrc ${HOME}/.bashrc.bak.$(/bin/date "+%m%d%Y.%S")
mv ${temp_file} ${HOME}/.bashrc
fi
else
echo "Unable to retrive bashrc from ${bashrc_source}"
rm ${temp_file}
fi
If a new version is available (a VERSION variable tracks the release #) I get the following output when I log in:
***Upgrading bashrc from version 44 to 46***
If github is unavailable due to a service issue or a firewall won’t let me out the script will let me know:
***Unable to retrieve bashrc from
https://gik/Matty9191/bashrc/master/bashrc***
How are you keeping your shell profiles up to date? Let me know in the comment section.
For the past two years I’ve scoured the official docker documentation when I needed to learn something. Their documentation is really good but there are areas that lack examples and a deep explanation of why something is the way it is. One of my goals for this year is to read one technical book / RFC a month so I decided to start off the year with James Turnbull’s The Docker Book. James starts with the basics and then extends this with a thorough description of images, testing with docker and orchestration. This is by far the best $10 I’ve spent on a book and I’m hoping to read his new Terraform book once I finish reading through my DNS RFC. Awesome job on the book James!