This is a guide to installing Ubuntu 14.04 LTS on an Hetzner VX6 vServer using LUKS encryption of the root partition. The guide is inspiried by blog posts of Martin Carpella and Oliver Feiler. On reboot you will be able to log in via ssh to provide the password for the LUKS partition (using dropbear and busybox).
As pointed out by Martin Carpella it may sound stupid to encrypt the disk of a virtual machine as the private key can be pulled from memory by the host (i.e. Hetzner). However, encrypting all data on the disk protects it in case you cancel the vServer, or the vServer gets moved to a new host, or a failed disk is returned to the manufacturer or discarded etc. So it is more a matter of protecting the data if the VM is cancelled/offline rather than online. If you do not want Hetzner to be able to pull the private key, go for something other than a virtual machine (e.g. a root server).
Anyway, here we go!
When signing up for the vServer select the Hetzner Ubuntu 14.04 LTS 64-bit minimal-install image. Once the server is setup log in via SSH and make backups of these files:
/etc/hostname
/etc/hosts
/etc/resolv.conf
/etc/network/interfaces
Log into the Hetzner robot interface and select 64-bit Linux rescue system, take note of the password for rescue system ssh login displayed on the page. Reboot your vServer in rescue mode and log in.
Setup disk partitions using fdisk:
1
fdisk /dev/vda
Create a boot partition of 256 MB (/dev/vda1) and a root partition of the remaining free space (/dev/vda2). Mark the boot partition as bootable. My partition table looks like this:
12345678910
Disk /dev/vda: 26.8 GB, 26843545600 bytes
255 heads, 63 sectors/track, 3263 cylinders, total 52428800 sectors
Units= sectors of 1 * 512=512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x00044f0a
Device Boot Start End Blocks Id System
/dev/vda1 * 204852633526214483 Linux
/dev/vda2 526336524287992595123283 Linux
Create the encrypted partition (enter passphrase when prompted):
blkid /dev/vda1 /dev/vda2 /dev/vg-encrypted/root /dev/vg-encrypted/swap
# These are my UUIDs/dev/vda1: UUID="409938b1-7244-4c34-a665-8f086dd1c5f9"TYPE="ext2"/dev/vda2: UUID="b360acf3-b392-417f-bc08-90f378a5d26b"TYPE="crypto_LUKS"/dev/vg-encrypted/root: UUID="efc68b96-de3d-4cb9-a884-127dca8c97d5"TYPE="ext4"/dev/vg-encrypted/swap: UUID="6556fbea-0e34-4f4e-92cc-c18b3ccb0ece"TYPE="swap"
MAke a chroot directory (/mnt/ubuntu) and mount volumes:
To enter the LUKS passphrase upon boot, first save the following script as unlock-cryptroot on your computer (not the vServer) and make it executable (chmod +x unlock-cryptroot):
#!/bin/shusage(){ cat <<EOF${0##*/}: Remotely unlock a LUKS-encrypted Ubuntu root filesystemWorks around bug #595648 <https://bugs.launchpad.net/bugs/595648>Usage: $0 [options] [--] <host>Arguments: -h, --help Display this usage message and exit -i <identity_file>, --identity <identity_file>, --identity=<identity_file> Path to the SSH private key. Default: ${idbase}<host> -k <knownhosts>, --known-hosts <knownhosts>, --known-hosts=<knownhosts> Path to the 'known_hosts' file. Default: ${knownhosts} -l, --login Just log in, don't try to unlock the system. -- End of options; treat the next argument as the hostname even if it begins with '-'. <host> The name of the remote system to unlockEOF}# handy logging and error handling functionslog(){printf'%s\n'"$*";}error(){ log "ERROR: $@" >&2;}fatal(){ error "$@";exit 1;}try(){"$@"|| fatal "'$@' failed";}usage_fatal(){ usage >&2;printf'\n' >&2; fatal "$@";}# quote special characters so that:# eval "set -- $(shell_quote "$@")"# is always a no-op no matter what values are in the positional# parameters. note that it is run in a subshell to protect the# caller's environment.shell_quote()(sep=for i in "$@";doiesc=$(printf %s\\n "${i}eoi"| sed -e "s/'/'\\\\''/g")iesc=\'${iesc%eoi}\'printf %s "${sep}${iesc}"sep=" "done)# parse argumentsknownhosts=~/.ssh/known_hosts.initramfs
idbase=~/.ssh/id_rsa.initramfs_
unset id
runscript=truewhile["$#" -gt 0];doarg=$1case$1 in
# convert "--opt=the value" to --opt "the value". --*'='*)shift;set -- "${arg%%=*}""${arg#*=}""$@";continue;; -h|--help) usage;exit 0;; -i|--identity)shift;id=$1;; -k|--known-hosts)shift;knownhosts=$1;; -l|--login)runscript=false;; --)shift;break;; -*) usage_fatal "unknown option: '$1'";; *)break;;esacshift|| usage_fatal "option '${arg}' requires a value"done["$#" -ge 1]|| usage_fatal "no hostname specified"host=$1;shift["$#" -eq 0]|| fatal "unknown argument: '$1'"[ -n "${id+set}"]||id=${idbase}${host%%.*}[ -r "${id}"]|| fatal "can't read ssh key ${id}"script='#!/bin/shPATH=/sbin:${PATH}p() { printf %s\\n "$*"; }log() { p "$@"; }warn() { log "WARNING: $@" >&2; }error() { log "ERROR: $@" >&2; }fatal() { error "$@"; exit 1; }try() { "$@" || fatal "'\''$@'\'' failed"; }getpid() { psout=$(try ps) || exit 1 psout=$(p "${psout}" | grep "$1") || return 0 pswc=$(p "${psout}" | try wc -l) || exit 1 [ "${pswc}" -eq 1 ] || fatal "more than one instance of $1:${psout}" p "${psout}" | try awk '\''{print$1}'\'' || exit 1}# if cryptroot is not running, then there is no password prompt so# there is nothing to dolog "checking if /scripts/local-top/cryptroot is running..."cr_pid=$(getpid "/scripts/local-top/[c]ryptroot") || exit 1[ -n "${cr_pid}" ] || fatal "/scripts/local-top/cryptroot is not running"unset pw# keep prompting for a password over and over until cryptroot has# finished runningwhile true; do cs_pid=$(getpid "/sbin/[c]ryptsetup") || exit 1 [ -n "${cs_pid}" ] || { log "waiting to see if there will be another passphrase prompt..." # the next commands are all on one line so that they are still # in busybox memory if the root filesystem is mounted during # the sleep (which would cause this script to disappear during # execution) sleep 1; [ -d /proc/"${cr_pid}" ] || { log "done"; exit 0; } continue } log "getting /sbin/cryptsetup command-line arguments..." cs_args=$(try tr "\\0" "\\n" </proc/${cs_pid}/cmdline) || exit 1 set -- while IFS= read -r line; do set -- "$@" "${line}" done <<EOF${cs_args}EOF log "command: $@" [ -n "${pw+set}" ] && { log "trying previously entered passphrase..." printf %s "${pw}" | try "$@" } || { pw=$(try /lib/cryptsetup/askpass "Enter passphrase: " && echo x) \ || exit 1 pw=${pw%x} printf %s "${pw}" | try "$@" || exit 1 } log "passphrase accepted; killing passphrase prompt..." for ap in \ "/lib/cryptsetup/[a]skpass" \ "[a]sk-for-password" \ ; do log " checking for ${ap}..." ap_pid=$(getpid "${ap}") || exit 1 [ -n "${ap_pid}" ] || continue log " killing PID ${ap_pid}..." try kill "${ap_pid}" donedone'run_ssh(){unset forcetty
case$1 in -t)forcetty=$1;shift;;esac ssh -o UserKnownHostsFile="${knownhosts}"\ -i "${id}"\${forcetty}\ root@"${host}""$@"}# $1 is the shell command to run; must be < 1024 characters (busybox# limitation?)run_ssh_cmd(){unset forcetty
case$1 in -t)forcetty=$1;shift;;esacsshcmd='sh -c '$(shell_quote "$1")' -' run_ssh ${forcetty}"${sshcmd}"}"${runscript}"||{whileIFS=read -r line;do log "${line}"done<<\EOFAfter you are logged in: 1. use 'ps -l' to get cryptsetup's command-line arguments 2. run: /lib/cryptsetup/askpass "Enter passphrase: " \ | /sbin/cryptsetup <args go here> 3. kill 'plymouth ask-for-password' or 'askpass' as appropriate 4. log outEOF run_ssh
exit$?}log "sending script to ${host}..."printf %s\\n "${script}"|run_ssh_cmd 'cat >tmp.sh && chmod +x tmp.sh'\|| fatal "unable to create script"log "running script on ${host}..."run_ssh_cmd -t './tmp.sh'
Use the script like this (enter passphrase when prompted, use the IP address of your own vServer)
In Denmark we have a public single-sign-on solution, NEMID. To set up NEMID on Hardware (if you have the Gemalto USB token) on Ubuntu 14.04 you have to install the proper token driver and a build environment for building the NEMID driver. These are the required commands (inspired by this post):
Then download the driver from NEMID, extract and configure:
1234
wget https://www.nemid.nu/dk-da/support/aktiver_nemid/aktiver_nemid_paa_hardware/installer_driver/drivers/libgtop11dotnet_2.2.0.12.tar.gz
tar xpzf libgtop11dotnet_2.2.0.12.tar.gz
cd libgtop11dotnet-2.2.0.12
./configure
Next, make and make install:
12
make
sudo make install
You will also need the icedtea-plugin (for web-browsers).
Our daughter dropped our old Dell Inspiron 1720 that she uses for kids television. After the fall it would not boot and CAPS lock was blinking. Apparently, the RAM had been unseated, so it was an easy fix. The following procedure worked:
Unplug the AC and battery. Remove both the RAM modules as well.
Press the power button. This will help to loose all electrical static remains left in it. Hold it for about 10 seconds.
Then plugin the AC and turn on - it should automatically shut itself off again due to the absence of the RAM modules. However if it doesn’t or if it blinks again then just power it down.
Remove the AC, then re-install both the RAM modules, then press the power button again for the same 10 seconds to loose all discharge especially from the RAM itself. Then plugin only the AC. Power it. See if it works this time round.
Before you can setup Nginx for serving pages via SSL/TLS you should obtain a certificate (e.g. test.wbnet.dk.crt) and a private key (e.g. test.wbnet.dk.key).
To server pages via SSL/TLS with SSL 3.0 disabled (due to Poodlebleed) use a Nginx configuration like (adapted from this):
server { listen 443 ssl; server_name test.wbnet.dk; ssl on; ssl_certificate /opt/local/etc/nginx/ssl/wbnet.dk/test.wbnet.dk.crt; ssl_certificate_key /opt/local/etc/nginx/ssl/wbnet.dk/test.wbnet.dk.key;# enable session resumption to improve https performance# http://vincent.bernat.im/en/blog/2011-ssl-session-reuse-rfc5077.html ssl_session_cache shared:SSL:1m; ssl_session_timeout 5m;# Diffie-Hellman parameter for DHE ciphersuites, recommended 2048 bits# to generate use: openssl dhparam -rand – 2048 ssl_dhparam /opt/local/etc/nginx/ssl/dhparam.pem;# read more here http://tautt.com/best-nginx-configuration-for-security/# don't send the nginx version number in error pages and Server header server_tokens off;# config to don't allow the browser to render the page inside an frame or iframe# and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking# if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with# ALLOW-FROM uri# https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options add_header X-Frame-Options SAMEORIGIN;# when serving user-supplied content, include a X-Content-Type-Options: nosniff# header along with the Content-Type: header, to disable content-type sniffing# on some browsers.# https://www.owasp.org/index.php/List_of_useful_HTTP_headers# currently suppoorted in IE > 8# http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx# http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx# 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020 add_header X-Content-Type-Options nosniff;# This header enables the Cross-site scripting (XSS) filter built into most# recent web browsers. It's usually enabled by default anyway, so the role# of this header is to re-enable the filter for this particular website if# it was disabled by the user.# https://www.owasp.org/index.php/List_of_useful_HTTP_headers add_header X-XSS-Protection "1; mode=block";# enables server-side protection from BEAST attacks# http://blog.ivanristic.com/2013/09/is-beast-still-a-threat.html ssl_prefer_server_ciphers on;# disable SSLv3(enabled by default since nginx 0.8.19) since it's less secure# then TLS http://en.wikipedia.org/wiki/Secure_Sockets_Layer#SSL_3.0 ssl_protocols TLSv1 TLSv1.1 TLSv1.2;# ciphers chosen for forward secrecy and compatibility# http://blog.ivanristic.com/2013/08/configuring-apache-nginx-and-openssl-for-forward-secrecy.html ssl_ciphers 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-ECDSA-RC4-SHA:RC4-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!3DES:!MD5:!PSK';# enable ocsp stapling (mechanism by which a site can convey certificate# revocation information to visitors in a privacy-preserving, scalable manner)# http://blog.mozilla.org/security/2013/07/29/ocsp-stapling-in-firefox/ resolver 8.8.8.8; ssl_stapling on; ssl_trusted_certificate /opt/local/etc/nginx/ssl/wbnet.dk/test.wbnet.dk.crt;# config to enable HSTS(HTTP Strict Transport Security)# https://developer.mozilla.org/en-US/docs/Security/HTTP_Strict_Transport_Security# to avoid ssl stripping https://en.wikipedia.org/wiki/SSL_stripping#SSL_stripping add_header Strict-Transport-Security "max-age=31536000; includeSubdomains;";#... the rest of your configuration}