Installing Debian onto USB flash media with everything encrypted 

http://www.debian-administration.org/articles/179

by DaveV on Sat 9 Jul 2005

This is a simple procedure for installing Debian GNU/Linux onto a USB key flash media. It includes several configuration changes but tries to stay as close to a default debian install as possible.

This is useful for administrators that need to carry sensitive information or people concerned about their privacy.

This was tested on Debian Sid and Knoppix 3.8.

Installation Procedure 

  1. Shred the drive

    shred -n 1 -z -v /dev/sdd
    (One pass to shred, one pass to zero)
  2. Create Partitions

    We will create two partitions on the USB key, one for /boot and one for / (root). We do not create a swap partition because that would prematurely age the usb key. You may mount and use swap partitions from the local harddrives ala knoppix but that is up to you.

    parted /dev/sdd "mklabel msdos mkpart primary 0 14 mkpart primary 15 -0"
  3. Shred rootfs

    shred -n 1 -v /dev/sdd2
    (zero'd filesystems are bad for encrypted ones.)
  4. Load modules if necessary

    modprobe dm-crypt
    modprobe aes
    KNOPPIX NOTE: We need to install a few packages.
    apt-get update
    apt-get install cryptsetup dmsetup libdevmapper1.01
  5. Created mapped crypt device for root

    cryptsetup -y create rootfs /dev/sdd2
  6. Format filesystems:

    Since we can't use journaling filesystems on flash media (premature aging again), we fall back to good old ext2.

    mkfs.ext2 /dev/mapper/rootfs
    mkfs.ext2 /dev/sdd1
    sync ; sync
  7. Apply disk labels

    We do this so that we can identify our drive when we boot on various systems. Using a strict device mapping often breaks if other usb or flash devices are detected before ours.You may use any label that you like, but you will have to remember to update the initrd (file: /sbin/init)

    e2label /dev/sdd1 PRIVDEB_BOOT
  8. Make temporary mount points and mount

    mkdir /mnt/buildroot/
    mount /dev/mapper/rootfs /mnt/buildroot
    mkdir /mnt/buildroot/boot
    mount /dev/sdd1 /mnt/buildroot/boot
  9. Install base files.

    debootstrap --arch i386 sid /mnt/buildroot
    Note: Installed size is about 160MB at this stage.
    KNOPPIX NOTE: We need to copy a few extra devices over.
    cp -ap /dev/ub[a-f]* /mnt/buildroot/dev/
  10. Enter chroot jail to work on system.

    chroot /mnt/buildroot/ /bin/su -
  11. Build fstab and mount everything.

    Create /etc/fstab file

    #/etc/fstab: static file system information.
    #
    LABEL=PRIVDEB_BOOT  /boot          ext2    defaults,noatime                   0 2
    /dev/mapper/rootfs  /              ext2    defaults,errors=remount-ro,noatime 0 1
    proc                /proc          proc    defaults                           0 0
    tmpfs               /etc/network/run tmpfs defaults,noatime                   0 0
    tmpfs               /tmp           tmpfs   defaults,noatime                   0 0
    tmpfs               /var/lock      tmpfs   defaults,noatime                   0 0
    tmpfs               /var/log       tmpfs   defaults,noatime                   0 0
    tmpfs               /var/run       tmpfs   defaults,noatime                   0 0
    tmpfs               /var/tmp       tmpfs   defaults,noatime                   0 0
    tmpfs               /home//Scratch tmpfs defaults,noatime               0 0
    #Warning:  By mounting /var/log on tmpfs, logs will only be available for the current session.
    Mount it all
    mount -a
  12. Build sources.list

    Create /etc/apt/sources.list

    deb http://mirrors.kernel.org/debian/[] sid main non-free contrib
    deb-src http://mirrors.kernel.org/debian/[] sid main non-free contrib
    
    deb http://ftp.uk.debian.org/debian-non-US/[] sid non-US/main non-US/non-free non-US/contrib
    deb-src http://ftp.uk.debian.org/debian-non-US/[] sid non-US/main non-US/non-free non-US/contrib
    
    # If you are using debian stable (woody) include the security updates.
    # deb http://security.debian.org/[] sid/updates main non-free contrib

    Note: You can install and use apt-spy to test for the fastest downloading mirrors in your area.

  13. System adjustments

    blkid.tab: this file is cached as drives are scanned. Since the scan only takes a few seconds, you dont lose much by not caching or setting the default cache to /dev/null. This file generates an error on boot if the cache file has different device mappings than are currently detected. By removing the cache and forcing a fresh scan every time, the error is eliminated.

    rm -f /etc/blkid.tab*
    ln -s /dev/null /etc/blkid.tab

    mtab: This file is written a lot and may prematurely age parts of the flash media and the information can simply be accessed from /proc directly.

    rm -f /etc/mtab
    ln -s /proc/mounts /etc/mtab

    Set Hostname

    vi /etc/hostname

    Set /etc/hosts with localhost + hostname

    vim /etc/hosts
    127.0.0.1 localhost.localdoman localhost
  14. Install additional required packages

    apt-get update
    apt-get install cryptsetup dmsetup libdevmapper1.01
    apt-get install discover1 libdiscover1
    apt-get install module-init-tools equivs cramfsprogs
    apt-get clean
  15. Install custom mkinitrd script and equiv package

    Create mkinitrd.dmcrypt-usb file in /usr/local/sbin

    #!/bin/bash
    
    # Filename:      mkinitrd.dmcrypt-usb
    # Maintainer:    Dave Vehrs
    
    # Help
     : << HELP_STEXT
    Options:
        -c           Temporary directory to build image in.
        -k           Keep temporary directory used to build image.
        -l    Use  to indenify boot partition.
        -o  Write to outfie
        -d,-m,-r     Included for fake support of default mkinitrd script
                     (anything passed to them is discarded).
    
    See http://www.saout.de/tikiwiki/tiki-index.php?page=USBFlashMedia[] for more info.
    HELP_STEXT
    
    function display_shelp {
            echo; echo "Usage $0 [OPTION]...<-o outfile> [version]"
            sed --silent -e '/HELP_STEXT$/,/^HELP_STEXT/p' "$0" | sed -e '/HELP_STEXT/d'
    }
    
    # Set defaults
    BOOT_LABEL="PRIVDEB_BOOT"
    CRAMFSDIR=/tmp/cramfs
    keep_temp=0
    unset VERSION
    
    # Parse command line.
    # if version + other options not specified, exit.
    if [ $# -eq 0 ] ; then
        display_shelp
        exit 1
    fi
    
    while [ $# -ge 1 ] ; do
            case $1 in
            -c  ) CRAMFSDIR=$2          ; shift ; shift ;;
            -d  ) dir_conf=$2           ; shift ; shift ;;
            -k  ) keep_temp=1           ; shift ;;
            -l  ) BOOT_LABEL=$2         ; shift ; shift ;;
            -m  ) cmd_mkinitrd=$2       ; shift ; shift ;;
            -o  ) outfile_name=$2       ; shift ; shift ;;
            -r  ) initrd_root=$2        ; shift ; shift ;;
                    *   ) VERSION=$1            ; shift ;;
            esac
    done
    
    # Exit if version not specified
    if [ -z "$VERSION" ] ; then
        echo "Error: You need to specify a kernel version to build for."
        exit 1
    else
        VERSION=${VERSION##*/}
    fi
    
    # Start build...
    echo "Build directory tree."
    install -d $CRAMFSDIR/{bin,dev/mapper,etc,proc,mnt,sbin}
    
    echo "Copy binaries from /bin."
    # Copy /bin binaries over and any require libraries.
    files_bin="bash grep mount umount mkdir mknod sed sleep uname"
    for file in $files_bin ; do
        install /bin/$file $CRAMFSDIR/bin/$file
        for lib in $( ldd /bin/$file | awk '{print $3}' | grep -v fffe000 ) ; do
            install -d $CRAMFSDIR/${lib%/*}
            install $lib $CRAMFSDIR/$lib
        done
    done
    
    echo "Copy binaries from /usr/bin."
    # Copy /usr/bin binaries over and any require libraries.
    files_usrbin="find mawk"
    for file in $files_usrbin ; do
        install /usr/bin/$file $CRAMFSDIR/bin/$file
        for lib in $( ldd /usr/bin/$file | awk '{print $3}' | grep -v fffe000 ); do
            install -d $CRAMFSDIR/${lib%/*}
            install $lib $CRAMFSDIR/$lib
        done
    done
    
    echo "Copy binaries from /sbin."
    # Copy /sbin binaries over and any require libraries.
    files_sbin="cryptsetup e2label modprobe pivot_root"
    for file in $files_sbin ; do
        install /sbin/$file $CRAMFSDIR/sbin/$file
        for lib in $( ldd /sbin/$file | awk '{print $3}' | grep -v fffe000 ) ; do
            install -d $CRAMFSDIR/${lib%/*}
            install $lib $CRAMFSDIR/$lib
        done
    done
    
    # Add common links
    ln -s bash /tmp/cramfs/bin/sh
    ln -s mawk /tmp/cramfs/bin/awk
    
    echo "Copy devices over."
    # Copy devices over
    cp -apL /dev/{console,hd,initrd,null,ram,scd,sd}* $CRAMFSDIR/dev/
    
    echo "Copy modules over."
    # Copy modules over
    modules="aes-i586 dm-crypt sd_mod sr_mod ehci-hcd uhci-hcd ohci-hcd sl811-hcd usbhid usbkbd usb-storage vesafb fbcon ext2 unix"
    for mod in $modules; do
      for ko in $( modprobe --set-version $VERSION --show-depends $mod | cut -b8- ) ; do
        install -d $CRAMFSDIR/${ko%/*}
        install $ko $CRAMFSDIR/$ko
      done
    done
    
    cp -apL /lib/modules/$VERSION/modules.* $CRAMFSDIR/lib/modules/$VERSION/
    
    echo "Copy /etc files over."
    # Copy required config files over
    cp -apr /etc/modprobe.d $CRAMFSDIR/etc/
    echo "Copy custom init over."
    # Copy custom init file.  (see below)
    cat <$CRAMFSDIR/sbin/init
    #!/bin/bash
    
    # Filename:      /sbin/init
    # Dependencies:  awk, bash, cryptsetup, e2label, find, grep, modprobe
    #                mount, pivot_root, sed, sleep and uname.
    #
    # This file generated by mkinitrd.dmcrypt-usb by Dave Vehrs.
    set -e
    
    # Set vars
    unset pass part_boot part_rootfs major minor label
    dm_name="device-mapper"
    dm_dir="mapper"
    dir="/dev/\$dm_dir"
    control="\$dir/control"
    count=0
    
    # Mount /proc
    /bin/mount -n -t proc none /proc
    
    # Mount /dev/mapper on tmpfs
    /bin/mount -o rw -n -t tmpfs none /dev/mapper
    
    # Modules to load
    CORE_MODULES="unix ide-core scsi_mod sd_mod sr_mod mbcache ext2"
    DISPLAY_MODULES="vesafb fbcon"
    CRYPT_MODULES="aes-i586 dm-mod dm-crypt"
    USB_MODULES="ehci-hcd ohci-hcd uhci-hcd sl811-hcd usbcore usbhid usbkbd usb-storage"
    
    # Load Modules
    if [ -e /lib/modules/\$(/bin/uname -r) ] ; then
        echo "initrd: loading modules."
        for module in \$DISPLAY_MODULES \$CORE_MODULES \$CRYPT_MODULES \$USB_MODULES ; do
            /bin/find /lib/modules/\$(/bin/uname -r) -name \$module.ko -exec /sbin/modprobe \$module \;
        done
    fi
    
    # Test to be sure the procfs is mounted, if not exit.
    if [ ! -e /proc/devices ] ; then
        echo "initrd: procfs not found: please create \$control manually."
        exit 1
    fi
    
    major=\$(/bin/sed -n 's/^ *\\([0-9]\+\\) \+misc$/\1/p' /proc/devices)
    minor=\$(/bin/sed -n "s/^ *\\([0-9]\+\\) \+\$dm_name\\\$/\1/p" /proc/misc)
    
    # Test to be sure dm_mod loaded
    if [ -z "\$major" -o -z "\$minor" ] ; then
        echo "initrd: \$dm_name kernel module not loaded: can't create \$control."
        exit 1
    fi
    
    # Create new control device.
    echo "initrd: creating \$control character device with major:\$major minor:\$minor."
    /bin/mknod --mode=600 \$control c \$major \$minor
    
    # Sleep to let kernel finish loading.  15 seconds is enough on most systems.
    echo "initrd: sleeping for 15 seconds so kernel can finish detecting devices."
    /bin/sleep 5
    echo "initrd: sleeping for 10 more seconds..."
    /bin/sleep 5
    echo "initrd: sleeping for 5 more seconds..."
    /bin/sleep 5
    echo "initrd: awake...."
    
    # Search for boot partition label.  When usb media is detected by the operating
    # system seems to migrate a little depending on what port you connect to on the
    # mainboard and what if any other devices are connected and where.  To
    # compensate for that, we search for the label on our boot partition.
    echo "initrd: searching for boot partition label."
    for device in \$( /bin/grep sd[a-h]1 /proc/partitions | /bin/awk '{print \$4}' ) ; do
        label=\$( /sbin/e2label /dev/\$device 2>/dev/null )
        if [ ! -z "\$label" ] ; then
            if [ "\$label" == "$BOOT_LABEL" ] ; then
                part_boot="/dev/\$device"
            break
            fi
        fi
    done
    
    # Exit if boot partition not found.
    if [ -z "\$part_boot" ] ; then
        echo "initrd: error -- boot partition label not found (\$part_boot)."
        exit 1
    fi
    
    # Assign rootfs variable from boot (i.e. if boot is on /dev/sda1, this will
    # set part_rootfs to /dev/sda2).
    part_rootfs=\$( echo \$part_boot | /bin/sed -e 's/1/2/' )
    
    # Unmount /proc
    /bin/umount /proc
    
    # Prompt for password
    echo -en "\\nplease enter password for rootfs filesystem: "
    read -s pass
    echo -e
    
    # Attempt mounting
    echo "initrd: attempting to mount rootfs."
    echo \$pass | /sbin/cryptsetup create rootfs \$part_rootfs
    /bin/mount -r -n -t ext2 /dev/mapper/rootfs /mnt
    
    # Loop for bad password attempts
    while [ \$? -ne 0  ] ; do
        # Remove old crypt mount.
        /sbin/cryptsetup remove rootfs
    
        # Test for max tries.
        if [ \$count -ge 5 ] ; then
            echo -e "\\ninitrd: too many bad guesses.  aborting."
            exit 1
        else
            count=\$(( \$count + 1 ))
        fi
    
        # Reprompt for password
        echo -e "\\ninitrd: error -- rootfs mount failed."
        echo -n "please re-enter password: "
        read -s pass
        echo
    
        # Reattempt mounting
        echo \$pass | /sbin/cryptsetup create rootfs \$part_rootfs
        /bin/mount -r -n -t ext2 /dev/mapper/rootfs /mnt
    done
    
    unset pass
    
    echo "initrd: rootfs successfully mounted."
    
    # Now that the encrypted media is readable, shift the root to it and continue
    # the boot cycle by running its init.
    cd /mnt
    /sbin/pivot_root . initrd
    exec /usr/sbin/chroot . /sbin/init
    EOF
    chown root:root $CRAMFSDIR/sbin/init
    chmod 755 $CRAMFSDIR/sbin/init
    
    # make cramfs file
    if [ -z "$outfile_name" ] ; then
        mkcramfs $CRAMFSDIR ./initrd-$VERSION.img
    else
        mkcramfs $CRAMFSDIR $outfile_name
    fi
    
    # Cleanup
    if [ $keep_temp -eq 0 ] ; then
        rm -rf $CRAMFSDIR
    fi

    Set permissions, and links.

    chown root.root /usr/local/sbin/mkinitrd.dmcrypt-usb
    chmod 750 /usr/local/sbin/mkinitrd.dmcrypt-usb
    ln -s /usr/local/sbin/mkinitrd.dmcrypt-usb /usr/sbin/mkinitrd

    Next we need to install an equivs package to let the package system know that we installed this ourselves and not to install initrd-tools

    cd /tmp
    equivs-control initrd-tools

    Edit the generated template so that it looks like:

    Section: misc
    Priority: optional
    Standards-Version:
    Package: initrd-tools

    Build equivs package

    equivs-build initrd-tools

    Install the package

    dpkg -i initrd-tools_1.0_all.deb

    For more information about equivs, see the APT howto at: APT-Howto: Equivs

  16. Remove unwanted locales

    Be very careful configuring and running localepurge. It is very easy to delete too many locales. For more information about localepurge, see the APT howto at: APT-Howto: localepurge

    apt-get install localepurge
    localepurge
    apt-get clean
  17. Install kernel

    [Warning]

    Kernels prior to 2.6.10 had a bug in the dm_crypt modules that potentially could reveal data. Only use 2.6.10 or better.

    apt-get install kernel-image-2.6.11-1-686
    apt-get clean
    [Note]

    Install size is approximately 184MB now. If you want to install a kernel built from source you can. After you install it, run /sbin/mkinitrd to build the /boot/initrd file. When you run /sbin/mkinitrd, it may print several FATAL errors regarding modules that it cannot find. If you built these modules into the kernel then you can ignore the error messages. If you omitted the modules, this is your warning to go build them as modules or into the kernel. Required modules: dm_crypt, aes, ide_core, scsi_mod, sd_mod, ehci-hcd, ohci-hcd, uhci-hcd, sl811-hcd, usb-storage, usb-hid, dm_mod, cramfs

  18. Install optional packages

    apt-get install vim irsii-text mutt fetchmail antiword screen
    apt-get install exuberant-ctags less procmail
    apt-get install python2.3 python2.3-pexpect python2.3-fuse
    apt-get install xserver-common xserver-xfree86 xbase-clients xfree86-common
    apt-get install ion3 -or- blackbox -or- fluxbox -or- icewm
    apt-get install xterm
    apt-get install memtest86+
    Note: All this is approximately 300mb installed (with dependencies).
  19. Install grub

    apt-get install grub
    grub-install /dev/sdd
    mkdir /boot/grub
    grub
     root (hd1,0)
     setup (hd1)
     quit

    Create /boot/grub/menu.lst file

    # default num
    default         0
    
    # timeout sec
    timeout         5
    
    # pretty colours
    color green/black black/green
    
    title   Debian GNU/Linux-2.6.11-1-686
    root    (hd0,0)
    kernel  /vmlinuz-2.6.11-1-686 root=/dev/ram0 init=/sbin/init vga=794
    initrd  /initrd.img-2.6.11-1-686
    savedefault
    boot
    
    title   Debian GNU/Linux-2.6.11-1-686 (Rescue/Single)
    root    (hd0,0)
    kernel  /vmlinuz-2.6.11-1-686 root=/dev/ram0 init=/sbin/init single
    initrd  /initrd.img-2.6.11-1-686
    boot
    
    title   Memtest86+
    root    (hd0,0)
    kernel  /memtest86+.bin
    boot
  20. Add User accounts

    Either:

    Copy an existing /etc/group, /etc/passwd, and /etc/shadow file over from another system (this has to be done from outside the chroot directory).

    Or:

    Add users locally.

    1. set root password

      passwd root
    2. add local user

      useradd
      passwd
    3. repeat step 2 as necessary
  21. Exit Jail

    umount -a
    umount /proc
    exit
  22. Unmount and remove crypt mapping

    cd
    umount /mnt/buildroot/
    cryptsetup remove rootfs
  23. Reboot to test media

    shutdown -r now

MOUNTING ON ANOTHER LINUX SYSTEM

  1. Make sure required modules are loaded.

    modprobe dm_crypt
    modprobe aes-i586  (or aes)
    modprobe usb-storage
  2. Insert USB key into port
  3. Create device mapping and mount

    cryptsetup create rootfs /dev/sdd2
    mount /dev/mapper/rootfs /mnt/buildroot

documented on: 2007.01.12