diff --git a/.gitignore b/.gitignore index 89f9ac0..e3f7771 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ out/ +work-*/ diff --git a/Makefile b/Makefile index bb84458..c1d7956 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,12 @@ -iso: - sudo mkteaiso -o ${PWD}/out -p ${PWD} +master: + cp ${PWD}/template/install.master.sh ${PWD}/airootfs/root/install.sh + cp ${PWD}/template/profile.master.yaml ${PWD}/profile.yaml + sudo mkteaiso -o ${PWD}/out -w ${PWD}/work-master -p ${PWD} + +slave: + cp ${PWD}/template/install.slave.sh ${PWD}/airootfs/root/install.sh + cp ${PWD}/template/profile.slave.yaml ${PWD}/profile.yaml + sudo mkteaiso -o ${PWD}/out -w ${PWD}/work-slave -p ${PWD} clean: sudo rm -f ${PWD}/out/*.iso diff --git a/airootfs/root/install.sh b/airootfs/root/install.sh index 77b2b78..3c6e36d 100644 --- a/airootfs/root/install.sh +++ b/airootfs/root/install.sh @@ -2,7 +2,7 @@ ### ## -## NoveriaOS Install script +## NoveriaOS Master Install script ## ### @@ -21,6 +21,7 @@ readonly INSTALLATION_PARTLABEL_ROOT="ROOT" readonly INSTALLATION_ESP_PARTITION_SIZE=4 readonly INSTALLATION_MOUNTPOINT='/mnt' readonly INSTALLATION_NOVERIA_BIN='/usr/local/noveria/bin' +readonly INSTALLATION_WG_KEYDIR='/opt/wireguard/keys' readonly INSTALLATION_SECRETS_FILE="/root/installation.secrets" readonly INSTALLATION_SALT_ROOT="srv/salt" readonly INSTALLATION_SALT_GIT="https://git.noveria.org/NoveriaOS/salt-statetree.git" @@ -156,6 +157,7 @@ function introDialogue() { OS: NoveriaOS Version: $(date "+%Y%m") + IP: $(ifconfig eth0 | grep "inet addr" | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2) How do you want to continue? " @@ -215,6 +217,13 @@ function prepareInstallation() { INSTALLATION_ROOT_PW="${INSTALLATION_ROOT_PW}-$(randomPasswordGen 5)" done + # hostname + INSTALLATION_HOSTNAME=$(dialog --clear --title "What's the hostname of this device?" --inputbox "Enter hostname" 10 70 3>&1 1>&2 2>&3 3>&-) + + # domain + INSTALLATION_DOMAIN=$(dialog --clear --title "What's the domain of this device?" --inputbox "Enter domain (leave empty for localhost)" 10 70 3>&1 1>&2 2>&3 3>&-) + [[ -z "$INSTALLATION_DOMAIN" ]] && INSTALLATION_DOMAIN="localhost" + # show summary summary } @@ -224,7 +233,8 @@ function prepareInstallation() { ## function summary() { dialog --stdout --clear --title "Summary" --yes-label "Confirm" --no-label "Abort" --yesno "\n -Disk: $INSTALLATION_DISK +Hostname: ${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}\n +Disk: $INSTALLATION_DISK " 9 60 case $? in @@ -345,7 +355,9 @@ function installation() { cp /etc/apk/repositories "${INSTALLATION_MOUNTPOINT}/etc/apk/repositories" || installationFailed installationSubtaskTitle "Install SaltStack" - chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add salt-minion envsubst" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add salt-master salt-minion envsubst wireguard-tools wireguard-tools-wg" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-update add salt-master boot" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-service salt-master start" || installationFailed installationSubtaskTitle "Setup keymap" chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-keymap ch ch" || installationFailed @@ -357,7 +369,7 @@ function installation() { chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hwclock --systohc" || installationFailed installationSubtaskTitle "Setup hostname" - chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'nov-alp1.localhost' > /etc/hostname" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo '${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}' > /etc/hostname" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname -F /etc/hostname" || installationFailed chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-update add hostname" || installationFailed @@ -371,6 +383,31 @@ function installation() { chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'btrfs' >> /etc/modules" chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'efivarfs' >> /etc/modules" + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Configure Wireguard Connection │" + echo "└──────────────────────────────────────────┘" + + mkdir -p "${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}" + chroot_hostname=$(chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname | cut -d. -f1") + + installationSubtaskTitle "Generate WG-Keypair" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg genkey | (umask 0077 && tee ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.key) | wg pubkey > ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub" & + + while [[ -z "$(cat ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub 2> /dev/null)" ]]; do + sleep 0.2 + done + +echo "Wireguard Public Key: $(cat ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub) +IP: $(ifconfig eth0 | grep 'inet addr' | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2)" + + read -p "Press [Enter] when copied to clipboard and setup on master-host!" + + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip link add dev wg0 type wireguard" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip addr add 10.0.0.1/24 dev wg0" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg set wg0 listen-port 51871 private-key ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.key" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip link set wg0 up" + echo "" echo "┌──────────────────────────────────────────┐" echo "│ Configure SaltStack and highstate │" @@ -380,7 +417,24 @@ function installation() { mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT} git clone ${INSTALLATION_SALT_GIT} ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT} - cat >"${INSTALLATION_MOUNTPOINT}/etc/salt/minion" <"${INSTALLATION_MOUNTPOINT}/etc/salt/master.d/noveria.conf" <"${INSTALLATION_MOUNTPOINT}/etc/salt/minion.d/noveria.conf" < label: NOVERIAOS diff --git a/template/install.master.sh b/template/install.master.sh new file mode 100644 index 0000000..3c6e36d --- /dev/null +++ b/template/install.master.sh @@ -0,0 +1,565 @@ +#!/usr/bin/env bash + +### +## +## NoveriaOS Master Install script +## +### + +### +## Definitions +### + +# Checks +readonly CHECK_INTERNET_URL='www.alpinelinux.org' + +# Installation +readonly INSTALLATION_LOCK_FILE='/root/.installation.lock' +readonly INSTALLATION_LOGFILE='/root/installation.log' +readonly INSTALLATION_PARTLABEL_ESP="ESP" +readonly INSTALLATION_PARTLABEL_ROOT="ROOT" +readonly INSTALLATION_ESP_PARTITION_SIZE=4 +readonly INSTALLATION_MOUNTPOINT='/mnt' +readonly INSTALLATION_NOVERIA_BIN='/usr/local/noveria/bin' +readonly INSTALLATION_WG_KEYDIR='/opt/wireguard/keys' +readonly INSTALLATION_SECRETS_FILE="/root/installation.secrets" +readonly INSTALLATION_SALT_ROOT="srv/salt" +readonly INSTALLATION_SALT_GIT="https://git.noveria.org/NoveriaOS/salt-statetree.git" +readonly INSTALLATION_PILLAR_ROOT="srv/pillar" +readonly INSTALLATION_PILLAR_GIT="https://git.noveria.org/NoveriaOS/salt-pillartree.git" +readonly INSTALLATION_ALPINE_VERSION=$(cat /etc/os-release | grep VERSION_ID | cut -d= -f2) + +# Colors +readonly RED='\033[0;31m' +readonly NC='\033[0m' # No Color + +### +## Errorhandling +### +# set -e exit script when a command fails +# set -o pipefail check any command in pipeline for error, not just last one +# set -eo pipefail + +# catch ^C and other signals and clean up +trap "errorHardExit 'Interrupted with CTRL+C'" SIGINT SIGHUP SIGTERM SIGABRT + +### +## Helper Functions +### + +## +# Installation subtask title output +# - $1: subtask title +## +function installationSubtaskTitle() { + echo -e "\n=> $1" +} + +## +# Random password generator (alphanumeric) +# - $1: password length (default 11) +# - $2: avoid poorly readable characters: l/I/1, O/0 (default false) +## +function randomPasswordGen() { + # character set + if ${2:-false}; then + local character_set='a-km-zA-HJ-NP-Z2-9' + else + local character_set='a-zA-Z0-9' + fi + + # https://en.wikipedia.org/wiki/randomPasswordGen#Bash + LC_ALL=C tr -dc "$character_set" /dev/null 2>&1; do + dialog --clear --title "No internet connection" --msgbox " + Insert network cable, wait 5 seconds and press 'OK'" 7 65 + done + + prepareInstallation +} + +## +# Installation preparation +## +function prepareInstallation() { + + # disk + readonly AVAILABLE_DISKS=($(lsblk | grep -vE "p[0-9]+" | grep -vE "[s,v]d[a-z][0-9]+" | grep -v "luks" | grep -v "rom" | grep -vE "sd[a-z][0-9]+" | grep -v "/" | tail -n +2 | awk '{print $1}')) + for available_disk in ${AVAILABLE_DISKS[@]}; do + if [[ -z "$diskString" ]]; then + diskString="$available_disk /dev/$available_disk off" + else + diskString="$diskString $available_disk /dev/$available_disk off" + fi + done + + INSTALLATION_DISK=$(dialog --clear --radiolist "Select Disk to install the system" 10 70 3 $(echo $diskString) 3>&1 1>&2 2>&3 3>&-) + INSTALLATION_DISK_BYID=$(lshw -class disk | grep ${INSTALLATION_DISK} | tr -d "[:space:]" | cut -d: -f2) + + # root password + INSTALLATION_ROOT_PW=$(randomPasswordGen 5) + for _ in {0..2}; do + INSTALLATION_ROOT_PW="${INSTALLATION_ROOT_PW}-$(randomPasswordGen 5)" + done + + # hostname + INSTALLATION_HOSTNAME=$(dialog --clear --title "What's the hostname of this device?" --inputbox "Enter hostname" 10 70 3>&1 1>&2 2>&3 3>&-) + + # domain + INSTALLATION_DOMAIN=$(dialog --clear --title "What's the domain of this device?" --inputbox "Enter domain (leave empty for localhost)" 10 70 3>&1 1>&2 2>&3 3>&-) + [[ -z "$INSTALLATION_DOMAIN" ]] && INSTALLATION_DOMAIN="localhost" + + # show summary + summary +} + +## +# Summary to confirm +## +function summary() { + dialog --stdout --clear --title "Summary" --yes-label "Confirm" --no-label "Abort" --yesno "\n +Hostname: ${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}\n +Disk: $INSTALLATION_DISK + " 9 60 + + case $? in + 0) installation ;; + 1) + clear + errorHardExit "Abort on summary dialog" + ;; + 255) + clear + errorHardExit "Abort on summary dialog" + ;; + esac +} + +## +# Installation +## +function installation() { + # clear display + clear + + # lock file + touch "$INSTALLATION_LOCK_FILE" || installationFailed + + # log all output to logfile + rm -f "$INSTALLATION_LOGFILE" || installationFailed + exec &> >(tee -a "$INSTALLATION_LOGFILE") + + # create boot environment timestamp + START_TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Swipe and repartition disk │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Wipe disk" + blkdiscard -f "${INSTALLATION_DISK_BYID}" || installationFailed + + installationSubtaskTitle "Repartitioning disk" + parted -s "${INSTALLATION_DISK_BYID}" mklabel gpt || installationFailed + parted -s "${INSTALLATION_DISK_BYID}" mkpart "${INSTALLATION_PARTLABEL_ESP}" fat32 1MiB ${INSTALLATION_ESP_PARTITION_SIZE}GiB || installationFailed + parted -s "${INSTALLATION_DISK_BYID}" set 1 esp on || installationFailed + parted -s "${INSTALLATION_DISK_BYID}" mkpart "${INSTALLATION_PARTLABEL_ROOT}" btrfs ${INSTALLATION_ESP_PARTITION_SIZE}GiB 100% || installationFailed + + # Informing the Kernel of the changes. + sleep 0.1 + partprobe "${INSTALLATION_DISK_BYID}" || installationFailed + + # loop until lsblk is updated and gives the partition back + while + sleep 0.1 + ESP_PARTITION="/dev/$(lsblk "${INSTALLATION_DISK_BYID}" -o NAME,PARTLABEL | grep "${INSTALLATION_PARTLABEL_ESP}" | cut -d " " -f1 | cut -c7-)" || installationFailed + ROOT_PARTITION="/dev/$(lsblk "${INSTALLATION_DISK_BYID}" -o NAME,PARTLABEL | grep "${INSTALLATION_PARTLABEL_ROOT}" | cut -d " " -f1 | cut -c7-)" || installationFailed + [[ "${ESP_PARTITION}" == '/dev/' || "${ROOT_PARTITION}" == '/dev/' ]] + do :; done + + installationSubtaskTitle "File system creation" + mkfs.vfat -F 32 -n EFI "${ESP_PARTITION}" || installationFailed + mkfs.btrfs -f -L ROOT "${ROOT_PARTITION}" || installationFailed + + installationSubtaskTitle "Create btrfs subvolumes" + mount -t btrfs "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@root_${START_TIMESTAMP}" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@home" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@podman" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@mysql" || installationFailed + umount "${INSTALLATION_MOUNTPOINT}" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Mount filesystems │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Mount btrfs subvolumes" + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@root_"${START_TIMESTAMP}" "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}" || installationFailed + mkdir -p ${INSTALLATION_MOUNTPOINT}/{efi,home,btrfs,var/lib/mysql,opt/podman,sys/firmware/efi/efivars} || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@home "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/home" || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@podman "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/opt/podman" || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@mysql "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/var/lib/mysql" || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=/ "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/btrfs" || installationFailed + + installationSubtaskTitle "Mount ESP" + mount -o nodev,nosuid,noexec "${ESP_PARTITION}" "${INSTALLATION_MOUNTPOINT}/efi" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Install and configure OS │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Install base packages" + wget https://raw.githubusercontent.com/alpinelinux/alpine-make-rootfs/v0.7.0/alpine-make-rootfs + chmod u+x alpine-make-rootfs + ./alpine-make-rootfs --no-cleanup --branch 'v'$(echo ${INSTALLATION_ALPINE_VERSION} | rev | cut -d. -f2- | rev) --packages "apk-tools alpine-base linux-lts linux-firmware-none zsh vim btrfs-progs dialog wget git mkinitfs lsblk parted lshw shadow" ${INSTALLATION_MOUNTPOINT} + + installationSubtaskTitle "Setup resolv.conf" + if [[ -f "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" ]]; then + rm -f "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" + fi + cp /etc/resolv.conf "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" || installationFailed + + installationSubtaskTitle "Setup PATH" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'" || installationFailed + + installationSubtaskTitle "Mount extra mounts for chroot" + mount -t proc /proc "${INSTALLATION_MOUNTPOINT}/proc" || installationFailed + mount -t sysfs /sys "${INSTALLATION_MOUNTPOINT}/sys" || installationFailed + mount -t efivarfs efivarfs "${INSTALLATION_MOUNTPOINT}/sys/firmware/efi/efivars" || installationFailed + mount -o bind /dev "${INSTALLATION_MOUNTPOINT}/dev" || installationFailed + mount -o bind /run "${INSTALLATION_MOUNTPOINT}/run" || installationFailed + + + installationSubtaskTitle "Install base-packages" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add alpine-base --no-cache" || installationFailed + + installationSubtaskTitle "Overwrite default repositories" + cp /etc/apk/repositories "${INSTALLATION_MOUNTPOINT}/etc/apk/repositories" || installationFailed + + installationSubtaskTitle "Install SaltStack" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add salt-master salt-minion envsubst wireguard-tools wireguard-tools-wg" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-update add salt-master boot" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-service salt-master start" || installationFailed + + installationSubtaskTitle "Setup keymap" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-keymap ch ch" || installationFailed + + installationSubtaskTitle "Setting localtime to Europe/Zurich" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-timezone Europe/Zurich" || installationFailed + + installationSubtaskTitle "Time sync" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hwclock --systohc" || installationFailed + + installationSubtaskTitle "Setup hostname" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo '${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}' > /etc/hostname" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname -F /etc/hostname" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-update add hostname" || installationFailed + + installationSubtaskTitle "Setup hosts" + cp /etc/hosts "${INSTALLATION_MOUNTPOINT}/etc/hosts" || installationFailed + + installationSubtaskTitle "Set root password" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo -e \"${INSTALLATION_ROOT_PW}\n${INSTALLATION_ROOT_PW}\" | passwd" || installationFailed + + installationSubtaskTitle "Enable btrfs module" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'btrfs' >> /etc/modules" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'efivarfs' >> /etc/modules" + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Configure Wireguard Connection │" + echo "└──────────────────────────────────────────┘" + + mkdir -p "${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}" + chroot_hostname=$(chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname | cut -d. -f1") + + installationSubtaskTitle "Generate WG-Keypair" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg genkey | (umask 0077 && tee ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.key) | wg pubkey > ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub" & + + while [[ -z "$(cat ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub 2> /dev/null)" ]]; do + sleep 0.2 + done + +echo "Wireguard Public Key: $(cat ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub) +IP: $(ifconfig eth0 | grep 'inet addr' | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2)" + + read -p "Press [Enter] when copied to clipboard and setup on master-host!" + + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip link add dev wg0 type wireguard" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip addr add 10.0.0.1/24 dev wg0" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg set wg0 listen-port 51871 private-key ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.key" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip link set wg0 up" + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Configure SaltStack and highstate │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Clone Salt-Repo" + mkdir -p ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT} + git clone ${INSTALLATION_SALT_GIT} ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_SALT_ROOT} + + mkdir -p "${INSTALLATION_MOUNTPOINT}/etc/salt/master.d" + cat >"${INSTALLATION_MOUNTPOINT}/etc/salt/master.d/noveria.conf" <"${INSTALLATION_MOUNTPOINT}/etc/salt/minion.d/noveria.conf" <"${INSTALLATION_MOUNTPOINT}/etc/salt/grains" <"${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/system/init.sls" << EOT +timestamp: ${START_TIMESTAMP} +EOT + + installationSubtaskTitle "Salt highstate" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "salt-call state.highstate" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Boot │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Make EFI boot image with mkinitfs" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "mkinitfs $(uname -r)" || installationFailed + + installationSubtaskTitle "Installing grub to /efi" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || installationFailed + + installationSubtaskTitle "Generating Bootmenu entries" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || installationFailed + + installationSubtaskTitle "Generating motd" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Finishing │" + echo "└──────────────────────────────────────────┘" + + #installationSubtaskTitle "Unmount" + #umount -l ${INSTALLATION_MOUNTPOINT} || installationFailed + + installationSubtaskTitle "End of installation" + + # end log all output to logfile + exec &>"$(tty)" + + # write secrets file + writeInstallationSecretsToFile + + # remove installation lock file + rm -f "$INSTALLATION_LOCK_FILE" + + # remove shell histories + rm -f /root/.zsh_history + + dialog --stdout --clear --cr-wrap --no-collapse --yes-label "Reboot" --no-label "Alpine shell" --yesno "\n Installation finished" 7 50 + case $? in + 0) reboot ;; + 1) + clear + exit + ;; + 255) + clear + exit + ;; + esac +} + +## +# Write installation secrets to file +## +writeInstallationSecretsToFile() { + rm -f "$INSTALLATION_SECRETS_FILE" + { + echo "# Installation secrets from $START_TIMESTAMP" + echo "" + echo "FQDN: $(cat /mnt/etc/hostname)" + echo "" + echo "root_pw: ${INSTALLATION_ROOT_PW}" + echo "" + } >>"$INSTALLATION_SECRETS_FILE" +} + +## +# Installation failed +# - $1: comment +## +installationFailed() { + # log error + echo -e "\n=> ERROR" + if [ -n "$1" ]; then + echo -e "=> Comment: $1" + fi + + # end log all output to logfile + exec &>"$(tty)" + + # Remove lock file + rm -f $INSTALLATION_LOCK_FILE + + dialog --no-collapse --ok-label "Exit" --msgbox "\n Installation failed\n\nLog: ${INSTALLATION_LOGFILE} " 9 32 + clear + exit 1 +} + + +### +## Script Start +### + +preChecks + +### +## Script End +### diff --git a/template/install.slave.sh b/template/install.slave.sh new file mode 100644 index 0000000..8cc3bdf --- /dev/null +++ b/template/install.slave.sh @@ -0,0 +1,551 @@ +#!/usr/bin/env bash + +### +## +## NoveriaOS Slave Install script +## +### + +### +## Definitions +### + +# Checks +readonly CHECK_INTERNET_URL='www.alpinelinux.org' + +# Installation +readonly INSTALLATION_LOCK_FILE='/root/.installation.lock' +readonly INSTALLATION_LOGFILE='/root/installation.log' +readonly INSTALLATION_PARTLABEL_ESP="ESP" +readonly INSTALLATION_PARTLABEL_ROOT="ROOT" +readonly INSTALLATION_ESP_PARTITION_SIZE=4 +readonly INSTALLATION_MOUNTPOINT='/mnt' +readonly INSTALLATION_NOVERIA_BIN='/usr/local/noveria/bin' +readonly INSTALLATION_WG_KEYDIR='/opt/wireguard/keys' +readonly INSTALLATION_SECRETS_FILE="/root/installation.secrets" +readonly INSTALLATION_PILLAR_ROOT="srv/pillar" +readonly INSTALLATION_PILLAR_GIT="https://git.noveria.org/NoveriaOS/salt-pillartree.git" +readonly INSTALLATION_ALPINE_VERSION=$(cat /etc/os-release | grep VERSION_ID | cut -d= -f2) + +# Colors +readonly RED='\033[0;31m' +readonly NC='\033[0m' # No Color + +### +## Errorhandling +### +# set -e exit script when a command fails +# set -o pipefail check any command in pipeline for error, not just last one +# set -eo pipefail + +# catch ^C and other signals and clean up +trap "errorHardExit 'Interrupted with CTRL+C'" SIGINT SIGHUP SIGTERM SIGABRT + +### +## Helper Functions +### + +## +# Installation subtask title output +# - $1: subtask title +## +function installationSubtaskTitle() { + echo -e "\n=> $1" +} + +## +# Random password generator (alphanumeric) +# - $1: password length (default 11) +# - $2: avoid poorly readable characters: l/I/1, O/0 (default false) +## +function randomPasswordGen() { + # character set + if ${2:-false}; then + local character_set='a-km-zA-HJ-NP-Z2-9' + else + local character_set='a-zA-Z0-9' + fi + + # https://en.wikipedia.org/wiki/randomPasswordGen#Bash + LC_ALL=C tr -dc "$character_set" /dev/null 2>&1; do + dialog --clear --title "No internet connection" --msgbox " + Insert network cable, wait 5 seconds and press 'OK'" 7 65 + done + + prepareInstallation +} + +## +# Installation preparation +## +function prepareInstallation() { + + # disk + readonly AVAILABLE_DISKS=($(lsblk | grep -vE "p[0-9]+" | grep -vE "[s,v]d[a-z][0-9]+" | grep -v "luks" | grep -v "rom" | grep -vE "sd[a-z][0-9]+" | grep -v "/" | tail -n +2 | awk '{print $1}')) + for available_disk in ${AVAILABLE_DISKS[@]}; do + if [[ -z "$diskString" ]]; then + diskString="$available_disk /dev/$available_disk off" + else + diskString="$diskString $available_disk /dev/$available_disk off" + fi + done + + INSTALLATION_DISK=$(dialog --clear --radiolist "Select Disk to install the system" 10 70 3 $(echo $diskString) 3>&1 1>&2 2>&3 3>&-) + INSTALLATION_DISK_BYID=$(lshw -class disk | grep ${INSTALLATION_DISK} | tr -d "[:space:]" | cut -d: -f2) + + # root password + INSTALLATION_ROOT_PW=$(randomPasswordGen 5) + for _ in {0..2}; do + INSTALLATION_ROOT_PW="${INSTALLATION_ROOT_PW}-$(randomPasswordGen 5)" + done + + # hostname + INSTALLATION_HOSTNAME=$(dialog --clear --title "What's the hostname of this device?" --inputbox "Enter hostname" 10 70 3>&1 1>&2 2>&3 3>&-) + + # domain + INSTALLATION_DOMAIN=$(dialog --clear --title "What's the domain of this device?" --inputbox "Enter domain (leave empty for localhost)" 10 70 3>&1 1>&2 2>&3 3>&-) + [[ -z "$INSTALLATION_DOMAIN" ]] && INSTALLATION_DOMAIN="localhost" + + # salt-master ip + INSTALLATION_MASTER_IP=$(dialog --clear --title "What's the IP of the salt-master?" --inputbox "Enter IP Address" 10 70 3>&1 1>&2 2>&3 3>&-) + + # wireguard ip + INSTALLATION_WG_IP=$(dialog --clear --title "What's the hosts wireguard IP?" --inputbox "Enter IP Address" 10 70 3>&1 1>&2 2>&3 3>&-) + + # wireguard peer master public + INSTALLATION_WG_MASTER_PUB=$(dialog --clear --title "Enter the public key of the wireguard master" --inputbox "Enter publickey" 10 70 3>&1 1>&2 2>&3 3>&-) + + # show summary + summary +} + +## +# Summary to confirm +## +function summary() { + dialog --stdout --clear --title "Summary" --yes-label "Confirm" --no-label "Abort" --yesno "\n +Hostname: ${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}\n +Salt-Master: $INSTALLATION_MASTER_IP\n +WG-IP: $INSTALLATION_WG_IP\n +WG-master-pub: $INSTALLATION_WG_MASTER_PUB\n +Disk: $INSTALLATION_DISK + " 9 60 + + case $? in + 0) installation ;; + 1) + clear + errorHardExit "Abort on summary dialog" + ;; + 255) + clear + errorHardExit "Abort on summary dialog" + ;; + esac +} + +## +# Installation +## +function installation() { + # clear display + clear + + # lock file + touch "$INSTALLATION_LOCK_FILE" || installationFailed + + # log all output to logfile + rm -f "$INSTALLATION_LOGFILE" || installationFailed + exec &> >(tee -a "$INSTALLATION_LOGFILE") + + # create boot environment timestamp + START_TIMESTAMP=$(date +"%Y-%m-%d_%H-%M-%S") || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Swipe and repartition disk │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Wipe disk" + blkdiscard -f "${INSTALLATION_DISK_BYID}" || installationFailed + + installationSubtaskTitle "Repartitioning disk" + parted -s "${INSTALLATION_DISK_BYID}" mklabel gpt || installationFailed + parted -s "${INSTALLATION_DISK_BYID}" mkpart "${INSTALLATION_PARTLABEL_ESP}" fat32 1MiB ${INSTALLATION_ESP_PARTITION_SIZE}GiB || installationFailed + parted -s "${INSTALLATION_DISK_BYID}" set 1 esp on || installationFailed + parted -s "${INSTALLATION_DISK_BYID}" mkpart "${INSTALLATION_PARTLABEL_ROOT}" btrfs ${INSTALLATION_ESP_PARTITION_SIZE}GiB 100% || installationFailed + + # Informing the Kernel of the changes. + sleep 0.1 + partprobe "${INSTALLATION_DISK_BYID}" || installationFailed + + # loop until lsblk is updated and gives the partition back + while + sleep 0.1 + ESP_PARTITION="/dev/$(lsblk "${INSTALLATION_DISK_BYID}" -o NAME,PARTLABEL | grep "${INSTALLATION_PARTLABEL_ESP}" | cut -d " " -f1 | cut -c7-)" || installationFailed + ROOT_PARTITION="/dev/$(lsblk "${INSTALLATION_DISK_BYID}" -o NAME,PARTLABEL | grep "${INSTALLATION_PARTLABEL_ROOT}" | cut -d " " -f1 | cut -c7-)" || installationFailed + [[ "${ESP_PARTITION}" == '/dev/' || "${ROOT_PARTITION}" == '/dev/' ]] + do :; done + + installationSubtaskTitle "File system creation" + mkfs.vfat -F 32 -n EFI "${ESP_PARTITION}" || installationFailed + mkfs.btrfs -f -L ROOT "${ROOT_PARTITION}" || installationFailed +sys + installationSubtaskTitle "Create btrfs subvolumes" + mount -t btrfs "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@root_${START_TIMESTAMP}" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@home" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@podman" || installationFailed + btrfs sub create "${INSTALLATION_MOUNTPOINT}/@mysql" || installationFailed + umount "${INSTALLATION_MOUNTPOINT}" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Mount filesystems │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Mount btrfs subvolumes" + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@root_"${START_TIMESTAMP}" "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}" || installationFailed + mkdir -p ${INSTALLATION_MOUNTPOINT}/{efi,home,btrfs,var/lib/mysql,opt/podman,sys/firmware/efi/efivars} || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@home "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/home" || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@podman "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/opt/podman" || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=@mysql "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/var/lib/mysql" || installationFailed + mount -o noatime,nodiratime,discard=async,space_cache=v2,subvol=/ "${ROOT_PARTITION}" "${INSTALLATION_MOUNTPOINT}/btrfs" || installationFailed + + installationSubtaskTitle "Mount ESP" + mount -o nodev,nosuid,noexec "${ESP_PARTITION}" "${INSTALLATION_MOUNTPOINT}/efi" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Install and configure OS │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Install base packages" + wget https://raw.githubusercontent.com/alpinelinux/alpine-make-rootfs/v0.7.0/alpine-make-rootfs + chmod u+x alpine-make-rootfs + ./alpine-make-rootfs --no-cleanup --branch 'v'$(echo ${INSTALLATION_ALPINE_VERSION} | rev | cut -d. -f2- | rev) --packages "apk-tools alpine-base linux-lts linux-firmware-none zsh vim btrfs-progs dialog wget git mkinitfs lsblk parted lshw shadow" ${INSTALLATION_MOUNTPOINT} + + installationSubtaskTitle "Setup resolv.conf" + if [[ -f "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" ]]; then + rm -f "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" + fi + cp /etc/resolv.conf "${INSTALLATION_MOUNTPOINT}/etc/resolv.conf" || installationFailed + + installationSubtaskTitle "Setup PATH" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "export PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'" || installationFailed + + installationSubtaskTitle "Mount extra mounts for chroot" + mount -t proc /proc "${INSTALLATION_MOUNTPOINT}/proc" || installationFailed + mount -t sysfs /sys "${INSTALLATION_MOUNTPOINT}/sys" || installationFailed + mount -t efivarfs efivarfs "${INSTALLATION_MOUNTPOINT}/sys/firmware/efi/efivars" || installationFailed + mount -o bind /dev "${INSTALLATION_MOUNTPOINT}/dev" || installationFailed + mount -o bind /run "${INSTALLATION_MOUNTPOINT}/run" || installationFailed + + + installationSubtaskTitle "Install base-packages" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add alpine-base --no-cache" || installationFailed + + installationSubtaskTitle "Overwrite default repositories" + cp /etc/apk/repositories "${INSTALLATION_MOUNTPOINT}/etc/apk/repositories" || installationFailed + + installationSubtaskTitle "Install SaltStack" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "apk add salt-minion envsubst wireguard-tools wireguard-tools-wg" || installationFailed + + installationSubtaskTitle "Setup keymap" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-keymap ch ch" || installationFailed + + installationSubtaskTitle "Setting localtime to Europe/Zurich" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "setup-timezone Europe/Zurich" || installationFailed + + installationSubtaskTitle "Time sync" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hwclock --systohc" || installationFailed + + installationSubtaskTitle "Setup hostname" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo '${INSTALLATION_HOSTNAME}.${INSTALLATION_DOMAIN}' > /etc/hostname" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname -F /etc/hostname" || installationFailed + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "rc-update add hostname" || installationFailed + + installationSubtaskTitle "Setup hosts" + cp /etc/hosts "${INSTALLATION_MOUNTPOINT}/etc/hosts" || installationFailed + + installationSubtaskTitle "Set root password" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo -e \"${INSTALLATION_ROOT_PW}\n${INSTALLATION_ROOT_PW}\" | passwd" || installationFailed + + installationSubtaskTitle "Enable btrfs module" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'btrfs' >> /etc/modules" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "echo 'efivarfs' >> /etc/modules" + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Configure Wireguard Connection │" + echo "└──────────────────────────────────────────┘" + + mkdir -p "${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}" + chroot_hostname=$(chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "hostname | cut -d. -f1") + + installationSubtaskTitle "Generate WG-Keypair" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg genkey | (umask 0077 && tee ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.key) | wg pubkey > ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub" & + + while [[ -z "$(cat ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub 2> /dev/null)" ]]; do + sleep 0.2 + done + +echo "Wireguard Public Key: $(cat ${INSTALLATION_MOUNTPOINT}/${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.pub) +IP: $(ifconfig eth0 | grep 'inet addr' | awk '{$1=$1};1' | awk '{print $2}' | cut -d: -f2)" + + read -p "Press [Enter] when copied to clipboard and setup on master-host!" + + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip link add dev wg0 type wireguard" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip addr add ${INSTALLATION_WG_IP}/24 dev wg0" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg set wg0 listen-port 51871 private-key ${INSTALLATION_WG_KEYDIR}/${chroot_hostname}.key" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "wg set wg0 peer ${INSTALLATION_WG_MASTER_PUB} endpoint ${INSTALLATION_MASTER_IP}:51871 allowed-ips 10.0.0.1/32" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "ip link set wg0 up" + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Configure SaltStack and highstate │" + echo "└──────────────────────────────────────────┘" + + mkdir -p "${INSTALLATION_MOUNTPOINT}/etc/salt/pki/minion" || installationFailed + + mkdir -p "${INSTALLATION_MOUNTPOINT}/etc/salt/minion.d" + cat >"${INSTALLATION_MOUNTPOINT}/etc/salt/minion.d/noveria.conf" <"${INSTALLATION_MOUNTPOINT}/etc/salt/grains" <"${INSTALLATION_MOUNTPOINT}/${INSTALLATION_PILLAR_ROOT}/system/init.sls" << EOT +timestamp: ${START_TIMESTAMP} +EOT + + installationSubtaskTitle "Salt highstate" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "salt-call state.highstate" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Boot │" + echo "└──────────────────────────────────────────┘" + + installationSubtaskTitle "Make EFI boot image with mkinitfs" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "mkinitfs $(uname -r)" || installationFailed + + installationSubtaskTitle "Installing grub to /efi" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/ash -c "grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=alpine" || installationFailed + + installationSubtaskTitle "Generating Bootmenu entries" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/noveriablcgen --noconfirm" || installationFailed + + installationSubtaskTitle "Generating motd" + chroot "${INSTALLATION_MOUNTPOINT}" /bin/bash -c "/usr/local/noveria/bin/generate_motd" || installationFailed + + echo "" + echo "┌──────────────────────────────────────────┐" + echo "│ Finishing │" + echo "└──────────────────────────────────────────┘" + + #installationSubtaskTitle "Unmount" + #umount -l ${INSTALLATION_MOUNTPOINT} || installationFailed + + installationSubtaskTitle "End of installation" + + # end log all output to logfile + exec &>"$(tty)" + + # write secrets file + writeInstallationSecretsToFile + + # remove installation lock file + rm -f "$INSTALLATION_LOCK_FILE" + + # remove shell histories + rm -f /root/.zsh_history + + dialog --stdout --clear --cr-wrap --no-collapse --yes-label "Reboot" --no-label "Alpine shell" --yesno "\n Installation finished" 7 50 + case $? in + 0) reboot ;; + 1) + clear + exit + ;; + 255) + clear + exit + ;; + esac +} + +## +# Write installation secrets to file +## +writeInstallationSecretsToFile() { + rm -f "$INSTALLATION_SECRETS_FILE" + { + echo "# Installation secrets from $START_TIMESTAMP" + echo "" + echo "FQDN: $(cat /mnt/etc/hostname)" + echo "" + echo "root_pw: ${INSTALLATION_ROOT_PW}" + echo "" + } >>"$INSTALLATION_SECRETS_FILE" +} + +## +# Installation failed +# - $1: comment +## +installationFailed() { + # log error + echo -e "\n=> ERROR" + if [ -n "$1" ]; then + echo -e "=> Comment: $1" + fi + + # end log all output to logfile + exec &>"$(tty)" + + # Remove lock file + rm -f $INSTALLATION_LOCK_FILE + + dialog --no-collapse --ok-label "Exit" --msgbox "\n Installation failed\n\nLog: ${INSTALLATION_LOGFILE} " 9 32 + clear + exit 1 +} + + +### +## Script Start +### + +preChecks + +### +## Script End +### diff --git a/template/profile.master.yaml b/template/profile.master.yaml new file mode 100755 index 0000000..392718d --- /dev/null +++ b/template/profile.master.yaml @@ -0,0 +1,17 @@ +name: noveriaos-master +distro: alpine +publisher: Noveria Network +label: NOVERIAOS +codename: latest-stable +application_id: Alpine Linux Live Media +airootfs_directory: airootfs +#iso_merge: iso_merge +compression: squashfs||-comp gzip +grub_cfg: grub.cfg +packages: + - packages.x86_64 +file_permissions: + - /etc/shadow|0:0:400 + - /root/install.sh|0:0:755 +customize_airootfs: + - customize-airootfs.sh diff --git a/template/profile.slave.yaml b/template/profile.slave.yaml new file mode 100755 index 0000000..d65c92e --- /dev/null +++ b/template/profile.slave.yaml @@ -0,0 +1,17 @@ +name: noveriaos-slave +distro: alpine +publisher: Noveria Network +label: NOVERIAOS +codename: latest-stable +application_id: Alpine Linux Live Media +airootfs_directory: airootfs +#iso_merge: iso_merge +compression: squashfs||-comp gzip +grub_cfg: grub.cfg +packages: + - packages.x86_64 +file_permissions: + - /etc/shadow|0:0:400 + - /root/install.sh|0:0:755 +customize_airootfs: + - customize-airootfs.sh