Linux DevCenter    
 Published on Linux DevCenter (http://www.linuxdevcenter.com/)
 See this if you're having trouble printing code examples


O'Reilly Book Excerpts: Linux Security Cookbook

Secure Cooking with Linux, Part 1

Related Reading

Linux Security Cookbook
By Daniel J. Barrett, Richard E. Silverman, Robert G. Byrnes

by Daniel J. Barrett, Richard E. Silverman, Robert G. Byrnes

Editor's note: The authors of Linux Security Cookbook have selected a number of recipes from their book to present here. These recipes are organized into basic, intermediate, and advanced categories. This week's set consists of three recipes of a basic flavor. Over the next two weeks we'll present the intermediate and then advanced recipes. There'll be something for everyone here. Enjoy.

Recipe 6.4: Authenticating by Public Key (OpenSSH)

Author's note: SSH is a protocol for secure, remote logins and file copying; and OpenSSH, provided with most Linux distributions, is its most popular implementation. This recipe, selected from Chapter 6 on "Protecting Outgoing Network Connections," shows you how to use public-key authentication to prove your identity to a remote OpenSSH server, a technique more secure than using login passwords.

Problem

You want to set up public-key authentication between an OpenSSH client and an OpenSSH server.

Solution

  1. Generate a key if necessary:

    $ mkdir -p ~/.ssh  If it doesn't already exist
    $ chmod 700 ~/.ssh
    $ cd ~/.ssh
    $ ssh-keygen -t dsa
  2. Copy the public key to the remote host:

    $ scp -p id_dsa.pub remoteuser@remotehost:
    Password: ********
  3. Log into the remote host and install the public key:

    $ ssh -l remoteuser remotehost
    Password: ********
    
    remotehost$ mkdir -p ~/.ssh If it doesn't already exist
    remotehost$ chmod 700 ~/.ssh
    remotehost$ cat id_dsa.pub >> ~/.ssh/authorized_keys  (Appending)
    remotehost$ chmod 600 ~/.ssh/authorized_keys
    remotehost$ mv id_dsa.pub ~/.ssh Optional, just to be organized
    remotehost$ logout
  4. Log back in via public-key authentication:

    $ ssh -l remoteuser remotehost
    Enter passphrase for key '/home/smith/.ssh/id_dsa': ********

Tip

OpenSSH public keys go into the file ~/.ssh/authorized_keys. Older versions of OpenSSH, however, require SSH-2 protocol keys to be in ~/.ssh/authorized_keys2.

Discussion

Public-key authentication lets you prove your identity to a remote host using a cryptographic key instead of a login password. SSH keys are more secure than passwords because keys are never transmitted over the network, whereas passwords are (albeit encrypted). Also, keys are stored encrypted, so if someone steals yours, it's useless without the passphrase for decrypting it. A stolen password, on the other hand, is immediately usable.

An SSH "key" is actually a matched pair of keys stored in two files. The private or secret key remains on the client machine, encrypted with a passphrase. The public key is copied to the remote (server) machine. When establishing a connection, the SSH client and server perform a complex negotiation based on the private and public key, and if they match (in a cryptographic sense), your identity is proven and the connection succeeds.

To set up public-key authentication, first create an OpenSSH key pair, if you don't already have one:

$ ssh-keygen -t dsa
Generating public/private dsa key pair.
Enter file in which to save the key (/home/smith/.ssh/id_dsa): <RETURN>
Enter passphrase (empty for no passphrase): *******
Enter same passphrase again: *******
Your identification has been saved in id_dsa
Your public key has been saved in id_dsa.pub.
The key fingerprint is: 76:00:b3:e8:99:1c:07:9b:84:af:67:69:b6:b4:12:17 
   smith@mymachine

Copy the public key to the remote host using password authentication:

$ scp ~/.ssh/id_dsa.pub remoteuser@remotehost:
Password: *********
id_dsa.pub      100% |*****************************|     736    00:03

Log into the remote host using password authentication:

$ ssh -l remoteuser remotehost
Password: ********

If your local and remote usernames are the same, you can omit the -l remoteuser part and just type ssh remotehost.

On the remote host, create the ~/.ssh directory if it doesn't already exist and set its mode appropriately:

remotehost$ mkdir -p ~/.ssh
remotehost$ chmod 700 ~/.ssh

Then append the contents of id_dsa.pub to ~/.ssh/authorized_keys:

remotehost$ cat id_dsa.pub >> ~/.ssh/authorized_keys    (Appending)
remotehost$ chmod 600 ~/.ssh/authorized_keys

Log out of the remote host and log back in. This time you'll be prompted for your key passphrase instead of your password:

$ ssh -l remoteuser remotehost
Enter passphrase for key '/home/smith/.ssh/id_dsa': *******

and you're done! If things aren't working, rerun ssh with the -v option (verbose) to help diagnose the problem.

The SSH server must be configured to permit public-key authentication, which is the default:

/etc/ssh/sshd_config:
PubkeyAuthentication yes If no, change it and restart sshd

For more convenience, you can eliminate the passphrase prompt using ssh-agent [Recipe 6.9] and create host aliases in ~/.ssh/config. [Recipe 6.12]

See Also

ssh(1), scp(1), ssh-keygen(1).

SSH-2 Key File Formats

The two major implementations of SSH—OpenSSH and SSH Secure Shell ("SSH2")—use different file formats for SSH-2 protocol keys. (Their SSH-1 protocol keys are compatible.) OpenSSH public keys for the SSH-2 protocol begin like this:

ssh-dss A9AAB3NzaC1iGMqHpSCEliaouBun8FF9t8p...

or:

ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA3DIqRox...

SSH Secure Shell public keys for the SSH-2 protocol look like this:

---- BEGIN SSH2 PUBLIC KEY ---- 
AAAAB3NzaC1kc3MAAACBAM4a2KKBE6zhPBgRx4q6Dbjxo5hXNKNWYIGkX/W/k5PqcCH0J6 ...
---- END SSH2 PUBLIC KEY ----

These keys are installed differently too. For OpenSSH, you insert your public keys into the file ~/.ssh/authorized_keys. For SSH Secure Shell, you copy your public key files into the directory ~/.ssh2 and reference them in the file ~/.ssh2/authorization by name:

Key public_key_filename

As for private keys, OpenSSH has no special requirements for installation, but SSH Secure Shell does. You must reference them in the file ~/.ssh2/identification by name:

IdKey private_key_filename

Recipe 7.25: Encrypting Backups

Author's note: If someone steals one of your backup tapes, your sensitive information could become compromised. This recipe, excerpted from Chapter 7 on "Protecting Files," illustrates how to encrypt the contents of a backup tape using GnuPG (gpg), a popular encryption program for Linux and other operating systems.

Problem

You want to create an encrypted backup.

Solution

Method 1: Pipe through gpg.

Method 2: Encrypt files separately.

  1. Make a new directory containing links to your original files:

    $ cp -lr mydir newdir
  2. In the new directory, encrypt each file, and remove the links to the unencrypted files:

    $ find newdir -type f -exec gpg -e '{}' \; -exec rm '{}' \;
  3. Back up the new directory with the encrypted data:

    $ tar c newdir

Discussion

Method 1 produces a backup that may be considered fragile: one big encrypted file. If part of the backup gets corrupted, you might be unable to decrypt any of it.

Method 2 avoids this problem. The cp -l option creates hard links, which can only be used within a single filesystem. If you want the encrypted files on a separate filesystem, use symbolic links instead:

$ cp -sr /full/path/to/mydir newdir
$ find newdir -type l -exec gpg -e '{}' \; -exec rm '{}' \;

Note that a full, absolute pathname must be used for the original directory in this case.

gpg does not preserve the owner, group, permissions, or modification times of the files. To retain this information in your backups, copy the attributes from the original files to the encrypted files, before the links to the original files are deleted:

# find newdir -type f -exec gpg -e '{}' \; \
                      -exec chown --reference='{}' '{}.gpg' \;
                      -exec chmod --reference='{}' '{}.gpg' \;
                      -exec touch --reference='{}' '{}.gpg' \;
                          -exec rm '{}' \;

Method 2 and the CD-ROM variant of method 1 use disk space (at least temporarily) for the encrypted files.

See Also

gpg(1), tar(1), find(1), cdrecord(1).

Recipe 9.35: Combining Log Files

Author's note: Each system log file in /var/log contains different information about your running Linux system. This recipe from Chapter 9 on "Testing and Monitoring" shows how to merge multiple log files, keeping the lines in sorted order by timestamp, which is trickier than you might think.

Problem

You want to merge a collection of log files into a single, chronological log file.

Solution

#!/bin/sh
perl -ne \
   'print $last, /last message repeated \d+ times$/ ? "\0" : "\n" if $last;
    chomp($last = $_);    
    if (eof) {
        print;
        undef $last;
    }' "$@" | sort -s -k 1,1M -k 2,2n -k 3,3 | tr '\0' '\n'

Discussion

The system logger automatically prepends a timestamp to each message, like this:

Feb 21 12:34:56 buster kernel: device eth0 entered promiscuous mode

To merge log files, sort each one by its timestamp entries, using the first three fields (month, date, and time) as keys.

A complication arises because the system logger inserts "repetition messages" to conserve log file space:

Feb 21 12:48:16 buster last message repeated 7923 times

The timestamp for the repetition message is often later than the last message. It would be terribly misleading if possibly unrelated messages from other log files were merged between the last message and its associated repetition message.

To avoid this, our Perl script glues together the last message with a subsequent repetition message (if present), inserting a null character between them: this is reliable because the system logger never writes null characters to log files. The script writes out the final line before the end of each file and then forgets the last line, to avoid any possibility of confusion if the next file happens to start with an unrelated repetition message.

The sort command sees these null-glued combinations as single lines, and keeps them together as the files are merged. The null characters are translated back to newlines after the files are sorted, to split the combinations back into separate lines.

We use sort -s to avoid sorting entire lines if all of the keys are equal: this preserves the original order of messages with the same timestamp, at least within each original log file.

If you have configured the system logger to write messages to multiple log files, then you may wish to remove duplicates as you merge. This can be done by using sort -u instead of -s, and adding an extra sort key -k 4 to compare the message contents. There is a drawback, however: messages could be rearranged if they have the same timestamp. All of the issues related to sort -s and -u are consequences of the one-second resolution of the timestamps used by the system logger.

We'll note a few other pitfalls related to timestamps. The system logger does not record the year, so if your log files cross a year boundary, then you will need to merge the log files for each year separately, and concatenate the results. Similarly, the system logger writes timestamps using the local time zone, so you should avoid merging log files that cross a daylight saving time boundary, when the timestamps can go backward. Again, split the log files on either side of the discontinuity, merge separately, and then concatenate.

If your system logger is configured to receive messages from other machines, note that the timestamps are generated on the machine where the log files are stored. This allows consistent sorting of messages even from machines in different time zones.

See Also

sort(1).

Be sure to check back here next week for recipes from Linux Security Cookbook on how to restrict access to network services by time of day, and on how to use sudo to permit read-only access to a shared file.


Return to Linux DevCenter.

Copyright © 2009 O'Reilly Media, Inc.