├── .gitignore ├── readme.md └── unlockgeli /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | *.swp 3 | *.swo 4 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # GeliUnlocker 2 | 3 | ### A rc.d script to automatically unlock geli encrypted disks using key and passphrase files stored on a remote system accessed via SSH. 4 | 5 | ## Use Cases 6 | 7 | 8 | 1. Encrypt your disks on your VPS, store the keys and passphrases on a server on premise. Your remote VPS can reboot with no user interaction as long as your on premise server hosting the keys is up. 9 | 2. Store the key file and passphrase file on two different remote systems if you like. Both systems must be up for your disks to be successfully decrypted. 10 | 3. Encrypt the keys on the remote system so they can be stored on untrusted systems. 11 | 12 | ## How to Install: 13 | 14 | 1. Copy the geliunlock script to /usr/local/etc/rc.d/ 15 | ``` 16 | fetch https://raw.githubusercontent.com/clinta/geliUnlocker/master/unlockgeli /usr/local/etc/rc.d/ 17 | chmod +x /usr/local/etc/rc.d/unlockgeli 18 | ``` 19 | 20 | ## How to Use: 21 | 22 | You need an account on a remote system with scp access via public key authentication using a key with no passphrase. If doing this on a vps, you might want to consider creating a user just for this purpose and restricting their login schell to scp only. 23 | 24 | The private key for ssh authentication to the remove server must be stored somehwere that is not on one of your encrypted disks. 25 | 26 | If you want, encrypt your geli key and passphrase file using openssl (the -k parameter is your passphrase that you will add into rc.conf later): 27 | ``` 28 | openssl enc -aes-256-cbc -a -salt -in geli.key -out geli.key.aes -k "YTVCXmx2hBY69zoA7s6Gp886X3" 29 | openssl enc -aes-256-cbc -a -salt -in geli.pw -out geli.pw.aes -k "NBRxX8rvZfOWfRYhMnnyfhCRO" 30 | ``` 31 | 32 | Copy your geli key file (or your encrypted keyfile if using encryption) to your remote host. Create a passphrase file (a text file containing your passphrase to your geli disk) and put it on the same, or a different remote host. 33 | 34 | Configure your automatic decryption in rc.conf: 35 | ``` 36 | # If netwait is enabled, geliunlock will wait to run until the default gateway responds to ping to run. 37 | netwait_enable="YES" 38 | 39 | # Enable the unlockgeli script 40 | unlockgeli_enable="YES" 41 | 42 | # A list of groups of disks. These do not necessarily have to correspond to zfs pools, but they often will. 43 | unlockgeli_pools="tank docs" 44 | 45 | # Devices belonging to the pool listed above are defined here. 46 | unlockgeli_tank_devs="/dev/da1 /dev/da2 /dev/gptid/96235f62-1074-11e4-a04d-50e549c81799" 47 | # scp syntax path to the geli key file 48 | unlockgeli_tank_key="bob@192.168.1.24:/home/bob/geli.key" 49 | # the OpenSSL password chosen for encryption. If this is omitted, the key is assumed to not be encrypted. 50 | unlockgeli_tank_key_enc_pw="YTVCXmx2hBY69zoA7s6Gp886X3" 51 | # The ssh key file for this server 52 | unlockgeli_tank_key_identityfile="/root/bob.id-rsa" 53 | # scp syntax path to the geli passphrase file 54 | unlockgeli_tank_passphrase="tom@192.168.1.53:/home/tom/geli.pw" 55 | # the OpenSSL password chosen for encryption. If this is omitted, the key is assumed to not be encrypted. 56 | unlockgeli_tank_passphrase_enc_pw="NBRxX8rvZfOWfRYhMnnyfhCRO" 57 | # the ssh key file for this server 58 | unlockgeli_tank_passphrase_identityfile="/root/tom.id-rsa" 59 | 60 | ``` 61 | 62 | At the end of the script `zfs mount -a` is called, so any zfs datasets on the newly decrypted disks should be mounted. Also this script will attempt to run before jail, so any jails stored on these encrypted volumes can run on boot. 63 | -------------------------------------------------------------------------------- /unlockgeli: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # PROVIDE: unlockgeli 3 | # REQUIRE: netwait 4 | # BEFORE: jail 5 | 6 | . /etc/rc.subr 7 | 8 | name=unlockgeli 9 | rcvar=unlockgeli_enable 10 | 11 | start_cmd="${name}_start" 12 | stop_cmd=":" 13 | 14 | load_rc_config $name 15 | : ${unlockgeli:=no} 16 | 17 | unlockgeli_start() 18 | { 19 | eval pools=\${$@:-${unlockgeli_pools}} 20 | for _g in $pools; do 21 | echo "Unlocking $_g pool" 22 | eval devs=\${unlockgeli_${_g}_devs} 23 | eval key=\${unlockgeli_${_g}_key} 24 | eval key_identityfile=\${unlockgeli_${_g}_key_identityfile} 25 | eval key_enc_pw=\${unlockgeli_${_g}_key_enc_pw} 26 | eval passphrase=\${unlockgeli_${_g}_passphrase} 27 | eval passphrase_identityfile=\${unlockgeli_${_g}_passphrase_identityfile} 28 | eval passphrase_enc_pw=\${unlockgeli_${_g}_passphrase_enc_pw} 29 | 30 | keytempfile=/tmp/unlockgeli.key.tmp 31 | pwtempfile=/tmp/unlockgeli.pw.tmp 32 | echo "Downloading geli key" 33 | scp -i ${key_identityfile} ${key} $keytempfile 34 | if [ "$?" -ne "0" ]; then 35 | warn "Unable to download identity file ${key}" 36 | fi 37 | if [ -n "${key_enc_pw}" ]; then 38 | echo "Decrypting keyfile" 39 | mv $keytempfile ${keytempfile}.aes 40 | openssl enc -aes-256-cbc -a -salt -d -in ${keytempfile}.aes -out $keytempfile -k "${key_enc_pw}" 41 | if [ "$?" -ne "0" ]; then 42 | warn "Unable to decrypt identity file ${key}" 43 | fi 44 | rm -f $keytempfile.aes 45 | fi 46 | if [ -n "${passphrase}" ]; then 47 | echo "Downloading geli passphrase" 48 | scp -i ${passphrase_identityfile} ${passphrase} $pwtempfile 49 | if [ "$?" -ne "0" ]; then 50 | warn "Unable to download passphrase file ${passphrase}" 51 | fi 52 | if [ -n "${passphrase_enc_pw}" ]; then 53 | echo "Decrypting passphrase file" 54 | mv $pwtempfile ${pwtempfile}.aes 55 | openssl enc -aes-256-cbc -a -salt -d -in ${pwtempfile}.aes -out $pwtempfile -k "${passphrase_enc_pw}" 56 | if [ "$?" -ne "0" ]; then 57 | warn "Unable to decrypt passphrase file ${passphrase}" 58 | fi 59 | rm -f $pwtempfile.aes 60 | fi 61 | fi 62 | for _d in ${devs}; do 63 | echo "Unlocking $_d" 64 | if [ -n "${passphrase}" ]; then 65 | geli attach -k $keytempfile -j $pwtempfile $_d 66 | else 67 | geli attach -k $keytempfile -p $_d 68 | fi 69 | if [ "$?" -ne "0" ]; then 70 | warn "Unable to geli attach $_d" 71 | fi 72 | done 73 | echo "Deleting temporary key file" 74 | rm -fP $keytempfile 75 | echo "Deleting temporary passphrase file" 76 | rm -fP $pwtempfile 77 | 78 | echo "Mounting unlocked zfs volumes" 79 | zfs mount -a 80 | done 81 | } 82 | 83 | case $# in 84 | 1) run_rc_command $@ ${geliunlock_list:-_ALL} ;; 85 | *) run_rc_command $@ ;; 86 | esac 87 | --------------------------------------------------------------------------------