From 8b6da9407eaf7333463345f91b2cbeb02a0a2c14 Mon Sep 17 00:00:00 2001 From: Ricard Illa Date: Mon, 3 Oct 2022 18:30:24 +0200 Subject: [PATCH] cryptoraid --- hosts.yml | 22 +++++++++ roles/cryptoraid/files/authorized_keys | 1 + roles/cryptoraid/files/bin/remote-unlock.sh | 17 +++++++ roles/cryptoraid/files/bin/unlock-luks.sh | 48 +++++++++++++++++++ roles/cryptoraid/files/etc/unlock-luks.conf | 8 ++++ .../files/share/unlock-luks-helpers.sh | 45 +++++++++++++++++ roles/cryptoraid/tasks/alpine.yml | 47 +++++++++++++++++- .../cryptoraid/templates/unlock-luks.conf.j2 | 8 ++++ 8 files changed, 194 insertions(+), 2 deletions(-) create mode 100644 roles/cryptoraid/files/authorized_keys create mode 100644 roles/cryptoraid/files/bin/remote-unlock.sh create mode 100644 roles/cryptoraid/files/bin/unlock-luks.sh create mode 100644 roles/cryptoraid/files/etc/unlock-luks.conf create mode 100644 roles/cryptoraid/files/share/unlock-luks-helpers.sh create mode 100644 roles/cryptoraid/templates/unlock-luks.conf.j2 diff --git a/hosts.yml b/hosts.yml index 417aa96..62357db 100644 --- a/hosts.yml +++ b/hosts.yml @@ -30,6 +30,11 @@ all: fstype: "vfat" opts: "noauto,defaults" passno: "0" + - path: "/boot" + src: "/media/mmcblk0p1/boot" + fstype: "none" + opts: "defaults,bind" + passno: "0" - path: "/media/mmcblk0p2" src: "UUID=75d4943d-2a1a-4f76-9f60-cff99b4d2e1f" fstype: "ext4" @@ -43,6 +48,23 @@ all: rpi_cfg: - "enable_uart=1" - "otg_mode=1" + luks_yk_slot: 2 + luks_yk_challenge: !vault | + $ANSIBLE_VAULT;1.1;AES256 + 34333431626366653132396433316337373134373832643066623838346535626639343130373536 + 3437363264343832346432373530316230623637333935310a643135323836306232366235333139 + 35323832333566653235386530643238633333356131373136333937373164373065313430633438 + 3731356134663033620a376230323761336534653064343135366465333438376539386238643931 + 31313735336563366366396536386262383430323161366263623639336661646465333436336264 + 3037623462653131643964383533646632343436613839623761 + luks_dropbear_port: 2222 + luks_timeout: 120 + luks_targets: + - data0 + - data1 + luks_source_uuids: + - 202c924c-ee53-4321-9efd-1f776e939702 + - a243ac31-094c-4fe2-bced-6e4311a16487 caladan: ansible_host: caladan diff --git a/roles/cryptoraid/files/authorized_keys b/roles/cryptoraid/files/authorized_keys new file mode 100644 index 0000000..151116c --- /dev/null +++ b/roles/cryptoraid/files/authorized_keys @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDaiwmnSKC4DpznZlode1987DvGVLWqkvDZXZ6ey/LOZhRHvNnr5lP4Ke034R17mHHuTlzzuTKUKTN6JcIxBURGUwjWgNQO5z+7SapdOvPpw7M8wOlgp92CbIMiE/tReNbUi2e584Y5NR4tMCQm+FPvQ7c7nY/WoxJ6VSiKBbXzN+IrB9H6ZAVyfAlzHpxhwXeuP5xFwTtapzyzyc4phvuIhbXUc9NOZHXwoAR2La/0TVOgDyktEmCq6aGet03Azz6KPRptdnf4g9V3u8YivccXfd9WTrJr9fj1fWjDU9bBKVU6GtdcSwfqKwa6X4sQIZfONKvVEfqbIIEB70FsXHcdfnm3EN5L1PWbC441Q8bB1zvu/GnlXTlxDFmzByxnbLWTSPLuQyKq5sv9va8Jl9QEVpS3qWJbPHYBTevgboTExyLmpEfsCI+Of86Oxb8PNjyhX1/oWiy8S3w+5oQgAb+yNfSVPnX7CO4oGQhnttoXHA94LzxArYr9zZIp2asRMlc4VVWVH/jQ4FdLDjvKNARYiytOplZBPvFOHJiGb/rfjZKbMPPE+3V1WQPZ6B2nlWN5QxTpnLgTQnONr5rlSrvzFPY8BISUAYcdOCErG4agHDkHFZqWn8u+51wUZUnXo4NI+rty4Nzmc/kPfqWyv/8mSJfihidfuuHGEEzCk1qVdQ== cardno:11 073 199 diff --git a/roles/cryptoraid/files/bin/remote-unlock.sh b/roles/cryptoraid/files/bin/remote-unlock.sh new file mode 100644 index 0000000..c44f4db --- /dev/null +++ b/roles/cryptoraid/files/bin/remote-unlock.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +. /usr/local/etc/unlock-luks.conf +. /usr/local/share/unlock-luks-helpers.sh + +[ -z "$SOURCE_UUIDS" ] && return 1 +[ -z "$TARGETS" ] && return 1 + +touch "$LOCK_FILE" +# shellcheck disable=SC2064 +trap "rm -f $LOCK_FILE" EXIT + +printf "Enter LUKS password:" +passwd=$(read_password) +decrypt "${passwd}" + +rm -f "$LOCK_FILE" diff --git a/roles/cryptoraid/files/bin/unlock-luks.sh b/roles/cryptoraid/files/bin/unlock-luks.sh new file mode 100644 index 0000000..1da8021 --- /dev/null +++ b/roles/cryptoraid/files/bin/unlock-luks.sh @@ -0,0 +1,48 @@ +#!/bin/sh + +. /usr/local/etc/unlock-luks.conf +. /usr/local/share/unlock-luks-helpers.sh + +REMOTE_UNLOCK=/usr/local/bin/remote-unlock.sh + +DROPBEAR_PORT="${DROPBEAR_PORT:-22}" +TIMEOUT="${TIMEOUT:-60}" +YK_SLOT="${YK_SLOT:-2}" + +[ -z "$YK_CHALLENGE" ] && return 1 +[ -z "$SOURCE_UUIDS" ] && return 1 +[ -z "$TARGETS" ] && return 1 + +loop() { + starttime=$(date +%s) + usedtime=0 + while ! check_is_open && [ "$usedtime" -le "$TIMEOUT" ]; do + while [ -f "$LOCK_FILE" ]; do + sleep 1 + done + yk_decrypt + sleep 1 + endtime=$(date +%s) + usedtime=$((endtime - starttime)) + done +} + +dropbear \ + -R -s -F \ + -G root \ + -p "${DROPBEAR_PORT}" \ + -c "${REMOTE_UNLOCK}" & +DROPBEAR_PID="$!" +sleep 0.5 +# shellcheck disable=SC2064 +trap "kill $DROPBEAR_PID" EXIT + +loop + +kill "${DROPBEAR_PID}" + +if check_is_open; then + printf "decryption succeeded\n" +else + printf "decryption failed\n" +fi diff --git a/roles/cryptoraid/files/etc/unlock-luks.conf b/roles/cryptoraid/files/etc/unlock-luks.conf new file mode 100644 index 0000000..d8ea841 --- /dev/null +++ b/roles/cryptoraid/files/etc/unlock-luks.conf @@ -0,0 +1,8 @@ +#!/bin/sh + +export SOURCE_UUIDS="202c924c-ee53-4321-9efd-1f776e939702 a243ac31-094c-4fe2-bced-6e4311a16487" +export TARGETS="data0 data1" +export TIMEOUT="60" +export YK_CHALLENGE="xWNQnvjBZav8UZzRKeQ7W1E0CV9E6Cnt" +export YK_SLOT="2" +export DROPBEAR_PORT=2222 diff --git a/roles/cryptoraid/files/share/unlock-luks-helpers.sh b/roles/cryptoraid/files/share/unlock-luks-helpers.sh new file mode 100644 index 0000000..0b1239d --- /dev/null +++ b/roles/cryptoraid/files/share/unlock-luks-helpers.sh @@ -0,0 +1,45 @@ +#!/bin/sh + +. /usr/local/etc/unlock-luks.conf + +export LOCK_FILE=/tmp/remote-unlock.lock + +[ -z "$SOURCE_UUIDS" ] && return 1 +[ -z "$TARGETS" ] && return 1 + +decrypt() { + passwd="$1" + i=1 + for uuid in $SOURCE_UUIDS; do + target=$(printf "%s" "$TARGETS" | cut -d ' ' -f "${i}") + printf "%s" "$passwd" | cryptsetup luksOpen "/dev/disk/by-uuid/${uuid}" "${target}" + i=$((i + 1)) + done +} + +read_password() { + stty -echo + trap 'stty echo' EXIT + read -r passwd + stty echo + trap - EXIT + printf "%s" "${passwd}" +} + +check_is_open() { + for target in $TARGETS; do + [ ! -b "/dev/mapper/${target}" ] && return 1 + done + return 0 +} + +yk_decrypt() { + printf "attempting decryption with yubikey\n" + if ykinfo "-${YK_SLOT}" >&2; then + printf "yubikey available\n" + yk_pass=$(ykchalresp "-${YK_SLOT}" "${YK_CHALLENGE}" | tr -d '\n') + decrypt "$yk_pass" + else + printf "yubikey not present\n" + fi +} diff --git a/roles/cryptoraid/tasks/alpine.yml b/roles/cryptoraid/tasks/alpine.yml index 3066832..0713a51 100644 --- a/roles/cryptoraid/tasks/alpine.yml +++ b/roles/cryptoraid/tasks/alpine.yml @@ -2,10 +2,11 @@ - name: install packages apk: name: + - btrfs-progs + - cryptsetup + - gnupg - gptfdisk - sgdisk - - cryptsetup - - btrfs-progs - zstd - name: load btrfs module @@ -18,3 +19,45 @@ path: /etc/modules line: btrfs insertafter: EOF + +- name: create script directories + file: + path: "/usr/local/{{ item }}" + state: directory + mode: '0755' + loop: + - bin + - etc + - share + +- name: copy unlock scripts + copy: + src: "bin/{{ item }}" + dest: "/usr/local/bin/{{ item }}" + mode: '0755' + loop: + - remote-unlock.sh + - unlock-luks.sh + +- name: copy helper unlock files + copy: + src: share/unlock-luks-helpers.sh + dest: /usr/local/share/unlock-luks-helpers.sh + mode: '0644' + +- name: copy unlock config files + template: + src: unlock-luks.conf.j2 + dest: /usr/local/etc/unlock-luks.conf + mode: '0644' + +- name: create root's ssh directory + file: + path: "/root/.ssh" + state: directory + mode: '0755' + +- name: copy authorized_keys + copy: + src: authorized_keys + dest: /root/.ssh/authorized_keys diff --git a/roles/cryptoraid/templates/unlock-luks.conf.j2 b/roles/cryptoraid/templates/unlock-luks.conf.j2 new file mode 100644 index 0000000..1b5eb4b --- /dev/null +++ b/roles/cryptoraid/templates/unlock-luks.conf.j2 @@ -0,0 +1,8 @@ +#!/bin/sh + +export SOURCE_UUIDS="{{ luks_source_uuids | join(" ") }}" +export TARGETS="{{ luks_targets | join(" ") }}" +export TIMEOUT="{{ luks_timeout }}" +export YK_CHALLENGE="{{ luks_yk_challenge }}" +export YK_SLOT="{{ luks_yk_slot }}" +export DROPBEAR_PORT="{{ luks_dropbear_port }}"