21700: Install Bundler system-wide in Rails postinst
[arvados.git] / tools / compute-images / scripts / usr-local-bin-ensure-encrypted-partitions.sh
1 #!/bin/bash
2
3 # Copyright (C) The Arvados Authors. All rights reserved.
4 #
5 # SPDX-License-Identifier: Apache-2.0
6
7 set -e
8 set -x
9
10 VGNAME=compute
11 LVNAME=tmp
12 LVPATH="/dev/mapper/${VGNAME}-${LVNAME}"
13 CRYPTPATH=/dev/mapper/tmp
14 MOUNTPATH=/tmp
15
16 findmntq() {
17     findmnt "$@" >/dev/null
18 }
19
20 ensure_umount() {
21     if findmntq "$1"; then
22         umount "$1"
23     fi
24 }
25
26 if findmntq --source "$CRYPTPATH" --target "$MOUNTPATH"; then
27     exit 0
28 fi
29
30 CLOUD_SERVER=""
31 while [[ ! "$CLOUD_SERVER" ]]; do
32     CLOUD_SERVER="$(curl --silent --head http://169.254.169.254/ \
33                     | awk '($1 == "Server:"){sub("\\r+$", ""); print substr($0, 9)}')"
34 done
35
36 DISK_PATTERN=""
37 case "$CLOUD_SERVER" in
38     # EC2
39     EC2ws) DISK_PATTERN=/dev/xvd ;;
40     # GCP
41     "Metadata Server for VM") DISK_PATTERN=/dev/sd ;;
42     # Azure
43     Microsoft-IIS/*) DISK_PATTERN=/dev/sd ;;
44 esac
45
46 if [[ -z "$DISK_PATTERN" ]]; then
47     echo "ensure-encrypted-partitions: Unknown disk configuration; can't run." >&2
48     exit 3
49 fi
50
51 declare -a LVM_DEVS=()
52
53 ROOT_PARTITION=`findmnt / -f -o source -n`
54 if [[ "$ROOT_PARTITION" =~ ^\/dev\/nvme ]]; then
55   # e.g. /dev/nvme0n1p1, strip last 4 characters
56   ROOT_DEVICE_STRING=${ROOT_PARTITION%????}
57 else
58   # e.g. /dev/xvda1, strip last character
59   ROOT_DEVICE_STRING=${ROOT_PARTITION//[0-9]/}
60 fi
61
62 # Newer AWS node types use another pattern, /dev/nvmeXn1 for fast instance SSD disks
63 if [[ "$CLOUD_SERVER" == "EC2ws" ]]; then
64   for dev in `ls /dev/nvme* 2>/dev/null`; do
65     if [[ "$dev" == "$ROOT_PARTITION" ]] || [[ "$dev" =~ ^$ROOT_DEVICE_STRING ]]; then
66       continue
67     fi
68     if [[ -e ${dev}n1 ]]; then
69       ensure_umount "${dev}n1"
70       if [[ "$devtype" = disk ]]; then
71         dd if=/dev/zero of="${dev}n1" bs=512 count=1
72       fi
73       LVM_DEVS+=("${dev}n1")
74     fi
75   done
76 fi
77
78 # Look for traditional disks but only if we're not on AWS or if we haven't found
79 # a fast instance /dev/nvmeXn1 disk
80 if [[ "$CLOUD_SERVER" != "EC2ws" ]] || [[ ${#LVM_DEVS[@]} -eq 0 ]]; then
81   for dev in `ls $DISK_PATTERN* 2>/dev/null`; do
82     # On Azure, we are dealing with /dev/sdb1, on GCP, /dev/sdb, on AWS, /dev/xvdb
83     if [[ "$dev" == "$ROOT_PARTITION" ]] || [[ "$dev" =~ ^$ROOT_DEVICE_STRING ]]; then
84       continue
85     fi
86     if [[ ! "$dev" =~ [a-z]$ ]]; then
87       continue
88     fi
89     if [[ -e ${dev}1 ]]; then
90         dev=${dev}1
91         devtype=partition
92     else
93         devtype=disk
94     fi
95     ensure_umount "$dev"
96     if [[ "$devtype" = disk ]]; then
97         dd if=/dev/zero of="$dev" bs=512 count=1
98     fi
99     LVM_DEVS+=("$dev")
100   done
101 fi
102
103 if [[ "${#LVM_DEVS[@]}" -eq 0 ]]; then
104     echo "ensure-encrypted-partitions: No extra disks found." >&2
105     exit 4
106 fi
107
108 vgcreate --force --yes "$VGNAME" "${LVM_DEVS[@]}"
109 lvcreate --extents 100%FREE --name "$LVNAME" "$VGNAME"
110
111 KEYPATH="$(mktemp -p /var/tmp key-XXXXXXXX.tmp)"
112 modprobe dm_mod aes sha256
113 head -c321 /dev/urandom >"$KEYPATH"
114 echo YES | cryptsetup luksFormat "$LVPATH" "$KEYPATH"
115 cryptsetup --key-file "$KEYPATH" luksOpen "$LVPATH" "$(basename "$CRYPTPATH")"
116 shred -u "$KEYPATH"
117 mkfs.xfs -f "$CRYPTPATH"
118
119 # First make sure docker is not using /tmp, then unmount everything under it.
120 if [ -d /etc/sv/docker.io ]
121 then
122   # TODO: Actually detect Docker state with runit
123   DOCKER_ACTIVE=true
124   sv stop docker.io || service stop docker.io || true
125 else
126   if systemctl --quiet is-active docker.service docker.socket; then
127     systemctl stop docker.service docker.socket || true
128     DOCKER_ACTIVE=true
129   else
130     DOCKER_ACTIVE=false
131   fi
132 fi
133
134 ensure_umount "$MOUNTPATH/docker/aufs"
135
136 MOUNTOPTIONS="async"
137 mount -o ${MOUNTOPTIONS} "$CRYPTPATH" "$MOUNTPATH"
138 chmod a+w,+t "$MOUNTPATH"
139
140 # Make sure docker uses the big partition
141 cat <<EOF > /etc/docker/daemon.json
142 {
143     "data-root": "$MOUNTPATH/docker-data"
144 }
145 EOF
146
147 if ! $DOCKER_ACTIVE; then
148   # Nothing else to do
149   exit 0
150 fi
151
152 # restart docker
153 if [ -d /etc/sv/docker.io ]
154 then
155   ## runit
156   sv up docker.io
157 else
158   systemctl start docker.service docker.socket || true
159 fi
160
161 end=$((SECONDS+60))
162
163 while [ $SECONDS -lt $end ]; do
164   if /usr/bin/docker ps -q >/dev/null; then
165     exit 0
166   fi
167   sleep 1
168 done
169
170 # Docker didn't start within a minute, abort
171 exit 1