From a9bc7372dec6a02659af09993ae906754ee5bbe0 Mon Sep 17 00:00:00 2001 From: Christian Wuerdig Date: Thu, 20 Dec 2018 11:33:41 +1300 Subject: [PATCH] Adding dm-crypt as core pkg Signed-off-by: Christian Wuerdig --- docs/encrypted-disk.md | 86 +++++++++++++++++++ examples/dm-crypt-loop.yml | 49 +++++++++++ examples/dm-crypt.yml | 43 ++++++++++ pkg/dm-crypt/Dockerfile | 19 ++++ pkg/dm-crypt/build.yml | 8 ++ pkg/dm-crypt/crypto.sh | 84 ++++++++++++++++++ .../004_dm-crypt/000_simple/check.sh | 10 +++ .../004_dm-crypt/000_simple/test.sh | 26 ++++++ .../004_dm-crypt/000_simple/test.yml | 30 +++++++ .../004_dm-crypt/001_luks/check.sh | 10 +++ .../004_dm-crypt/001_luks/test.sh | 26 ++++++ .../004_dm-crypt/001_luks/test.yml | 30 +++++++ .../004_dm-crypt/002_key/check.sh | 10 +++ .../040_packages/004_dm-crypt/002_key/test.sh | 26 ++++++ .../004_dm-crypt/002_key/test.yml | 33 +++++++ test/cases/040_packages/012_losetup/test.yml | 2 +- 16 files changed, 491 insertions(+), 1 deletion(-) create mode 100644 docs/encrypted-disk.md create mode 100644 examples/dm-crypt-loop.yml create mode 100644 examples/dm-crypt.yml create mode 100644 pkg/dm-crypt/Dockerfile create mode 100644 pkg/dm-crypt/build.yml create mode 100755 pkg/dm-crypt/crypto.sh create mode 100755 test/cases/040_packages/004_dm-crypt/000_simple/check.sh create mode 100644 test/cases/040_packages/004_dm-crypt/000_simple/test.sh create mode 100644 test/cases/040_packages/004_dm-crypt/000_simple/test.yml create mode 100755 test/cases/040_packages/004_dm-crypt/001_luks/check.sh create mode 100644 test/cases/040_packages/004_dm-crypt/001_luks/test.sh create mode 100644 test/cases/040_packages/004_dm-crypt/001_luks/test.yml create mode 100755 test/cases/040_packages/004_dm-crypt/002_key/check.sh create mode 100644 test/cases/040_packages/004_dm-crypt/002_key/test.sh create mode 100644 test/cases/040_packages/004_dm-crypt/002_key/test.yml diff --git a/docs/encrypted-disk.md b/docs/encrypted-disk.md new file mode 100644 index 000000000..094a58f89 --- /dev/null +++ b/docs/encrypted-disk.md @@ -0,0 +1,86 @@ +# Device encryption with dm-crypt + +In the packages section you can find an image to setup dm-crypt encrypted devices in [linuxkit](https://github.com/linuxkit/linuxkit)-generated images. + +## Usage + +The setup is a one time step during boot: + +```yaml +onboot: + - name: dm-crypt + image: linuxkit/dm-crypt: + command: ["/usr/bin/crypto", "dm_crypt_name", "/dev/sda1"] + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "/dev/mapper/dm_crypt_name", "/var/secure_storage"] +files: + - path: etc/dm-crypt/key + contents: "abcdefghijklmnopqrstuvwxyz123456" +``` + +The above will map `/dev/sda1` as an encrypted device under `/dev/mapper/dm_crypt_name` and mount it under `/var/secure_storage` + +The `dm-crypt` container by default bind-mounts `/dev:/dev` and `/etc/dm-crypt:/etc/dm-crypt`. It expects the encryption key to be present in the file `/etc/dm-crypt/key`. You can pass an alternative location as encryption key which can be either a file path relative to `/etc/dm-crypt` or an absolute path. + +Providing an alternative encryption key file name: + +```yaml +onboot: + - name: dm-crypt + image: linuxkit/dm-crypt: + command: ["/usr/bin/crypto", "-k", "some_other_key", "dm_crypt_name", "/dev/sda1"] + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "/dev/mapper/dm_crypt_name", "/var/secure_storage"] +files: + - path: etc/dm-crypt/some_other_key + contents: "abcdefghijklmnopqrstuvwxyz123456" +``` + +Providing an alternative encryption key file name as absolute path: + +```yaml +onboot: + - name: dm-crypt + image: linuxkit/dm-crypt: + command: ["/usr/bin/crypto", "-k", "/some/other/key", "dm_crypt_name", "/dev/sda1"] + binds: + - /dev:/dev + - /etc/dm-crypt/some_other_key:/some/other/key + - name: mount + image: linuxkit/mount: + command: ["/usr/bin/mountie", "/dev/mapper/dm_crypt_name", "/var/secure_storage"] +files: + - path: etc/dm-crypt/some_other_key + contents: "abcdefghijklmnopqrstuvwxyz123456" +``` + +Note that you have to also map `/dev:/dev` explicitly if you override the default bind-mounts. + +The `dm-crypt` container + +* Will create an `ext4` file system on the encrypted device if none is present. + * It will also initialize the encrypted device by filling it from `/dev/zero` prior to creating the filesystem. Which means if the device is being setup for the first time it might take a bit longer. +* Uses the `aes-cbc-essiv:sha256` cipher (it's explicitly specified in case the default ever changes) + * Consequently the encryption key is expected to be 32 bytes long, a random one can be created via + ```shell + dd if=/dev/urandom of=dm-crypt.key bs=32 count=1 + ``` + If you see the error `Cannot read requested amount of data.` next to the log message `Creating dm-crypt mapping for ...` then this means your keyfile doesn't contain enough data. + +### Examples + +There are two examples in the `examples/` folder: + +1. `dm-crypt.yml` - formats an external disk and mounts it encrypted. +2. `dm-crypt-loop.yml` - mounts an encrypted loop device backed by a regular file sitting on an external disk + +### Options + +|Option|Default|Required|Notes| +|---|---|---|---| +|`-k` or `--key`|`key`|No|Encryption key file name. Must be either relative to `/etc/dm-crypt` or an absolute file path.| +|`-l` or `--luks`||No|Use LUKS format for encryption| +|``||**Yes**|The device-mapper device name to use. The device will be mapped under `/dev/mapper/`| +|``||**Yes**|Device to encrypt.| diff --git a/examples/dm-crypt-loop.yml b/examples/dm-crypt-loop.yml new file mode 100644 index 000000000..8b634e040 --- /dev/null +++ b/examples/dm-crypt-loop.yml @@ -0,0 +1,49 @@ +kernel: + image: linuxkit/kernel:4.14.88 + cmdline: "console=tty0 console=ttyS0" +init: + - linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1 + - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe + - linuxkit/containerd:326b096cd5fbab0f864e52721d036cade67599d6 + - linuxkit/ca-certificates:v0.6 +onboot: + - name: sysctl + image: linuxkit/sysctl:v0.6 + - name: dhcpcd + image: linuxkit/dhcpcd:v0.6 + command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] + - name: format + image: linuxkit/format:v0.6 + command: ["/usr/bin/format", "/dev/sda"] + - name: mount + image: linuxkit/mount:v0.6 + command: ["/usr/bin/mountie", "/dev/sda1", "/var/external"] + - name: loop + image: linuxkit/losetup:b05ffc8641cc955abe45f6730cbe6d723b63bd3f + command: ["/usr/bin/loopy", "--create", "/var/external/storage_file"] + - name: dm-crypt + image: linuxkit/dm-crypt:9e41a164358b0235f0c242219b1a424c6552d46c + command: ["/usr/bin/crypto", "crypt_loop_dev", "/dev/loop0"] + - name: mount + image: linuxkit/mount:v0.6 + command: ["/usr/bin/mountie", "/dev/mapper/crypt_loop_dev", "/var/secure_storage"] + - name: bbox + image: busybox + command: ["sh", "-c", "echo 'secret things' >/var/secure_storage/secrets"] + binds: + - /var:/var +services: + - name: getty + image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478 + env: + - INSECURE=true + - name: rngd + image: linuxkit/rngd:v0.6 +files: + - path: etc/dm-crypt/key + # the below key is just to keep the example self-contained + # !!! provide a proper key for production use here !!! + contents: "abcdefghijklmnopqrstuvwxyz123456" +trust: + org: + - linuxkit diff --git a/examples/dm-crypt.yml b/examples/dm-crypt.yml new file mode 100644 index 000000000..0fb0b7f87 --- /dev/null +++ b/examples/dm-crypt.yml @@ -0,0 +1,43 @@ +kernel: + image: linuxkit/kernel:4.14.88 + cmdline: "console=tty0 console=ttyS0" +init: + - linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1 + - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe + - linuxkit/containerd:326b096cd5fbab0f864e52721d036cade67599d6 + - linuxkit/ca-certificates:v0.6 +onboot: + - name: sysctl + image: linuxkit/sysctl:v0.6 + - name: dhcpcd + image: linuxkit/dhcpcd:v0.6 + command: ["/sbin/dhcpcd", "--nobackground", "-f", "/dhcpcd.conf", "-1"] + - name: format + image: linuxkit/format:v0.6 + command: ["/usr/bin/format", "/dev/sda"] + - name: dm-crypt + image: linuxkit/dm-crypt:9e41a164358b0235f0c242219b1a424c6552d46c + command: ["/usr/bin/crypto", "crypt_dev", "/dev/sda1"] + - name: mount + image: linuxkit/mount:v0.6 + command: ["/usr/bin/mountie", "/dev/mapper/crypt_dev", "/var/secure_storage"] + - name: bbox + image: busybox + command: ["sh", "-c", "echo 'secret things' >/var/secure_storage/secrets"] + binds: + - /var:/var +services: + - name: getty + image: linuxkit/getty:2eb742cd7a68e14cf50577c02f30147bc406e478 + env: + - INSECURE=true + - name: rngd + image: linuxkit/rngd:v0.6 +files: + - path: etc/dm-crypt/key + # the below key is just to keep the example self-contained + # !!! provide a proper key for production use here !!! + contents: "abcdefghijklmnopqrstuvwxyz123456" +trust: + org: + - linuxkit diff --git a/pkg/dm-crypt/Dockerfile b/pkg/dm-crypt/Dockerfile new file mode 100644 index 000000000..6551d4996 --- /dev/null +++ b/pkg/dm-crypt/Dockerfile @@ -0,0 +1,19 @@ +FROM linuxkit/alpine:3683c9a66cd4da40bd7d6c7da599b2dcd738b559 AS mirror +RUN mkdir -p /out/etc/apk && cp -r /etc/apk/* /out/etc/apk/ +RUN apk add --no-cache --initdb -p /out \ + alpine-baselayout \ + cryptsetup \ + e2fsprogs + +# Remove apk residuals +RUN rm -rf /out/etc/apk /out/lib/apk /out/var/cache + +FROM scratch +ENTRYPOINT [] +WORKDIR / +COPY --from=mirror /out/ / + +COPY crypto.sh /usr/bin/crypto +RUN chmod +x /usr/bin/crypto + +CMD ["/usr/bin/crypto"] diff --git a/pkg/dm-crypt/build.yml b/pkg/dm-crypt/build.yml new file mode 100644 index 000000000..a255f0c84 --- /dev/null +++ b/pkg/dm-crypt/build.yml @@ -0,0 +1,8 @@ +image: dm-crypt +config: + binds: + - /dev:/dev + - /etc/dm-crypt:/etc/dm-crypt + capabilities: + - CAP_SYS_ADMIN + - CAP_MKNOD diff --git a/pkg/dm-crypt/crypto.sh b/pkg/dm-crypt/crypto.sh new file mode 100755 index 000000000..64255d005 --- /dev/null +++ b/pkg/dm-crypt/crypto.sh @@ -0,0 +1,84 @@ +#!/bin/sh + +set -e + +help() +{ + echo "Usage: $0 [options] " + echo + echo "Options:" + echo " -l|--luks Use LUKS extension" + echo " -k|--key-file Name of the key file, default: key" + echo " Name of the device mapper file, the encrypted device will become available under /dev/mapper/" + echo " The encrypted device (e.g. /dev/sda1, /dev/loop0, etc)" + echo +} + +luks=false +key_file="key" + +O=`getopt -l key-file:luks,help -- k:lh "$@"` || exit 1 +eval set -- "$O" +while true; do + case "$1" in + -l|--luks) luks=true; shift;; + -k|--key-file) key_file=$2; shift 2;; + -h|--help) help; exit 0;; + --) shift; break;; + *) echo "Unknown option $1"; help; exit 1;; + esac +done + +if [ -z "$1" ]; then + echo "Missing argument " + help + exit 1 +fi + +if [ -z "$2" ]; then + echo "Missing argument " + help + exit 1 +fi + +dm_name=$1 +device=$2 +dmdev_name="/dev/mapper/$dm_name" +cipher="aes-cbc-essiv:sha256" + +case "$key_file" in + /*) ;; + *) key_file="/etc/dm-crypt/$key_file" ;; +esac + +if [ ! -f "$key_file" ]; then + echo "Couldn't find encryption keyfile $key_file!" + exit 1 +fi + +if [ ! -d "/run/cryptsetup" ]; then + echo "Creating cryptsetup lock directory" + mkdir /run/cryptsetup +fi + +if [ $luks = true ]; then + echo "Creating dm-crypt LUKS mapping for $device under $dmdev_name" + if ! cryptsetup isLuks $device; then + echo "Device $device doesn't seem to have a valid LUKS setup so one will be created." + cryptsetup --key-file "$key_file" --cipher "$cipher" luksFormat "$device" + fi + cryptsetup --key-file "$key_file" luksOpen "$device" "$dm_name" +else + echo "Creating dm-crypt mapping for $device under $dmdev_name" + cryptsetup --key-file "$key_file" --cipher "$cipher" create "$dm_name" "$device" +fi + +o=`blkid $dmdev_name` +if [ -z "$o" ]; then + echo "Device $dmdev_name doesn't seem to contain a filesystem, creating one." + # dd will write the device until it's full and then return with an error because "no space left" + dd if=/dev/zero of="$dmdev_name" || true + mkfs.ext4 "$dmdev_name" +else + echo "Device $dmdev_name seems to contain filesystem: $o" +fi diff --git a/test/cases/040_packages/004_dm-crypt/000_simple/check.sh b/test/cases/040_packages/004_dm-crypt/000_simple/check.sh new file mode 100755 index 000000000..ffad3ca35 --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/000_simple/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "dm-crypt test suite FAILED\n" >&1 + exit 1 +} + +[ -b /dev/mapper/it_is_encrypted ] || failed + +printf "dm-crypt test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/004_dm-crypt/000_simple/test.sh b/test/cases/040_packages/004_dm-crypt/000_simple/test.sh new file mode 100644 index 000000000..3e518fc3a --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/000_simple/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that the losetup package works +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=dm-crypt +DISK=disk.img + +clean_up() { + rm -rf ${NAME}-* ${DISK} +} +trap clean_up EXIT + +# Test code goes here +linuxkit build -format kernel+initrd -name ${NAME} test.yml +RESULT="$(linuxkit run -disk file=${DISK},size=32M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/004_dm-crypt/000_simple/test.yml b/test/cases/040_packages/004_dm-crypt/000_simple/test.yml new file mode 100644 index 000000000..2ce7db685 --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/000_simple/test.yml @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.14.88 + cmdline: "console=ttyS0 console=ttyAMA0" +init: + - linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1 + - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe +onboot: + - name: dm-crypt + image: linuxkit/dm-crypt:9e41a164358b0235f0c242219b1a424c6552d46c + command: ["/usr/bin/crypto", "it_is_encrypted", "/dev/sda"] + - name: test + image: alpine:3.8 + net: host + binds: + - /check.sh:/check.sh + - /dev:/dev + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:afe8f7dd0d47a7991c54519b0f09124cb8c4e300 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh + - path: etc/dm-crypt/key + contents: "abcdefghijklmnopqrstuvwxyz123456" +trust: + org: + - linuxkit + image: + - alpine:3.8 diff --git a/test/cases/040_packages/004_dm-crypt/001_luks/check.sh b/test/cases/040_packages/004_dm-crypt/001_luks/check.sh new file mode 100755 index 000000000..ffad3ca35 --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/001_luks/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "dm-crypt test suite FAILED\n" >&1 + exit 1 +} + +[ -b /dev/mapper/it_is_encrypted ] || failed + +printf "dm-crypt test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/004_dm-crypt/001_luks/test.sh b/test/cases/040_packages/004_dm-crypt/001_luks/test.sh new file mode 100644 index 000000000..89cdafe7e --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/001_luks/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that the losetup package works +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=dm-crypt +DISK=disk.img + +clean_up() { + rm -rf ${NAME}-* ${DISK} +} +trap clean_up EXIT + +# Test code goes here +linuxkit build -format kernel+initrd -name ${NAME} test.yml +RESULT="$(linuxkit run -disk file=${DISK},size=8M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/004_dm-crypt/001_luks/test.yml b/test/cases/040_packages/004_dm-crypt/001_luks/test.yml new file mode 100644 index 000000000..841556cd9 --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/001_luks/test.yml @@ -0,0 +1,30 @@ +kernel: + image: linuxkit/kernel:4.14.88 + cmdline: "console=ttyS0 console=ttyAMA0" +init: + - linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1 + - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe +onboot: + - name: dm-crypt + image: linuxkit/dm-crypt:9e41a164358b0235f0c242219b1a424c6552d46c + command: ["/usr/bin/crypto", "-l", "it_is_encrypted", "/dev/sda"] + - name: test + image: alpine:3.8 + net: host + binds: + - /check.sh:/check.sh + - /dev:/dev + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:afe8f7dd0d47a7991c54519b0f09124cb8c4e300 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh + - path: etc/dm-crypt/key + contents: "abcdefghijklmnopqrstuvwxyz123456" +trust: + org: + - linuxkit + image: + - alpine:3.8 diff --git a/test/cases/040_packages/004_dm-crypt/002_key/check.sh b/test/cases/040_packages/004_dm-crypt/002_key/check.sh new file mode 100755 index 000000000..ffad3ca35 --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/002_key/check.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +function failed { + printf "dm-crypt test suite FAILED\n" >&1 + exit 1 +} + +[ -b /dev/mapper/it_is_encrypted ] || failed + +printf "dm-crypt test suite PASSED\n" >&1 diff --git a/test/cases/040_packages/004_dm-crypt/002_key/test.sh b/test/cases/040_packages/004_dm-crypt/002_key/test.sh new file mode 100644 index 000000000..3e518fc3a --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/002_key/test.sh @@ -0,0 +1,26 @@ +#!/bin/sh +# SUMMARY: Check that the losetup package works +# LABELS: +# REPEAT: + +set -e + +# Source libraries. Uncomment if needed/defined +#. "${RT_LIB}" +. "${RT_PROJECT_ROOT}/_lib/lib.sh" + +NAME=dm-crypt +DISK=disk.img + +clean_up() { + rm -rf ${NAME}-* ${DISK} +} +trap clean_up EXIT + +# Test code goes here +linuxkit build -format kernel+initrd -name ${NAME} test.yml +RESULT="$(linuxkit run -disk file=${DISK},size=32M ${NAME})" +echo "${RESULT}" +echo "${RESULT}" | grep -q "suite PASSED" + +exit 0 diff --git a/test/cases/040_packages/004_dm-crypt/002_key/test.yml b/test/cases/040_packages/004_dm-crypt/002_key/test.yml new file mode 100644 index 000000000..a0ef005ae --- /dev/null +++ b/test/cases/040_packages/004_dm-crypt/002_key/test.yml @@ -0,0 +1,33 @@ +kernel: + image: linuxkit/kernel:4.14.88 + cmdline: "console=ttyS0 console=ttyAMA0" +init: + - linuxkit/init:c563953a2277eb73a89d89f70e4b6dcdcfebc2d1 + - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe +onboot: + - name: dm-crypt + image: linuxkit/dm-crypt:9e41a164358b0235f0c242219b1a424c6552d46c + command: ["/usr/bin/crypto", "-k", "/some/other/enc_key", "it_is_encrypted", "/dev/sda"] + binds: + - /dev/:/dev + - /some/other/enc_key:/some/other/enc_key + - name: test + image: alpine:3.8 + net: host + binds: + - /check.sh:/check.sh + - /dev:/dev + command: ["sh", "./check.sh"] + - name: poweroff + image: linuxkit/poweroff:afe8f7dd0d47a7991c54519b0f09124cb8c4e300 + command: ["/bin/sh", "/poweroff.sh", "10"] +files: + - path: check.sh + source: ./check.sh + - path: some/other/enc_key + contents: "abcdefghijklmnopqrstuvwxyz123456" +trust: + org: + - linuxkit + image: + - alpine:3.8 diff --git a/test/cases/040_packages/012_losetup/test.yml b/test/cases/040_packages/012_losetup/test.yml index 4cad560fe..803f59466 100644 --- a/test/cases/040_packages/012_losetup/test.yml +++ b/test/cases/040_packages/012_losetup/test.yml @@ -6,7 +6,7 @@ init: - linuxkit/runc:83d0edb4552b1a5df1f0976f05f442829eac38fe onboot: - name: losetup - image: linuxkit/losetup:aaceeea49ac519bc3b87da239436dd997d67b431 + image: linuxkit/losetup:b05ffc8641cc955abe45f6730cbe6d723b63bd3f command: ["/usr/bin/loopy", "-c", "/var/test.img"] - name: test image: alpine:3.8