rsyslog loggly remote

Shipping your logs to a central server is usually a good thing to do. For a large number of servers it provides a better overview, and no matter the numbers of servers a secondary log location can be helpful in figuring out why something bad happened to a server.

My two VPS nodes are now using loggly as a remote (TLS) syslog server. I’m even allowed do that for free, as long as I don’t upload more than 200 MB of logs per day, nor want the log data to be retained for more than a week. Not that I would mind paying a bit for a longer retention period. It’s just that their pricing feels a bit steep, given that I currently log less than a megabyte per day.

(Yes, I do realize that I’m not their obvious target audience.)

Already running rsyslog I decided to follow loggly’s rsyslog instructions, which did a pretty good job of explaining the additional configuration needed. The one thing I did miss in those instruction were a discussion on queue setting, which very much will matter when loggly’s servers for one reason or another becomes unavailable. By default rsyslog only queues a limited number of entries in memory, so for additional resilience I explicitly enabled a disk assisted queue, based on the rsyslog reliable forwarding guide.

Want to test the queuing? Just put appropriate iptables rules in place, and then speed up time by using logger(1) to pipe lots and lots of entries into syslog.

All in all, the following loggly specific configuration seems to do the trick for me.

# /etc/rsyslog.d/loggly.conf
$DefaultNetstreamDriverCAFile /etc/ssl/loggly/loggly_full.crt
$DefaultNetstreamDriverCertFile /etc/ssl/loggly/dummy-halleck.crt
$DefaultNetstreamDriverKeyFile /etc/ssl/loggly/dummy-halleck.key

$ActionSendStreamDriver gtls
$ActionSendStreamDriverMode 1
$ActionSendStreamDriverAuthMode x509/name
$ActionSendStreamDriverPermittedPeer *.loggly.com

$ActionQueueType LinkedList
$ActionQueueFileName loggly
$ActionResumeRetryCount -1
$ActionQueueSaveOnShutdown on

*.* @@logs.loggly.com:<assigned port>

If you are running Ubuntu, and Launchpad bug #1075901 have yet to be fully fixed, you might manually need to chown syslog:syslog /var/spool/rsyslog/. While you are at it, also install the needed rsyslog-gnutls package.

Worth mentioning is that loggly provides the option of archiving your logs to a S3 bucket. Given my modest log volumes the cost of doing that ought to be pleasantly close to zero.

Will be very interesting to see how reliable this solution turns out to be. The plan is to setup some semi-automated testing, and hopefully have some results to share in a follow-up post, say in a month or two.

YubiKey NEO and Ubuntu

My Christmas gift to myself this year turned out to be a YubiKey NEO.

The new feature I myself find most interesting is that the NEO can act as an OpenPGP smartcard. While there is a pretty good introduction in the Yubico blog post YubiKey NEO and OpenPGP I ran into some obstacles getting things running under Ubuntu.

First of all it doesn’t seem like the version of the yubikey-personalization  (1.7.0) included in Ubuntu 12.10 recognizes the YubiKey NEO. Without spending to much time on debugging that issue was solved by upgrading to the current yubikey-personalization version, using the Yubico PPA.

Then there was the matter of getting the device permissions right, allowing my non-root user to use/modify the NEO more actively than just having it act as a keyboard (HID), spitting out one time passwords. Turns out that the /lib/udev/rules.d/70-yubikey.rules provided by the current yubikey-personalization (1.11.1) only matches the ATTRS{idProduct} “0010″, which doesn’t apply to the NEO. I solved that by copying the 70-yubikey.rules to /etc/udev/rules.d/, modifying it to instead match ATTRS{idProduct} against “0010|0111″. According to the add udev rules for YubiKey NEO bug report it probably doesn’t hurt to also through the 0110 id into the mix.

