Friday, August 23, 2013

Linux server partitioning with mdadm software RAID and LVM2

Over the years, I've really come to appreciate what judicious use of LVM (or LVM2) brings to the table when administering servers. If you rely on it heavily and leverage it properly, you can do things like:
  • Snapshot any file system (other then /boot) for backups, or to make images, or to test something out.
  • Migrate a logical volume (LV) from one physical volume (PV) to another, without having to take the file system offline or deal with downtime.
  • Resize file systems that are too large or too small, with minimal downtime (if the file system supports it).
Basically, other then /boot, if you're thinking of creating a separate partition or Software RAID device the you should be using LVM instead of physical partitions or RAID devices. You gain a lot of flexibility in the long-run and setting up LVM on top of hardware or software RAID or plain old disks is no longer that difficult.

These days, when I setup disk partitions to hold a server's boot-up files, I only create (2) partitions on the drive. One for the Software RAID-1 mirror set to hold /boot (usually 256-1024MB) and the rest of the drive is a second RAID-1 mirror set that is turned into a LVM physical volume (PV) and assigned to a volume group. I will usually only partition out to about 99% of the drive size if I'm doing Software RAID, because that makes it easier later to put in a different model disk of the same capacity and still have things work. Drives from different manufacturers have slightly different capacities, so you can run into trouble down the road when you go to replace a failed drive if you assumed all drives were exactly the size as your original drives.

Inside that LVM volume group (VG), I create all of my other partitions. These days, that means:
  • / - the "root" partition, usually 16-32GB for CentOS 6
  • /home - Usually starts at 4GB for a server where people won't be logging in much.
  • /opt - 4-24GB
  • /srv - 1-4GB (sub-directories get their own LV later)
  • /tmp - 4-24GB
  • /usr/local - 8-24GB
  • /var - 4-24GB
  • /var/log - 4-24GB
  • /var/spool - 2-4GB to start
  • /var/tmp - 2-8GB to start
And that's just the basic operating system file systems. For things like squid, e-mail, web servers, samba shares, etc., each of those will get its own LV, allocated from the server-wide volume group.

Follow ups:
  • GRUB2 understands mdadm (software RAID) and LVM. So we will eventually be able to put /boot in an LVM volume. But the GRUB that ships with RHEL6 and CentOS6 is still GRUB 0.97.

Sunday, August 18, 2013

TLS: SSL_read() failed: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca: SSL alert number 48

Here's a fun error message that we're getting on our mail server at the office:

Aug 15 10:52:26 fvs-pri dovecot: imap-login: Disconnected (no auth attempts in 1 secs): user=<>, rip=172.30.0.221, lip=172.30.0.1, TLS: SSL_read() failed: error:14094418:SSL routines:SSL3_READ_BYTES:tlsv1 alert unknown ca: SSL alert number 48, session=

The odd thing is that using public SSL testing tools (such as the one at DigiCert) do not indicate any problems with the mail server's SSL configuration. And this only seems to affect some clients, and is possibly only acting up with Dovecot. So my guess is that Apache/OpenSSL is configured correctly, but Dovecot is not.

The key to figuring this out is the "openssl s_client" command:

openssl s_client -connect mail.example.com:143 -starttls imap

This showed us that the openssl library was having problems validating the server's certificate, because the intermediate certificates were not also stored in the certificate file that gets sent to the client. The solution is to adjust the file pointed to by Dovecot's "ssl_cert" argument and add your certificate vendor's intermediate certificates to the end of the file.

The order of the certificates inside that file matters. Your server certificate needs to be first, then list the rest of the certificates in order as you move up the certificate chain to the root CA.

Wednesday, August 14, 2013

LUKS: /dev/mapper "read failed after 0 of 4096 at 0: Input/output error"

We're using external USB drives for our backups, protected using LUKS/cryptsetup. On our 3-4 year old Opteron 2210 HE CPU running at 1.8GHz, we estimate that LUKS can perform about 60-70 MB/s per CPU core. We mount the LUKS volumes automatically (at server boot) by listing them in /etc/cryptsetup and using a key-file instead of having to enter a password and autofs handles the automatic mounting/dismounting of the ext4 file system inside the LUKS volume.

