Skip to content

Instantly share code, notes, and snippets.

@Luzifer
Last active December 5, 2023 15:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Luzifer/2c760963dbd040e60a698d63ec71c493 to your computer and use it in GitHub Desktop.
Save Luzifer/2c760963dbd040e60a698d63ec71c493 to your computer and use it in GitHub Desktop.
Setup for LUKS encrypted disk using Vault transit encryption for the key and local auth-expiry
#!/usr/bin/env bash
set -euo pipefail
function fatal() {
log "$@"
exit 1
}
function log() {
echo "$@" >&2
}
function main() {
[[ -n ${VAULT_ADDR:-} ]] || fatal "Missing ENV VAULT_ADDR"
[[ -n ${VAULT_ROLE_ID:-} ]] || fatal "Missing ENV VAULT_ROLE_ID"
[[ -n ${VAULT_SECRET_ID:-} ]] || fatal "Missing ENV VAULT_SECRET_ID"
key_file=/etc/luks-volume/key
mountpoint=/volume
open_name=volume-luks
transit=luks-archnas
volume=/dev/md127
case ${1:-help} in
create-key)
[[ -e $key_file ]] && fatal "Key already exists." || true
log "Creating new key in ${key_file}..."
vault_login
mkdir -p $(dirname ${key_file})
openssl rand 512 | base64 -w0 | vault write -field=ciphertext transit/encrypt/${transit} plaintext=- >${key_file}
chmod 0400 ${key_file}
;;
format)
cryptsetup isLuks ${volume} && fatal "${volume} is already formated as luks" || true
log "Formatting ${volume} with LUKS..."
vault_login
vault write -field=plaintext transit/decrypt/${transit} ciphertext=- <${key_file} |
base64 -d |
cryptsetup luksFormat --batch-mode --type luks2 --pbkdf argon2id --key-file - ${volume}
;;
mount)
mount | grep -q "on ${mountpoint}" && fatal "Mountpoint ${mountpoint} already mounted." || true
log "Mounting ${volume} on ${mountpoint}..."
vault_login
[[ -e /dev/mapper/${open_name} ]] || vault write -field=plaintext transit/decrypt/${transit} ciphertext=- <${key_file} |
base64 -d |
cryptsetup open --type luks --key-file - ${volume} ${open_name}
mount /dev/mapper/${open_name} ${mountpoint}
;;
umount)
[[ -e /dev/mapper/${open_name} ]] || fatal "Crypto mapper not available." || true
log "Unmounting ${volume} from ${mountpoint}..."
mount | grep -q "on ${mountpoint}" && umount ${mountpoint} || true
[[ -e /dev/mapper/${open_name} ]] && cryptsetup close /dev/mapper/${open_name} || true
;;
*)
echo "Usage: $(basename $0) <create-key|format|mount|umount>"
;;
esac
}
function vault_login() {
export VAULT_TOKEN=$(vault write -field=token auth/approle/login role_id=${VAULT_ROLE_ID} secret_id=${VAULT_SECRET_ID})
[[ -n ${VAULT_TOKEN:-} ]]
}
main "$@"
[Unit]
Description=Start/stop the LUKS-encrypted partition
After=local-fs.target network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
EnvironmentFile=/etc/luks-volume/vault-auth
ExecStart=/usr/local/bin/manage-volume mount
ExecStop=/usr/local/bin/manage-volume umount
[Install]
WantedBy=multi-user.target
#!/usr/bin/env bash
set -euo pipefail
function fatal() {
log "$@"
exit 1
}
function log() {
echo "$@" >&2
}
function main() {
[[ -n ${VAULT_ADDR:-} ]] || fatal "Missing ENV VAULT_ADDR"
[[ -n ${VAULT_ROLE_ID:-} ]] || fatal "Missing ENV VAULT_ROLE_ID"
auth_file=/etc/luks-volume/vault-auth
role_name=luks-archnas
while :; do
log "Updating ${auth_file} with new credentials..."
export VAULT_TOKEN=$(vault write -field=token auth/approle/login role_id=${VAULT_ROLE_ID})
[[ -n ${VAULT_TOKEN:-} ]] || fatal "Could not retrieve VAULT_TOKEN"
local role_id=$(vault read -field=role_id auth/approle/role/${role_name}/role-id)
[[ -n $role_id ]] || fatal "Could not retrieve VAULT_ROLE_ID"
local secret_json=$(vault write --format=json --force auth/approle/role/${role_name}/secret-id)
local secret_id=$(jq -r '.data.secret_id' <<<"${secret_json}")
[[ -n $secret_id ]] || fatal "Could not retrieve VAULT_SECRET_ID"
local expiry=$(jq -r '.data.secret_id_ttl' <<<"${secret_json}")
echo "VAULT_ADDR=${VAULT_ADDR}" >${auth_file}.new
echo "VAULT_ROLE_ID=${role_id}" >>${auth_file}.new
echo "VAULT_SECRET_ID=${secret_id}" >>${auth_file}.new
chmod 0400 ${auth_file}.new
mv ${auth_file}.new ${auth_file}
log "Credentials updated, sleeping for $((expiry / 2))s..."
sleep $((expiry / 2))
done
}
main "$@"
[Unit]
Description=Update the auth data for volume auto-mount
After=network-online.target manage-volume.service
Requires=manage-volume.service
[Service]
EnvironmentFile=/volume/.luks-volume-renew
ExecStart=/usr/local/bin/renew-volume-auth
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment