Using VirtualBox host networks with vagrant

I have a few VirtualBox VMs that I use to test clustering, Gluster, Ceph and various other technologies. These hosts have a NAT interface as well as a host network for internal communications. This week I revamped several of my Vagrantfiles to use a host network and learned a few things in the process. To get a machine to ‘vagrant up’ and connect to an existing VirtualBox host network I first had to install the vbguest plug-in:

$ vagrant plugin install vagrant-vbguest

Copy iso file /usr/share/virtualbox/VBoxGuestAdditions.iso into the
box /tmp/VBoxGuestAdditions.iso
mount: /dev/loop0 is write-protected, mounting read-only
Installing Virtualbox Guest Additions 5.1.6 – guest version is unknown
Verifying archive integrity… All good.
Uncompressing VirtualBox 5.1.6 Guest Additions for Linux………..
VirtualBox Guest Additions installer
Copying additional installer modules …
Installing additional modules …
vboxadd.sh: Building Guest Additions kernel modules.

Once this plugin was installed I added a “private_network” stanza similar to the following to each Vagrantfile:

config.vm.network “private_network”, ip: “1.2.3.4”

Then I ran ‘vagrant up’ and my machines could see the host networks my VirtualBox VMs reside on. Niiiiice!

Using fail2ban to lock out unwanted visitors to your SSH daemon

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!

What are bash return codes > 128?

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=’\n[\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.

Having fun in the shell with cowsay and fortune

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. :)

Automatically updating your .bashrc when you log into a server

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.

One of the best docker resources on the interwebs

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!