Friday, December 20, 2013

How-to: Create a gzipped tarball via SSH

I recently needed to remotely backup a server and store the data on another system. However my complication was that there wasn't enough space on the server to create the backup then transfer it to the remote system. I thought about using scp but that creates a lot of overhead as each file transfer is essentially a new SSH session. The crux was that I needed to keep the data secure but transfer within a short amount of time. I thought about using netcat, but that would mean the data would be going across the wire unencrypted even if I compressed it using gzip.

I ultimately decided that I needed SSH, tar and gzip. I popped up the manual page for tar and found that I can send the output to stdout (standard out). I immediately knew this was the best solution for the problem; I tinkered around a bit and developed a command that would allow me to use SSH, tar and gzip. The way it works is you send the tar command through SSH, tell tar to output via stdout and redirect the output from SSH to a gzipped tarball. The only downside is I had to temporarily enable root access via SSH; this is required if you're going to archive the whole file system. You can see how I accomplished the remote backup using the command below:

$ ssh root@remote.host.com 'tar -czvf - / --exclude=/dev --exclude=/proc --exclude=/var/run --exclude=/tmp --exclude=/sys --exclude=/usr/lib' > my-server-backup.tar.gz

I'll break down the command for you:

$ ssh root@remote.host.com 'command'

With SSH you can run commands remotely and the output will be displayed in your local terminal. The tar command:

 tar -czvf - / --exclude=/dev --exclude=/proc --exclude=/var/run --exclude=/tmp --exclude=/sys --exclude=/usr/lib

We invoke tar on the remote machine, telling it to create a gzipped tarball and list the files as it compresses them (czvf). Normally where we would specify the archive's file name we place a hyphen (-) which tells tar to output the archive to stdout (standard out, our screen). We want to backup the whole file system so we tell tar to start at the root of the directory tree (/) but we don't need libraries, device descriptors, process or temp files; thus we exclude specific directories with the exclude flag (--exclude=/dir/to/leave/behind). The last part of the command is important:

 > my-server-backup.tar.gz

We redirect the output to a file on the system receiving the archive; this is what the greater-than symbol does. To store the output into a file we specify a file name (my-server-backup.tar.gz); the ".tar.gz" extension identifies the file as a gzipped-tarball. To look at it without the confusion of the tar command:

 $ ssh root@remote.host.com 'command' > output.file

You can essentially perform the same function with any other command, so long as it supports outputting the data via stdout. At any rate, if you were to run the tar command all you (the user) would see is the file listing, like such:

$ ssh sysadmin@my.server.com 'tar -czvf - Downloads/' > sysadmin-downloads.tar.gz
Downloads/
Downloads/file-a.txt
Downloads/file-b.txt
Downloads/file-c.txt

In the above example, I made a backup of the Downloads directory that resides in the sysadmin user's home directory. You can even check to make sure the file is of the appropriate format using the file command:

$ file sysadmin-downloads.tar.gz
sysadmin-downloads.tar.gz: gzip compressed data, from Unix, last modified: Fri Dec 20 17:53:28 2013

There you have it! A remote, compressed backup streamed to your server or workstation over SSH. Until next time, my friends ...

Thursday, December 12, 2013

How-to: Check the bit-length of an SSH RSA keypair

As a SysAdmin, some of my responsibilities include maintaining system security, access and auditing accounts. However, from time to time I've come across the need to check a public key to make sure it conforms with my requirements. I've performed this operation enough times that I thought I would make a short post to help others in this situation. Albeit a simple solution, its not very obvious.

Let's begin by creating a public/private key pair:

$ ssh-keygen -t rsa -b 4096
Generating public/private rsa key pair.
Enter file in which to save the key (/home/derp/.ssh/id_rsa): derp_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in derp_rsa.
Your public key has been saved in derp_rsa.pub.
The key fingerprint is:
fe:5c:60:be:46:54:10:7a:25:19:63:cb:67:ce:09:62 derp@herpderp
The key's randomart image is:
+--[ RSA 4096]----+
|          B=.    |
|         +.=.    |
|        E =.o    |
|       . o.* .   |
|        S.o +    |
|       . o..     |
|        ... .    |
|         o.o     |
|         .+      |
+-----------------+


Since the public key is what is provided by the user, that is all the SysAdmin will ever see. To check the public key, we test it like so:

$ ssh-keygen -lf derp_rsa.pub
4096 fe:5c:60:be:46:54:10:7a:25:19:63:cb:67:ce:09:62 derp_rsa.pub (RSA)


As you can see, the bit-length is printed at the beginning of the string (4096), followed by the key's fingerprint, the file name and the encryption algorithm (RSA). Looking at a raw pubkey doesn't allow one to easily identify the bit-length.

If you are the one providing the public key, you can easily check the bit-length of your private key with a simple command and pipe it to grep:

$ openssl rsa -text -noout -in derp_rsa | grep -i "private\-key"
Private-Key: (4096 bit)


Simple enough? Yup! To take it one step further, if you have multiple key pairs to manage, here is a simple way to test them against each other. You simply compare the fingerprint of the private key with the public key:

$ ssh-keygen -lf derp_rsa && ssh-keygen -lf derp_rsa.pub
4096 fe:5c:60:be:46:54:10:7a:25:19:63:cb:67:ce:09:62 derp_rsa.pub (RSA)
4096 fe:5c:60:be:46:54:10:7a:25:19:63:cb:67:ce:09:62 derp_rsa.pub (RSA)


There you have it! Until next time ...

Monday, December 9, 2013

Random Password Generator

I recently needed a facility for easily generating random passwords for new accounts on a server. I looked at different packages but I didn't find anything that was satisfactory. I then stumbled across a blog post that talked about using openssl to generate random passwords. I started toying with openssl and was able to generate a 12-byte base64 string:
$ openssl rand -base64 12
Elg6gD/+jGAl88/S
However, I needed the password simple enough to give to users which meant I needed to remove the special characters. I know, removing special characters decreases security and increases the attack vector. However, these are SFTP accounts that are chrooted with no shell ... so I'm not too concerned. Moving forward, I decided to use sed to remove the characters:
$ echo "Elg6gD/+jGAl88/S" | sed 's/\///g' | sed 's/\+//g' | sed 's/\=//g'
Elg6gDjGAl88S
Goodie. Now, I need to keep it out of memory and store it in a randomly named temporary text file; mktemp to the rescue! With that in mind, I now had everything I needed to build a function:
makepass (){
    local TMPFILE=$(eval mktemp)
    openssl rand -base64 12 > $TMPFILE
    sed -i 's/\///g' $TMPFILE
    sed -i 's/\+//g' $TMPFILE
    sed -i 's/\=//g' $TMPFILE
    cat $TMPFILE; rm -f $TMPFILE
}
Now, implementing it was easy as one, two, three:
PASS = $(eval makepass)
echo $PASS | passwd --stdin NewUser
Huzzah! Once the account setup is done, all I do is echo $PASS so that the SysAdmin (me) can provide it to the end user.

Until next time and as Richard Stallman says, "Happy hacking, folks."