Finally I had the fun experience of running into a limitation in the gnome-keyring’s capacity to act as gnupg-agent (Launchpad bug #884856). Any attempt to have GnuPG interact with the NEO smartcard, while using the gnome-keyring gnupg-agent, resulted in a “selecting openpgp failed: unknown command” error. Not finding any cleaner configuration option I resorted to simply removing /etc/xdg/autostart/gnome-keyring-gpg.desktop, resulting in gnome-keyring no longer hijacking the GPG_AGENT_INFO environment variable, instead letting the real gnupg-agent do its thing.

Now I only need to decide to what extent to actually use the OpenPGP smartcard feature. Yet, that’s a whole different blog post.

Easy IPv4+IPv6 Nagios monitoring using check_v46

Not feeling ready to give up on IPv4 quite yet? In that case you most likely want your Nagios to probe your services on both their IPv4- as well as their IPv6 addresses.

Looking into how how to handle that duplication in a sane manner I stumbled over the rather convenient check_v46 plugin wrapper. Assuming the actual check being run provides the -4/-6 options check_v46 can automatically, based on a hostname lookup, test using IPv4 and/or IPv6, and then return the worst result. See below for a trivial example, as well a matching example response.

define command{
       command_name    dual_check_http
       command_line    /usr/local/nagios/check_v46 -H '$HOSTNAME$' /usr/lib/nagios/plugins/check_http
}
CRITICAL: IPv6/halleck.arrakis.se OK, IPv4/halleck.arrakis.se CRITICAL

Do note that there is also the option of manually feeding check_v46 IPv4 and IPv6 addresses. See the plugin –help for the actual details. Also note that the check_v46 wrapper does not appear to work with the Nagios embedded Perl.

Of course, a more perfect solution probably requires Nagios itself to be more IPv4 vs IPv6 aware. For example, in the case that a host (or a datacenter) temporarily becomes unavailable over IPv6, it might then be more helpful if the service checks focused primarily on the IPv4 results, instead of either going full ballistic or completely silent. Yet, as long as good enough is good enough, the check_v46 wrapper is definitely an easy win.

Fully using apt-get download

Occasionally I need to download a Debian package or two. While I could find a download link using packages.debian.org / packages.ubuntu.com I really do prefer using apt-get download. In addition to the general pleasantness of using a command line tool the main benefit really is that apt automatically will verify checksums and gpg signatures.

For me the most typical usage scenario is that I want to download a Debian package from a different release than the one I happen to run on my workstation. Instead of putting additional entries in /etc/apt/sources.list, and hence having to deal with apt pinning as well as it making my regular apt-get update runs slower, I find it much more convenient to setup a separate apt environment.

First there is the basic directory structure.

$ mkdir -p ~/.cache/apt/{cache,lists}
$ mkdir -p ~/.config/apt/{apt.conf.d,preferences.d,trusted.gpg.d}
$ touch ~/.cache/apt/status
$ ln -s /usr/share/keyrings/debian-archive-keyring.gpg ~/.config/apt/trusted.gpg.d/
$ ln -s /usr/share/keyrings/ubuntu-archive-keyring.gpg ~/.config/apt/trusted.gpg.d/

(For an Ubuntu system the /usr/share/keyrings/debian-archive-keyring.gpg keyring is provided by the debian-archive-keyring package.)

Then there is the creation of the files ~/.config/apt/downloader.conf and ~/.config/apt/sources.list. They should contain something like the following.

## ~/.config/apt/downloader.conf
Dir::Cache "/home/USERNAME/.cache/apt/cache";
Dir::Etc "/home/USERNAME/.config/apt";
Dir::State::Lists "/home/USERNAME/.cache/apt/lists";
Dir::State::status "/home/USERNAME/.cache/apt/status";
## ~/.config/apt/sources.list
# Debian 6.0 (Squeeze)
deb http://ftp.us.debian.org/debian/ squeeze main contrib non-free
deb http://ftp.us.debian.org/debian/ squeeze-updates main non-free
deb http://security.debian.org/ squeeze/updates main contrib non-free

# Debian 6.0 (Squeeze) Backports
deb http://backports.debian.org/debian-backports squeeze-backports main contrib non-free

# Debian 7.0 (Wheezy)
deb http://ftp.us.debian.org/debian/ wheezy main
deb http://security.debian.org/ wheezy/updates main

# Debian Unstable (Sid)
deb http://ftp.us.debian.org/debian/ sid main

# Ubuntu 12.04 (Precise)
deb http://us.archive.ubuntu.com/ubuntu/ precise main restricted universe multiverse
deb http://us.archive.ubuntu.com/ubuntu/ precise-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu precise-security main restricted universe multiverse

# Ubuntu 12.10 (Quantal)
deb http://us.archive.ubuntu.com/ubuntu/ quantal main restricted universe multiverse
deb http://us.archive.ubuntu.com/ubuntu/ quantal-updates main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu quantal-security main restricted universe multiverse

Given the just described setup, apt-get download can now download packages from any release/codename defined in ~/.config/apt/sources.list.

$ APT_CONFIG=~/.config/apt/downloader.conf apt-get update
...
$ APT_CONFIG=~/.config/apt/downloader.conf apt-get download git/squeeze-backports
Get:1 Downloading git 1:1.7.10.4-1~bpo60+1 [6557 kB]
Fetched 6557 kB in 2s (2512 kB/s)
$ APT_CONFIG=~/.config/apt/downloader.conf apt-get download git/precise
Get:1 Downloading git 1:1.7.9.5-1 [6087 kB]
Fetched 6087 kB in 3s (1525 kB/s)

Do note that apt-get download was introduced in apt 0.8.11. For Debian that translates into Wheezy (7.0) and for Ubuntu that would be as of Natty (11.04). The main difference between apt-get download and apt-get –download-only install is that the later also does dependency resolution.

My bastardized Masterless Puppet

I am currently using Puppet to control my laptop as well as my two VPS nodes. That is not exactly the scale where I feel the need to have a puppet master running. Especially not since I am not overly keen on the idea of giving an external machine control over my laptop.

That being said, I still want some central location from where my nodes can fetch the latest recipes, allowing me the freedom to push updated recipes even if a node don’t happen to be online at the time. I just don’t want to spend any actual resources on this central location, nor having to trust it more than necessary.

At first my recipes didn’t contain any secrets and I got away with pulling updated recipes from a (public) github repository. The only overhead was the need to have my puppet cron script verify that HEAD contained a valid gpg signed tag.

Now my puppet recipes do depend on secrets. These shouldn’t be available neither to the central location nor to the wrong node. That bringing us to my current homegrown, slightly bastardized, solution.

The current central location for my puppet recipes is a cheap web host. To it I am uploading gpg encrypted tarballs. These tarballs are individually generated as well as encrypted with each nodes own gpg key. For further details, see the included Makefile below.

default:
	apt-get moo

locally: manifests/$(shell facter hostname).pp
	./modules/puppet/files/etckeeper-commit.sh
	puppet apply --confdir . --ssldir /etc/puppet/ssl ./manifests/$(shell facter hostname).pp
	./modules/puppet/files/etckeeper-commit.sh

backup:
	tarsnap --configfile ./.tarsnaprc -c -f "$(shell date +%s)" .

manifests/%.pp: manifests/defaults.inc manifests/%.inc
	cat $^ > $@

validate:
	find -regextype posix-egrep -regex ".+\.(pp|inc)" | xargs puppet parser validate
	find -name "*.erb" | xargs ./tools/validaterb.sh

exported/%.tar: manifests/%.pp validate
	tar cf $@ manifests/$*.pp modules/ secrets/common/ secrets/$*/

exported/%.tar.gpg: exported/%.tar
	gpg --batch --yes --recipient puppet@$*.arrakis.se --encrypt $<

exported/%.tar.gpg.sig: exported/%.tar.gpg
	gpg --batch --yes --detach-sign $<

upload-%: exported/%.tar.gpg exported/%.tar.gpg.sig
	scp -o BatchMode=yes exported/$*.tar.gpg.sig andol_andolpuppet@ssh.phx.nearlyfreespeech.net:/home/public/
	scp -o BatchMode=yes exported/$*.tar.gpg andol_andolpuppet@ssh.phx.nearlyfreespeech.net:/home/public/

hosts := halleck hawat leto
deploy: $(addprefix upload-, $(hosts))

.PHONY: default locally backup deploy validate

…and here is the download script running on the nodes. In addition to doing the gpg stuff the script also handles ETags for the http download.

#!/bin/bash

tarball="$(facter hostname).tar"
gpgball="${tarball}.gpg"
gpghead="${gpgball}.header"
sigfile="${gpgball}.sig"
etagfile="/usr/local/var/puppet/etag"
netrcfile="/usr/local/etc/puppet/netrc_puppet"

bailout () {
    rm -rf "$workdir"
    [ -n "$2" ] && echo "$2"
    exit $1
}

umask 0027

curretag=""
if [ -f "$etagfile" ]; then
    curretag=$(head -n1 "$etagfile" | grep -Ei "^[0-9a-f\-]+$")
fi

workdir=$(mktemp --directory)
cd $workdir || exit 1

curl --silent --show-error \
    --netrc-file "$netrcfile" \
    --header "If-None-Match: \"$curretag\"" \
    --dump-header "$gpghead" --remote-name \
    "http://puppet.arrakis.se/$gpgball"

if grep -Eq "^HTTP/1.1 304" "$gpghead"; then
    bailout 0
elif grep -Eq "^HTTP/1.1 200" "$gpghead"; then
    newetag=$(sed -nre "s/^ETag: \"([0-9a-f\-]+)\"\s*$/\1/pi" "$gpghead")
    [ -n "$newetag" ] && echo "$newetag" > "$etagfile"
else
    bailout 0 "Failed to get expected HTTP response."
fi

curl --silent --show-error \
    --netrc-file "$netrcfile" --remote-name \
    "http://puppet.arrakis.se/$sigfile"

gpgv --keyring /usr/local/etc/puppet/gnupg/trustedkeys.gpg "$sigfile" 2> /dev/null
if [ $? -ne 0 ]; then
    bailout 0 "Signature verification failed."
fi

export GNUPGHOME=/usr/local/etc/puppet/gnupg
gpg --quiet --batch "$gpgball" 2> /dev/null
if [ $? -ne 0 ]; then
    bailout 0 "Decryption failed."
fi

tar --no-same-owner --no-same-permissions -xf "$tarball"
if [ $? -ne 0 ]; then
    bailout 0 "tar extract failed."
fi

rsync --archive --delete --chmod=o-rxw,g-w \
    manifests modules secrets /usr/local/etc/puppet/

if [ $? -ne 0 ]; then
    echo beef > "$etagfile"
    bailout 1 "rsync update failed."
fi

rm -rf "$workdir"

Of course, this approach involves a bit more work while setting up Puppet on a new node. So while I feel that it is a good fit for my current situation it isn’t anything I would use in a larger environment. Also, with a larger amount of nodes there are puppet master features, such as reporting and storeconfigs, being potentially more valuable.

coloncolonone.net

For some reason I decided it was a good idea to register the domain coloncolonone.net. Currently it is only used to serve a static html page, proclaiming the following message.

There’s no place like ::1

Any ideas on other, possible slightly more creative, ways to use the domain name?

OpenSSH 5.7, SFTP and hard links

OpenSSH 5.7 just got released. You can read the full announcement at http://www.openssh.com/txt/release-5.7. Personally I especially appreciate the following improvement to their SFTP stack.

sftp(1)/sftp-server(8): add a protocol extension to support a hard link operation. It is available through the “ln” command in the client. The old “ln” behaviour of creating a symlink is available using its “-s” option or through the preexisting “symlink” command

Being able to handle hard links definitely makes SFTP even more useful as a remote filesystem.

Tarsnap Nagios checks

While I have been using Tarsnap for a while now it is first recently I have gotten around to make Nagios monitor those backups. Given that I really don’t want to give the nagios user any actual access to my backups, I instead take the approach of having my backup script create a status file containing a Unix timestamp of the most recent backup.

My check_tarsnap Nagios plugin can then use that status file to check that the most recent backup isn’t older than a specified number of hours. For my nightly backups I have the Warning threshold set to 26 hours and the Critical threshold set to 42 hours.

(See the top comment in the plugin source for an example on how to create the status file.)

Managing passwords using GnuPG, Git and Emacs

Like any other security conscious and/or slightly paranoid computer geek I have lots and lots of unique and nontrivial passwords to keep track of.  My solution to this problem involves having one GnuPG encrypted text file per username/password pair.

andreas@stilgar:~/safe$ gpg < example.gpg

You need a passphrase to unlock the secret key for
user: "Andreas Olsson <andreas@arrakis.se>"
4096-bit RSA key, ID 9A943D4A, created 2010-07-11 (main key ID 13CD4F59)
  Here gnupg-agent calls pinentry-gtk2 to prompt me for the passphrase
gpg: encrypted with 4096-bit RSA key, ID 9A943D4A, created 2010-07-11
      "Andreas Olsson <andreas@arrakis.se>"

https://127.0.0.1/

username: sigge
password: sigge

andreas@stilgar:~/safe$

As I need to have access to those passwords on more than one computer I use Git, and a remote repository, to keep my encrypted files in sync. Other options might be to mount a SFTP folder using SSHFS, or to simply put the files in your Dropbox. Yet, if you too decide to go with Git, here is a .gitignore you might want to use.

andreas@stilgar:~/safe$ cat .gitignore
*
!*.gpg
!.gitignore
andreas@stilgar:~/safe$

Thanks to Emacs and EasyPG it is a breeze to  create new GnuPG encrypted text files, as well as to modify existing ones. Just use the file extension .gpg, and EasyPG will do its thing. The first time, when you actually create the file, you will be prompted for which public keys you want to encrypt against.

andreas@stilgar:~/safe$ emacs yet_another_example.gpg

(EasyPG is included in Emacs 23, and don’t need to be installed separately.)

Do note that this method also works when there are multiple people involved. Just make sure that the intended users have access to the share/repository in question, and that their public keys are included when you create the GnuPG files.

Server configuration and version control

One of the (few?) good habits I managed to pick up during 2010 was that I became serious about keeping server configuration under version control. While it might primarily have been something I was taught at work it is definitely a practice I have adopted privately as well.

The most obvious benefit, and potentially the most valuable one, is the historic record version control provides. Yet, the part I appreciate most is how easy it becomes to compare new configuration against current one; to verify that you only made  just those changes which you  intended to make. There is a certain comfort in being able to run a git diff before restarting a local service or before pushing new cluster configuration.

(Not that I do not appreciate having access to the configuration history. When being asked about something which happend a few months ago, those commit messages and those diffs becomes awful handy.)

For your local /etc this is as a good time as any to take a peak at etckeeper.

Follow

Get every new post delivered to your Inbox.