aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-02-25 12:06:25 -0700
committerJosh Rahm <joshuarahm@gmail.com>2023-02-25 12:06:25 -0700
commit1a669da23bea9bb8c74cafd92e0819249ff13493 (patch)
tree65bca35b435ed68de7defe509f5697a782fb6d0d
parent10c1fe4071f248e976d920b3ca29971670893f33 (diff)
downloadacquire-key-over-ssh-1a669da23bea9bb8c74cafd92e0819249ff13493.tar.gz
acquire-key-over-ssh-1a669da23bea9bb8c74cafd92e0819249ff13493.tar.bz2
acquire-key-over-ssh-1a669da23bea9bb8c74cafd92e0819249ff13493.zip
Add ability to acquire the key from a separate drive and shred the key when finished.
-rw-r--r--example.conf45
-rwxr-xr-xmodule-setup.sh6
-rwxr-xr-xpoll-ssh-acquire.sh86
-rwxr-xr-xstart-ssh-acquire.sh2
4 files changed, 129 insertions, 10 deletions
diff --git a/example.conf b/example.conf
new file mode 100644
index 0000000..cacf0f1
--- /dev/null
+++ b/example.conf
@@ -0,0 +1,45 @@
+# This is an example configuration for the acquire-key-over-ssh module
+
+# This is the interface the keyserver will be on. This script should
+# wait until this interface is up before trying to connect to the keyserver.
+keyserver_interface=eno2
+
+# This is the host that contains the ssh server with the key.
+keyserver_host=192.168.12.34
+
+# The host's ssh port.
+keyserver_port=22
+
+# Username to ssh into.
+keyserver_user=keyper
+
+# Uncomment the following if the key is stored on a block device.
+#
+# This device will be mounted before the key is retrieved.
+#
+# client_ssh_keys_device='/dev/disk/by-uuid/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
+
+# The mountpoint to mount the ssh-key drive on (from above).
+# Uncomment if using the above configuration for keys stored on a device.
+# This is where the script will mount the block device to.
+#
+# client_ssh_keys_mountpoint="/mnt/boot/"
+
+# The location of the identity file (after mounting).
+# This defaults to /root/.ssh/id_rsa
+#
+# client_identity_file="/mnt/boot/ghost_key"
+
+# Shred the keys after use. This is useful to minimize the time an unencrypted
+# private key is on disk. Only really makes sense if the keys are on disk.
+#
+# One can set up a systemd service that places the identity key on the drive
+# during a routine shutdown, where it will be picked up, used to acquire the
+# decryption key, and shredded.
+#
+# Assuming the drive can be mounted, the script will always shred the keys
+# if this is set even if authentication failed.
+#
+# shred_keys_after_use=1
+
+add_dracutmodules+=" acquire-key-over-ssh "
diff --git a/module-setup.sh b/module-setup.sh
index fd0bb5d..8708778 100755
--- a/module-setup.sh
+++ b/module-setup.sh
@@ -22,8 +22,12 @@ install() {
echo "keyserver_host='$keyserver_host'" >> "$genconf"
echo "keyserver_user='$keyserver_user'" >> "$genconf"
echo "keyserver_port='$keyserver_port'" >> "$genconf"
+ echo "client_ssh_keys_device='${client_ssh_keys_device}'" >> "$genconf"
+ echo "client_ssh_keys_mountpoint='$client_ssh_keys_mountpoint'" >> "$genconf"
+ echo "client_identity_file='$client_identity_file'" >> "$genconf"
+ echo "shred_keys_after_use='$shred_keys_after_use'" >> "$genconf"
- inst_hook pre-udev 99 "$moddir/start-ssh-acquire.sh"
+ inst_hook initqueue/settled 99 "$moddir/start-ssh-acquire.sh"
inst_script "$moddir/poll-ssh-acquire.sh" "/bin/poll-ssh-acquire.sh"
inst_simple "/root/.ssh/known_hosts"
inst_simple "/root/.ssh/id_rsa.pub"
diff --git a/poll-ssh-acquire.sh b/poll-ssh-acquire.sh
index 225287c..ffa4672 100755
--- a/poll-ssh-acquire.sh
+++ b/poll-ssh-acquire.sh
@@ -5,6 +5,7 @@
# This is useful because my system motherboard does not save the system time
# for some reason.
+lockfile=/tmp/acquire-ssh-key-lock
timeout=600
count=0
@@ -25,30 +26,99 @@ while ! ( ip route list dev "$keyserver_interface" &>/dev/null ) ; do
done
echo -e "\ndone"
+# Amount of tries
tries=10
-count=0
+# If the ssh-key is on a device, we have to mount that device before
+# we can do anything.
+mounted=0
+
+if [[ ! -z "$client_ssh_keys_device" ]] ; then
+ if [[ -z "$client_ssh_keys_mountpoint" ]] ; then
+ echo "client_ssh_keys_device requires client_ssh_keys_mountpoint to be set!"
+ return 1
+ fi
+
+ count=0
+ while true ; do
+ if [[ "$count" -eq "$tries" ]] ; then
+ echo "Failed to mount $client_ssh_keys_device on $client_ssh_keys_mountpoint after $tries tries"
+ exit 1
+ fi
+ mkdir -p "$client_ssh_keys_mountpoint"
+ echo "mounting $client_ssh_keys_device on $client_ssh_keys_mountpoint"
+ mount "$client_ssh_keys_device" "$client_ssh_keys_mountpoint"
+ ec="$?"
+ if [[ "$ec" -eq 0 ]] ; then
+ break
+ fi
+ sleep 1
+ count=$((count + 1))
+ done
+ count=0
+
+ mounted=1
+fi
+
+# Default identity file is root's identity file.
+if [[ -z "$client_identity_file" ]] ; then
+ client_identity_file=/root/.ssh/id_rsa
+fi
+
+if [[ ! -f "$client_identity_file" ]] ; then
+ echo "$client_identity_file does not exist."
+ exit 1
+fi
+
+# The main loop. This is going to try repeatedly 10 times to acquire the
+# decryption key. If it fails each time, it will give up and someone
+# will have to manually unlock the device.
+count=0
+acquired=0
while /bin/true ; do
if [[ "$count" -eq "$tries" ]] ; then
echo "Unable to connect to $keyserver_user@$keyserver_host after 10 tries."
- exit 1
+ break;
fi
echo "Trying $keyserver_user@$keyserver_host ..."
- ssh "$keyserver_user@$keyserver_host" -p "$keyserver_port" > /tmp/enc-key
+ echo ssh -i "$client_identity_file" "$keyserver_user@$keyserver_host" -p "$keyserver_port"
- if [[ "$?" -eq 0 ]] ; then
+ ssh -i "$client_identity_file" "$keyserver_user@$keyserver_host" -p "$keyserver_port" > /tmp/enc-key
+
+ ec="$?"
+ if [[ "$ec" -eq 0 ]] ; then
+ acquired=1
break;
+ else
+ echo "Non-zero exit code ec=$ec"
fi
sleep 1
count=$((count + 1))
done
-echo "Passphrase acquired. Stored in /tmp/enc-key."
+# Shred the keys and unmount the filessystems if needed.
+if [[ "$shred_keys_after_use" -eq 1 ]] ; then
+ echo "shred $client_identity_file"
+ shred -u "$client_identity_file"
+fi
+
+if [[ "$mounted" -eq "1" ]] ; then
+ echo "unmount client_ssh_keys_mountpoint"
+ umount "$client_ssh_keys_mountpoint"
+fi
+
+# If the key was acquired, send it to systemd.
+if [[ "$acquired" -eq 1 ]] ; then
+ echo "Key acquired. Stored in /tmp/enc-key."
-socket_file=$(cat /run/systemd/ask-password/ask.* | grep -E '^Socket' | cut -d'=' -f2)
-echo "running: /lib/systemd/systemd-reply-password 1 $socket_file < /tmp/enc-key"
-/lib/systemd/systemd-reply-password 1 "$socket_file" < /tmp/enc-key
+ socket_file=$(cat /run/systemd/ask-password/ask.* | grep -E '^Socket' | cut -d'=' -f2)
+ echo "running: /lib/systemd/systemd-reply-password 1 $socket_file < /tmp/enc-key"
+ /lib/systemd/systemd-reply-password 1 "$socket_file" < /tmp/enc-key
+else
+ echo "Failed to acquire key."
+fi
+# Shred the encryption key for good measure. Probably not necessary.
shred /tmp/enc-key
diff --git a/start-ssh-acquire.sh b/start-ssh-acquire.sh
index 1b3b684..06c4be5 100755
--- a/start-ssh-acquire.sh
+++ b/start-ssh-acquire.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-nohup /bin/poll-ssh-acquire.sh "eno2" &>/var/log/ssh-acquire.log &
+nohup /bin/poll-ssh-acquire.sh 2>&1 >> /var/log/ssh-acquire.log &