It all works very well, until you remove the USB device and then run pvscan/lvscan commands of LVM. Which then throws the following errors:
# pvscan
  /dev/mapper/USBOFFSITE12B: read failed after 0 of 4096 at 999201636352: Input/output error
  /dev/mapper/USBOFFSITE12B: read failed after 0 of 4096 at 999201693696: Input/output error
  /dev/mapper/USBOFFSITE12B: read failed after 0 of 4096 at 0: Input/output error
  /dev/mapper/USBOFFSITE12B: read failed after 0 of 4096 at 4096: Input/output error
  PV /dev/md12   VG vg13   lvm2 [2.67 TiB / 821.62 GiB free]
  Total: 1 [2.67 TiB] / in use: 1 [2.67 TiB] / in no VG: 0 [0   ]

If 'autofs' would allow us to execute a script after it dismounts the drive from inactivity, it might be a good option for us. But I'm not sure that is possible.

Another option would be that at the end of the daily backup script which copies files off to the attached device, we dismount it automatically.

A third option would be to check every hour and see whether the /dev/mapper/NAME is no longer in use, then tell cryptsetup to dismount it. The command to check that might be "dmsetup ls --tree -o uuid,open | grep -i 'CRYPT-LUKS'".

Still exploring options at this point. I need to do some more testing first. I'm also searching for a way to auto-open LUKS volumes upon device insertion.

Monday, August 12, 2013

Auto-mounted external USB drives with Linux autofs daemon

This explains how to use 'autofs' to automatically mount external USB hard drives at a predictable path under CentOS 6 (but probably also works for CentOS 5, RHEL 5, RHEL 6, etc.). On one of my Ubuntu desktops; file systems on USB drives get automatically mounted, but that requires a GUI environment to be installed. On our servers at work, we generally do not install a GUI environment. We also had some special requirements in order to use the USB drives as backup targets:
  • The USB drive needs to mount at a standard location. Such as /mnt/offsite/LABEL or something. This way the backup scripts are not overly complex.
  • Mounting needs to be automatic, without any user intervention.
  • Ideally, the file system should be dismounted when not in use. That way the user who swaps out the backup drives only needs to check the drive activity light before knowing that it is safe to swap out the drive.

So the standard Ubuntu method of doing things via Gnome comes close, but I explored other options as well. The one I settled on is called 'autofs'. It is a script/daemon that is found in the standard CentOS 6 repositories, so you just need to run "yum install autofs".

Configuration of the autofs daemon consists of two parts:

A. You need to find and edit the master configuration file for autofs, also called the 'master map file'. Under CentOS 6, this is located at /etc/auto.master, or you can look at '/etc/sysconfig/autofs ' to find out the configuration file location.

If you want to mount your USB backup drives at /mnt/offsite/XYZ, then your auto.master file only needs to contain the following:

# USB backup drives
/mnt/offsite            /etc/auto.offsite       --timeout=1800

As you can see, you tell autofs the location, what configuration file to look at for devices that need to be mounted, and optional arguments such as custom timeout settings. Note that you need to create the location directory by hand (e.g. "# mkdir /mnt/offsite") before starting autofs.

B. The second part of configuration is telling autofs which devices should be automatically mounted. It is best if you use either the UUID of the partition (/dev/disk/by-uuid/XYZ) or the device ID (/dev/disk/by-id/XYZ-part0).

OFFSITE1 -fstype=ext4,rw,noatime,data=journal,commit=1 
    :/dev/disk/by-uuid/b5c1db0d-776f-499b-b4f2-ac53ec3bf0ef

Please note that the above should be all on line line, I have broken it up for clarity.

The only real mount options that you need is "fstype=auto,rw,noatime". I have added "data=journal,commit=1" to make the ext4 file system on the drive a bit more resilient.

One limitation of autofs is that if you have multiple USB drives to be mounted, each one needs its own unique mount point (/mnt/offsite/OFFSITE1, /mnt/offsite/OFFSITE2, etc.). However, you could decide to mount all of the drives at the same location if you give them all the same UUID. But I'm not sure how well autofs would deal with two drives, having the same UUID, being hooked up to the server at the same time.



After editing your mapping file, you (probably) need to restart autofs. Assuming that you have done everything correctly, attempting to list the contents 'ls -l /mnt/offsite/OFFSITE1' will cause the drive to be automatically mounted. After the timeout period expires, the drive will automatically dismount.

Updates (2015):

I have started to document this process in my "sync2usb" project over on GitHub.  Including using LUKS encryption to protect the contents of the USB drive against disclosure after loss/theft.

https://github.com/tgharold/sync2usb/blob/master/AUTOFS.md
https://github.com/tgharold/sync2usb/blob/master/LUKS.md