second commit
This commit is contained in:
@@ -0,0 +1,652 @@
|
||||
#!/bin/bash
|
||||
|
||||
RED='\e[0;41m\e[1;37m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[0;33m'
|
||||
PURPLE='\033[0;35m'
|
||||
DARK='\e[100m'
|
||||
NC='\033[0m' # No Color
|
||||
TO_BE_DEFINED="TO BE DEFINED"
|
||||
|
||||
# BOLD='\033[1m'
|
||||
# DIM='\e[2m\e[0;90m'
|
||||
|
||||
function echo() {
|
||||
[[ -n ${PREFIX:-} ]] && printf "${DARK}%25.25s${NC} " "${PREFIX}"
|
||||
builtin echo "$@"
|
||||
}
|
||||
|
||||
function check_normal_user() {
|
||||
[[ $(id -u) -lt 1000 ]] && echoerr "normal user (>1000) expected, please connect as a normal user then call again!" && exit 100
|
||||
return 0
|
||||
}
|
||||
|
||||
function sudo_required() {
|
||||
check_normal_user
|
||||
command -v sudo &>/dev/null &&
|
||||
id -G | grep -q sudo && echoerr "command <sudo> not found, please install as so: \`apt install -y sudo\`" && exit 1
|
||||
if ! sudo -n true &>/dev/null; then
|
||||
if [[ -n "${1:-}" ]]; then
|
||||
echowarnn "[sudo] requiring authorized access for: [ $1 ]"
|
||||
else
|
||||
echowarnn "[sudo] requiring authorized access for further processing"
|
||||
fi
|
||||
fi
|
||||
sudo -vp ' : '
|
||||
}
|
||||
|
||||
# idempotent cargo install <package1 package2 ...>
|
||||
function idem_cargo_install() {
|
||||
for i in "$@"; do
|
||||
if [ ! -f ~/.cargo/bin/"$i" ]; then
|
||||
cargo install "$i"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# display error in red
|
||||
function echoerr() {
|
||||
echo -e "${RED}$*${NC}" >&2
|
||||
}
|
||||
|
||||
function echoerrn() {
|
||||
echo -en "${RED}$*${NC}" >&2
|
||||
}
|
||||
|
||||
# display warn in yellow
|
||||
function echowarn() {
|
||||
echo -e "${YELLOW}$*${NC}" >&2
|
||||
}
|
||||
|
||||
function echowarnn() {
|
||||
echo -en "${YELLOW}$*${NC}" >&2
|
||||
}
|
||||
|
||||
# display error in green
|
||||
function echoinfo() {
|
||||
echo -e "${GREEN}$*${NC}" >&2
|
||||
}
|
||||
|
||||
function echoinfon() {
|
||||
echo -en "${GREEN}$*${NC}" >&2
|
||||
}
|
||||
|
||||
# test whether <ip> is a valid ipv4 address?
|
||||
function valid_ipv4() {
|
||||
local ip="$1"
|
||||
if [[ $ip =~ ^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$ ]]; then
|
||||
IFS='.' read -ra ADDR <<<"$ip"
|
||||
[[ ${ADDR[0]} -le 255 && ${ADDR[1]} -le 255 && ${ADDR[2]} -le 255 && ${ADDR[3]} -le 255 ]]
|
||||
return $?
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
function enable_trace() {
|
||||
trap 'trap_error $? ${LINENO:-0} ${BASH_LINENO:-0} ${BASH_COMMAND:-empty} $(printf "::%s" ${FUNCNAME[@]})' ERR
|
||||
}
|
||||
|
||||
function disable_trace() {
|
||||
trap - ERR
|
||||
}
|
||||
|
||||
function prepare_nftables() {
|
||||
local PREFIX="miaou:nftables"
|
||||
|
||||
if [[ ! -f /etc/nftables.rules.d/firewall.table ]]; then
|
||||
echo "installing nftables ..."
|
||||
sudo apt install -y nftables
|
||||
sudo cp -f "$MIAOU_BASEDIR/templates/hardened/nftables.conf" /etc/
|
||||
sudo mkdir -p /etc/nftables.rules.d
|
||||
sudo cp -f "$MIAOU_BASEDIR/templates/hardened/firewall.table" /etc/nftables.rules.d/
|
||||
sudo systemctl restart nftables
|
||||
sudo systemctl enable nftables
|
||||
echo "OK"
|
||||
else
|
||||
echo "nftables already installed!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function miaou_init() {
|
||||
# shellcheck source=/dev/null
|
||||
[[ -f /opt/debian-bash/lib/functions.sh ]] && source /opt/debian-bash/lib/functions.sh
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$MIAOU_BASEDIR/lib/functions.sh"
|
||||
|
||||
export MIAOU_CONFIGDIR="$HOME/.config/miaou"
|
||||
|
||||
set -Eeuo pipefail
|
||||
enable_trace
|
||||
trap 'ctrl_c $? ${LINENO:-0} ${BASH_LINENO:-0} ${BASH_COMMAND:-empty} $(printf "::%s" ${FUNCNAME[@]})' INT
|
||||
}
|
||||
|
||||
function ctrl_c() {
|
||||
PREFIX="miaou:trap" echoerr "Ctrl + C happened, exiting!!! $*"
|
||||
exit 125
|
||||
}
|
||||
|
||||
# extract source code error triggered on trap error <error_code> <error_line>
|
||||
function trap_error() {
|
||||
ERRORS_COUNT=0
|
||||
if [[ -f "$MIAOU_CONFIGDIR"/error_count ]]; then
|
||||
ERRORS_COUNT=$(cat "$MIAOU_CONFIGDIR"/error_count)
|
||||
else
|
||||
mkdir -p "$MIAOU_CONFIGDIR"
|
||||
printf 0 >"$MIAOU_CONFIGDIR"/error_count
|
||||
fi
|
||||
ERRORS_COUNT=$((ERRORS_COUNT + 1))
|
||||
printf '%s' $ERRORS_COUNT >"$MIAOU_CONFIGDIR"/error_count
|
||||
|
||||
local PREFIX=""
|
||||
|
||||
# local file="${0:-}"
|
||||
local err=$1 # error status
|
||||
local line=$2 # LINENO
|
||||
local linecallfunc=${3:-}
|
||||
local command="${4:-}"
|
||||
local funcstack="${5:-}"
|
||||
local caller
|
||||
|
||||
caller=$(caller | cut -d' ' -f2)
|
||||
|
||||
# echo >&2
|
||||
# if [ "$funcstack" != "::" ]; then
|
||||
# echo -e "${RED}ERROR <$err>, due to command <$command> at line $line from <$caller>, stack=${funcstack}${NC}" >&2
|
||||
# else
|
||||
# echo >&2 "ERROR DETECTED"
|
||||
# fi
|
||||
|
||||
# echo
|
||||
# echo -e "${PURPLE}$caller:$line ${NC}EXIT ${RED}<$err>${NC}" >&2
|
||||
# echo -e "${PURPLE}------------------------------------------ ${NC}" >&2
|
||||
if [[ $ERRORS_COUNT == 1 ]]; then
|
||||
echo
|
||||
echo -e "${RED}ERROR <$err>, due to command <$command $funcstack>${NC}" >&2
|
||||
fi
|
||||
echo -e "${PURPLE}$ERRORS_COUNT: $caller:$line ${RED}$command $funcstack${NC}" >&2
|
||||
# echo -e "${PURPLE}----------------------------- ${PURPLE}EXIT CODE ${PURPLE}--------------${PURPLE} $err ${NC}" >&2
|
||||
|
||||
# if [[ $line -gt 2 ]]; then
|
||||
# sed "$((line - 2))q;d" "$caller" >&2
|
||||
# sed "$((line - 1))q;d" "$caller" >&2
|
||||
# fi
|
||||
# echo -ne "${BOLD}" >&2
|
||||
# sed "${line}q;d" "$caller" >&2
|
||||
# echo -e "${PURPLE}------------------------------------------ ${NC}" >&2
|
||||
}
|
||||
|
||||
# exist_command(cmd1, ...)
|
||||
# test all commands exist, else fail
|
||||
function exist_command() {
|
||||
for i in "$@"; do
|
||||
command -v "$i" &>/dev/null || return 50
|
||||
done
|
||||
}
|
||||
|
||||
# test whether container <ct> is up and running?
|
||||
function container_running() {
|
||||
arg1_required "$@"
|
||||
container_exists "$1" && lxc list "$1" -c ns -f csv | head -n1 | grep -q "$1,RUNNING"
|
||||
lxc exec "$1" -- bash <<EOF
|
||||
set -Eeuo pipefail
|
||||
if [[ ! -f /root/cloud-status.json ]]; then
|
||||
cloud-init status --wait >/dev/null
|
||||
fi
|
||||
EOF
|
||||
}
|
||||
|
||||
# test arg1 required
|
||||
function arg1_required() {
|
||||
[[ -z "${1:-}" ]] && echoerr "ERROR: arg#1 expected!" && return 125
|
||||
return 0
|
||||
}
|
||||
|
||||
# test arg2 required
|
||||
function arg2_required() {
|
||||
[[ -z "${2:-}" ]] && echoerr "ERROR: arg#2 expected!" && return 125
|
||||
return 0
|
||||
}
|
||||
|
||||
# test whether container <ct> exists yet?
|
||||
function container_exists() {
|
||||
arg1_required "$@"
|
||||
lxc list "$1" -c n -f csv | grep -q "^$1\$"
|
||||
}
|
||||
|
||||
# build debian image with prebuild debian-bash and various useful settings
|
||||
# ARG1=release [bullseye, buster]
|
||||
function build_miaou_image() {
|
||||
local RELEASE="$1"
|
||||
local IMAGE_LABEL="$RELEASE-miaou"
|
||||
local PREFIX="miaou:image"
|
||||
|
||||
local DEB_REPOSITORY
|
||||
DEB_REPOSITORY=$(grep ^deb /etc/apt/sources.list | head -n1 | cut -d ' ' -f2 | cut -d '/' -f3)
|
||||
|
||||
if ! lxc image -cl list -f csv | grep -q "$IMAGE_LABEL"; then
|
||||
|
||||
echo "building lxc image <$IMAGE_LABEL> ... "
|
||||
echo "image will reuse same local repository <$DEB_REPOSITORY>"
|
||||
creation_date=$(date +%s)
|
||||
sudo /opt/debian-bash/tools/idem_apt_install debootstrap
|
||||
|
||||
cat <<EOF1 | sudo bash
|
||||
set -euo pipefail
|
||||
rm -rf /tmp/$IMAGE_LABEL{,-image}
|
||||
mkdir -p /tmp/$IMAGE_LABEL{,-image}
|
||||
debootstrap $RELEASE /tmp/$IMAGE_LABEL http://$DEB_REPOSITORY/debian
|
||||
|
||||
echo
|
||||
echo "DEBOOTSTRAP ... OK"
|
||||
echo
|
||||
|
||||
cat <<EOF2 | chroot /tmp/$IMAGE_LABEL
|
||||
set -euo pipefail
|
||||
echo "image prepare source.list from $DEB_REPOSITORY"
|
||||
if [[ "$RELEASE" == "buster" ]]; then
|
||||
cat <<EOF3 >/etc/apt/sources.list
|
||||
deb http://$DEB_REPOSITORY/debian $RELEASE main contrib
|
||||
deb http://$DEB_REPOSITORY/debian $RELEASE-updates main contrib
|
||||
deb http://$DEB_REPOSITORY/debian-security/ $RELEASE/updates main contrib
|
||||
EOF3
|
||||
else
|
||||
cat <<EOF3 >/etc/apt/sources.list
|
||||
deb http://$DEB_REPOSITORY/debian $RELEASE main contrib
|
||||
deb http://$DEB_REPOSITORY/debian $RELEASE-updates main contrib
|
||||
deb http://$DEB_REPOSITORY/debian-security/ $RELEASE-security main contrib
|
||||
EOF3
|
||||
fi
|
||||
|
||||
echo APT UPDATE
|
||||
|
||||
apt update && apt dist-upgrade -y
|
||||
apt install -y curl wget file git sudo bash-completion
|
||||
curl https://git.artcode.re/pvincent/debian-bash/raw/branch/master/install.sh | sudo bash -s -- --host
|
||||
ln -sf /usr/share/zoneinfo/Indian/Reunion /etc/localtime
|
||||
cat <<EOF3 >/etc/network/interfaces
|
||||
# This file describes the network interfaces available on your system
|
||||
# and how to activate them. For more information, see interfaces(5).
|
||||
|
||||
# The loopback network interface
|
||||
auto lo
|
||||
iface lo inet loopback
|
||||
|
||||
auto eth0
|
||||
iface eth0 inet dhcp
|
||||
|
||||
source /etc/network/interfaces.d/*
|
||||
EOF3
|
||||
echo "deboostrap ready!"
|
||||
EOF2
|
||||
cd /tmp/$IMAGE_LABEL-image
|
||||
tar -czf rootfs.tar.gz -C /tmp/$IMAGE_LABEL .
|
||||
cat <<EOF2 >metadata.yaml
|
||||
architecture: "x86_64"
|
||||
creation_date: $creation_date
|
||||
properties:
|
||||
architecture: "x86_64"
|
||||
description: "Debian $RELEASE for miaou instances"
|
||||
os: "debian"
|
||||
release: "$RELEASE"
|
||||
EOF2
|
||||
tar -czf metadata.tar.gz metadata.yaml
|
||||
EOF1
|
||||
lxc image import "/tmp/$IMAGE_LABEL-image/metadata.tar.gz" "/tmp/$IMAGE_LABEL-image/rootfs.tar.gz" --alias "$IMAGE_LABEL"
|
||||
echo "image <$IMAGE_LABEL> successfully built!"
|
||||
echo DONE
|
||||
else
|
||||
echo "image <$IMAGE_LABEL> already built!"
|
||||
fi
|
||||
}
|
||||
|
||||
# execute remote scripting onto one LXC container <CONTAINER> [COMMANDS, ...]
|
||||
# may use one command like: `lxc_exec ct1 uname -a`
|
||||
# or pipe like so: `
|
||||
# cat <<EOF | lxc_exec ct1
|
||||
# ls -l
|
||||
# uname -a
|
||||
# echo [\$0] [\$1] [\$2] # toto titi tata
|
||||
# EOF
|
||||
# `
|
||||
function lxc_exec() {
|
||||
arg1_required "$@"
|
||||
container="$1"
|
||||
shift
|
||||
|
||||
declare -a ARGUMENTS
|
||||
ARGUMENTS=(toto titi tata) # might be overriden with interesting stuff!
|
||||
|
||||
if ((${#} == 0)); then
|
||||
multiline=""
|
||||
while read -r line; do
|
||||
if [[ ! "$line" =~ ^\# ]] && [[ ! "$line" =~ ^[[:space:]]*$ ]]; then
|
||||
if [[ "$line" =~ .*\;$ ]] || [[ "$line" =~ do$ ]] || [[ "$line" =~ then$ ]] || [[ "$line" =~ else$ ]]; then
|
||||
multiline+="${line} " # append space in case of ending with either '; do then else'
|
||||
else
|
||||
multiline+="${line};" # append ; for multiple commands
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# echo "DEBUG: multiline = [$multiline]"
|
||||
# echo DEBUG: lxc exec "$container" -- bash -lc "$multiline" "${ARGUMENTS[@]}"
|
||||
lxc exec "$container" -- bash -lc "$multiline" "${ARGUMENTS[@]}"
|
||||
else
|
||||
lxc exec "$container" -- bash -lc "$*" "${ARGUMENTS[@]}"
|
||||
fi
|
||||
}
|
||||
|
||||
# check container exist and running
|
||||
function check_container() {
|
||||
arg1_required "$@"
|
||||
local CT="$1"
|
||||
container_exists "$CT"
|
||||
container_running "$CT"
|
||||
}
|
||||
|
||||
function launch_container() {
|
||||
arg1_required "$@"
|
||||
local ct="$1"
|
||||
if ! container_exists "$ct"; then
|
||||
echo "container <$ct> about to be created ..."
|
||||
local extra_release="${2:-}"
|
||||
if [[ -n "$extra_release" ]] && ! lxc image info "${extra_release}-miaou" >/dev/null; then
|
||||
echoerrn "unknown extra_release <${extra_release}-miaou>!\nHINT : please add it into /etc/miaou/defaults.yaml, then re-install miaou!"
|
||||
exit 128
|
||||
fi
|
||||
|
||||
if [[ -n "$extra_release" ]]; then
|
||||
echoerrn "FIXME: lxc-miaou-create -o release=bookworm should be implemented ...."
|
||||
lxc-miaou-create "$ct" "$extra_release"
|
||||
else
|
||||
lxc-miaou-create "$ct"
|
||||
fi
|
||||
echo "DONE"
|
||||
fi
|
||||
|
||||
if ! container_running "$ct"; then
|
||||
echowarn "container <$ct> seems to be asleep, starting ..."
|
||||
lxc start "$ct"
|
||||
echowarn DONE
|
||||
fi
|
||||
}
|
||||
|
||||
function load_yaml_from_expanded {
|
||||
arg1_required "$@"
|
||||
yaml_key="$1"
|
||||
yaml_file="$MIAOU_CONFIGDIR/miaou.expanded.yaml"
|
||||
yaml_value=$(yq ".$yaml_key" "$yaml_file")
|
||||
if [[ -n "$yaml_value" ]] && [[ "$yaml_value" != "null" ]] && [[ "$yaml_value" != "$TO_BE_DEFINED" ]]; then
|
||||
PREFIX="" echo "$yaml_value"
|
||||
else
|
||||
echoerr "undefined value for key: <$yaml_key> from file: <$yaml_file>"
|
||||
return 98
|
||||
fi
|
||||
}
|
||||
|
||||
function check_yaml_defined_value {
|
||||
yaml_file="$1"
|
||||
yaml_key="$2"
|
||||
yaml_value=$(yq ".$yaml_key" "$yaml_file")
|
||||
if [[ -n "$yaml_value" ]] && [[ "$yaml_value" != "null" ]] && [[ "$yaml_value" != "$TO_BE_DEFINED" ]]; then
|
||||
return 0
|
||||
else
|
||||
echoerr "undefined value for key: <$yaml_key> from file: <$yaml_file>"
|
||||
return 99
|
||||
fi
|
||||
}
|
||||
|
||||
# halt unless current user is root
|
||||
function root_required() {
|
||||
[[ $(id -u) == 0 ]] || (echoerr "root required" && return 1)
|
||||
}
|
||||
|
||||
# arg#1: environment variable
|
||||
# read from environment or ask entry before exporting new variable
|
||||
function env_or_ask {
|
||||
if [[ -n ${1+x} ]]; then
|
||||
if printenv "$1" >/dev/null; then
|
||||
echo "value defined as $(printenv "$1")"
|
||||
else
|
||||
printf "Please define %20s: " "$1"
|
||||
read -r
|
||||
export "$1=\"$REPLY\"" >/dev/null
|
||||
fi
|
||||
else
|
||||
echoerr "env_or_ask requires one argument: <VARIABLE_NAME>" && exit 5
|
||||
fi
|
||||
}
|
||||
|
||||
# install_debian_bash()
|
||||
# grab and install related project
|
||||
function install_debian_bash() {
|
||||
local PREFIX="debian-bash:install"
|
||||
if [[ ! -d /opt/debian-bash ]]; then
|
||||
echo "installing curl wget commands ..."
|
||||
apt install -y curl wget
|
||||
|
||||
echo "installing debian-bash..."
|
||||
curl https://git.artcode.re/pvincent/debian-bash/raw/branch/master/install.sh | sudo bash -s -- --host
|
||||
export PATH=$PATH:/opt/debian-bash/tools/
|
||||
echo "OK"
|
||||
else
|
||||
# /opt/debian-bash/tools/debian_bash_upgrade
|
||||
echo "addon <debian-bash> already installed!"
|
||||
fi
|
||||
# shellcheck source=/dev/null
|
||||
source /etc/bash.bashrc
|
||||
|
||||
sudo /opt/debian-bash/tools/idem_apt_install bash-completion
|
||||
}
|
||||
|
||||
function add_toolbox_sudoers {
|
||||
local PREFIX="toolbox:sudoers"
|
||||
echo -n "creating sudoers file to allow sudo as command from /TOOLBOX... "
|
||||
sudo mkdir -p /etc/sudoers.d
|
||||
if [[ ! -f /etc/sudoers.d/add_TOOLBOX_to_PATH ]]; then
|
||||
sudo tee /etc/sudoers.d/add_TOOLBOX_to_PATH &>/dev/null <<EOF
|
||||
Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/TOOLBOX"
|
||||
EOF
|
||||
PREFIX="" echo "updated!"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
}
|
||||
|
||||
function prepare_toolbox() {
|
||||
local PREFIX="toolbox:prepare"
|
||||
sudo mkdir -p /TOOLBOX
|
||||
|
||||
if ! command -v cargo &>/dev/null; then
|
||||
echo -n "installing <cargo> ... "
|
||||
curl -sSf https://sh.rustup.rs | sh -s -- -y
|
||||
# shellcheck source=/dev/null
|
||||
source "$HOME/.cargo/env"
|
||||
/opt/debian-bash/tools/append_or_replace "^PATH=\$PATH:\$HOME/\\.cargo/bin" "PATH=\$PATH:\$HOME/.cargo/bin" ~/.bashrc
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
echo "command <cargo> already installed!"
|
||||
fi
|
||||
|
||||
echo -n "installing <fd> ... "
|
||||
if [ ! -f "/TOOLBOX/fd" ]; then
|
||||
idem_cargo_install fd-find
|
||||
sudo cp "$HOME"/.cargo/bin/fd /TOOLBOX/fd
|
||||
PREFIX="" echo "successfully installed!"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <viu> ... "
|
||||
if [ ! -f "/TOOLBOX/viu" ]; then
|
||||
idem_cargo_install viu
|
||||
sudo cp "$HOME"/.cargo/bin/viu /TOOLBOX/
|
||||
PREFIX="" echo "successfully installed!"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <rg> alias <ripgrep> ... "
|
||||
if [ ! -f "/TOOLBOX/rg" ]; then
|
||||
|
||||
sudo /opt/debian-bash/tools/idem_apt_install ripgrep
|
||||
sudo ln /usr/bin/rg /TOOLBOX/
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <ag> alias <silversearcher-ag> ... "
|
||||
if [ ! -f "/TOOLBOX/ag" ]; then
|
||||
sudo /opt/debian-bash/tools/idem_apt_install silversearcher-ag
|
||||
sudo ln /usr/bin/ag /TOOLBOX/
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <bandwhich> ... "
|
||||
if [ ! -f "/TOOLBOX/bandwhich" ]; then
|
||||
idem_cargo_install bandwhich
|
||||
sudo cp "$HOME"/.cargo/bin/bandwhich /TOOLBOX/bandwhich
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <btm> alias <bottom> ... "
|
||||
if [ ! -f "/TOOLBOX/btm" ]; then
|
||||
VERSION=$(wget_semver github ClementTsang/bottom)
|
||||
cd /tmp
|
||||
wget "https://github.com/ClementTsang/bottom/releases/download/$VERSION/bottom_x86_64-unknown-linux-musl.tar.gz"
|
||||
tar -xzvf bottom_x86_64-unknown-linux-musl.tar.gz
|
||||
sudo cp btm /usr/local/bin/
|
||||
sudo ln /usr/local/bin/btm /TOOLBOX/
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <micro> ... "
|
||||
if [ ! -f "/TOOLBOX/micro" ]; then
|
||||
cd /tmp || (echoerr "/tmp wrong permission" && exit 101)
|
||||
curl -q https://getmic.ro | GETMICRO_REGISTER=n sh
|
||||
sudo mv micro /TOOLBOX/micro
|
||||
sudo chown root:root /TOOLBOX/micro
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <ncdu> ... "
|
||||
if [ ! -f "/TOOLBOX/ncdu" ]; then
|
||||
sudo /opt/debian-bash/tools/idem_apt_install ncdu
|
||||
sudo cp /usr/bin/ncdu /TOOLBOX/ncdu
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <unzip> ... "
|
||||
if [ ! -f "/TOOLBOX/unzip" ]; then
|
||||
sudo /opt/debian-bash/tools/idem_apt_install unzip
|
||||
sudo cp /usr/bin/unzip /TOOLBOX/unzip
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <tree> ... "
|
||||
if [ ! -f "/TOOLBOX/tree" ]; then
|
||||
sudo /opt/debian-bash/tools/idem_apt_install tree
|
||||
sudo cp /bin/tree /TOOLBOX/tree
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <duf> ... "
|
||||
if [ ! -f "/TOOLBOX/duf" ]; then
|
||||
VERSION=$(/opt/debian-bash/tools/wget_semver github muesli/duf)
|
||||
VERSION_WITHOUT_V=${VERSION#v}
|
||||
wget -O /tmp/duf.deb "https://github.com/muesli/duf/releases/download/${VERSION}/duf_${VERSION_WITHOUT_V}_linux_amd64.deb"
|
||||
sudo dpkg -i /tmp/duf.deb
|
||||
sudo cp /bin/duf /TOOLBOX/duf
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <curl> ... "
|
||||
if [ ! -f "/TOOLBOX/curl" ]; then
|
||||
sudo wget -O /TOOLBOX/curl "https://github.com/moparisthebest/static-curl/releases/latest/download/curl-amd64"
|
||||
sudo chmod +x /TOOLBOX/curl
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
echo -n "installing <wget> ... "
|
||||
if [ ! -f "/TOOLBOX/wget" ]; then
|
||||
sudo ln -f /usr/bin/wget /TOOLBOX/wget
|
||||
PREFIX="" echo "successfully installed"
|
||||
else
|
||||
PREFIX="" echo "already done!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# install_mandatory_commands
|
||||
function install_mandatory_commands() {
|
||||
local PREFIX="mandatory:commands"
|
||||
|
||||
sudo /opt/debian-bash/tools/idem_apt_install dnsutils build-essential curl mariadb-client postgresql-client
|
||||
|
||||
if ! exist_command tera; then
|
||||
echo "installing <tera> ..."
|
||||
|
||||
local version=v0.2.4
|
||||
wget -q "https://github.com/chevdor/tera-cli/releases/download/${version}/tera-cli_linux_amd64.deb" -O /tmp/tera-cli_linux_amd64.deb
|
||||
sudo dpkg -i /tmp/tera-cli_linux_amd64.deb
|
||||
else
|
||||
echo "command <tera> already installed!"
|
||||
fi
|
||||
|
||||
if ! exist_command yq; then
|
||||
local version binary
|
||||
version='v4.35.2'
|
||||
binary='yq_linux_amd64'
|
||||
|
||||
sudo sh -c "wget https://github.com/mikefarah/yq/releases/download/${version}/${binary}.tar.gz -O - |\
|
||||
tar -xz ./${binary} && sudo mv ${binary} /usr/bin/yq"
|
||||
else
|
||||
echo "command <yq> already installed!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# flatten array, aka remove duplicated elements in array
|
||||
# return: `mapfile -t OUTPUT_ARRAY < <(sort_array "${INPUT_ARRAY[@]}")`
|
||||
function flatten_array {
|
||||
declare -a array=("$@")
|
||||
IFS=" " read -r -a array <<<"$(tr ' ' '\n' <<<"${array[@]}" | sort -u | tr '\n' ' ')"
|
||||
printf '%s\n' "${array[@]}"
|
||||
}
|
||||
|
||||
function prepare_nftables() {
|
||||
local PREFIX="miaou:firewall"
|
||||
|
||||
if [[ ! -f /etc/nftables.rules.d/firewall.table ]]; then
|
||||
echo "installing nftables ..."
|
||||
sudo apt install -y nftables
|
||||
sudo cp -f "$MIAOU_BASEDIR/templates/hardened/nftables.conf" /etc/
|
||||
sudo mkdir -p /etc/nftables.rules.d
|
||||
sudo cp -f "$MIAOU_BASEDIR/templates/hardened/firewall.table" /etc/nftables.rules.d/
|
||||
sudo systemctl restart nftables
|
||||
sudo systemctl enable nftables
|
||||
echo "OK"
|
||||
else
|
||||
echo "nftables already installed!"
|
||||
fi
|
||||
}
|
||||
Executable
+294
@@ -0,0 +1,294 @@
|
||||
#!/bin/bash
|
||||
|
||||
### FUNCTIONS
|
||||
### ---------
|
||||
|
||||
function prepare_config_hardened() {
|
||||
mkdir -p "$HARDEN_CONFIGDIR"
|
||||
}
|
||||
|
||||
function pubkey_authorize() {
|
||||
local PREFIX="harden:pubkey:authorize"
|
||||
|
||||
if [[ ! -d $HOME/.ssh ]]; then
|
||||
echo -n "create .ssh folder for the first time ..."
|
||||
mkdir -m 700 ~/.ssh
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
local security_issue_in_ssh_folder
|
||||
security_issue_in_ssh_folder=$(find "$HOME/.ssh" -perm -go=r | wc -l)
|
||||
if [[ $security_issue_in_ssh_folder -gt 0 ]]; then
|
||||
echo -n "force security in .ssh folder for <$CURRENT_USER> ..."
|
||||
chmod -R u+rwX,go-rwx "/home/$CURRENT_USER/.ssh"
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
echo "security in .ssh folder for <$CURRENT_USER> approved!"
|
||||
fi
|
||||
fi
|
||||
|
||||
pubkey_value=$(yq ".authorized.pubkey" "$HARDEN_CONFIGFILE")
|
||||
if [[ ! -f /home/$CURRENT_USER/.ssh/authorized_keys ]]; then
|
||||
echo -n "authorized_keys first time ..."
|
||||
PREFIX="" echo "$pubkey_value" >"$HOME/.ssh/authorized_keys"
|
||||
chmod u+rw,go-rwx "/home/$CURRENT_USER/.ssh/authorized_keys"
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
if ! grep -q "^$pubkey_value" "/home/$CURRENT_USER/.ssh/authorized_keys"; then
|
||||
echo -n "pubkey <$CURRENT_USER> appended to <.ssh/authorized_keys> ..."
|
||||
echo "$pubkey_value" >>"$HOME/.ssh/authorized_keys"
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
echo "pubkey <$CURRENT_USER> already authorized!"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function sudoers() {
|
||||
local PREFIX="harden:sudoers"
|
||||
if [[ -d /etc/sudoers.d ]]; then
|
||||
echo -n "add $CURRENT_USER and no more ..."
|
||||
|
||||
sudo env current_user="$CURRENT_USER" tera -e --env-key env --env-only -o /etc/sudoers -t "$MIAOU_BASEDIR/templates/hardened/sudoers.j2" >/dev/null
|
||||
|
||||
rm /etc/sudoers.d -rf
|
||||
grep -Eq "^debian" /etc/passwd && userdel -rf debian
|
||||
grep -Eq "^sudo" /etc/group && groupdel sudo
|
||||
passwd -dq root
|
||||
passwd -dq "$CURRENT_USER"
|
||||
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
echo "sudo authorized for <$CURRENT_USER> only!"
|
||||
fi
|
||||
}
|
||||
|
||||
function sshd() {
|
||||
local PREFIX="harden:sshd"
|
||||
if [[ ! -f /etc/ssh/sshd_config ]]; then
|
||||
sudo apt install -y openssh-server
|
||||
else
|
||||
echo "sshd already installed!"
|
||||
fi
|
||||
|
||||
if ! grep -Eq "^Port 2222" /etc/ssh/sshd_config; then
|
||||
echo -n "replacing sshd ..."
|
||||
|
||||
sudo env current_user="$CURRENT_USER" tera -e --env-key env --env-only -o /etc/ssh/sshd_config -t "$MIAOU_BASEDIR/templates/hardened/sshd_config.j2" >/dev/null
|
||||
sudo systemctl restart sshd
|
||||
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
echo "already done!"
|
||||
fi
|
||||
}
|
||||
|
||||
function prepare_proxy() {
|
||||
local PREFIX="harden:proxy"
|
||||
|
||||
if ! grep -Eq "^precedence ::ffff:0:0/96.*" /etc/gai.conf; then
|
||||
echo "prefer ipv4 ..."
|
||||
sudo /opt/debian-bash/tools/append_or_replace "^precedence ::ffff:0:0/96.*" "precedence ::ffff:0:0/96 100" /etc/gai.conf
|
||||
echo "OK"
|
||||
else
|
||||
echo "ipv4 already prefered!"
|
||||
fi
|
||||
|
||||
if ! grep -Eq "^net.ipv4.ip_forward=1" /etc/sysctl.conf; then
|
||||
echo "allow forwarding from kernel ..."
|
||||
sudo /opt/debian-bash/tools/append_or_replace "^net.ipv4.ip_forward=1.*" "net.ipv4.ip_forward=1" /etc/sysctl.conf
|
||||
sudo sysctl -p
|
||||
echo "OK"
|
||||
else
|
||||
echo "kernel forwarding already allowed!"
|
||||
fi
|
||||
}
|
||||
|
||||
function set_current_user {
|
||||
local PREFIX="harden:environment"
|
||||
|
||||
CURRENT_USER=$(id -un)
|
||||
echo "current user is <$CURRENT_USER>"
|
||||
}
|
||||
|
||||
function load_configuration {
|
||||
local PREFIX="harden:configuration:load"
|
||||
|
||||
if [[ ! -f "$HARDEN_CONFIGFILE" ]]; then
|
||||
echo "configuration requires further details ..."
|
||||
cp "$MIAOU_BASEDIR/templates/hardened/hardened.yaml.sample" "$HARDEN_CONFIGFILE"
|
||||
echo "OK"
|
||||
fi
|
||||
|
||||
editor "$HARDEN_CONFIGFILE"
|
||||
}
|
||||
|
||||
function check_configuration {
|
||||
local PREFIX="harden:configuration:check"
|
||||
|
||||
check_yaml_defined_value "$HARDEN_CONFIGFILE" 'authorized.pubkey'
|
||||
check_yaml_defined_value "$HARDEN_CONFIGFILE" 'alert.to'
|
||||
check_yaml_defined_value "$HARDEN_CONFIGFILE" 'alert.from'
|
||||
check_yaml_defined_value "$HARDEN_CONFIGFILE" 'alert.smtp.server'
|
||||
}
|
||||
|
||||
function set_timezone_if_defined {
|
||||
local PREFIX="harden:timezone"
|
||||
timezone=$(yq ".timezone" "$HARDEN_CONFIGFILE")
|
||||
if [[ "$timezone" != null ]]; then
|
||||
if ! grep -q "$timezone" /etc/timezone; then
|
||||
if [[ -f "/usr/share/zoneinfo/$timezone" ]]; then
|
||||
echo "set timezone to $timezone ..."
|
||||
ln -fs "/usr/share/zoneinfo/$timezone" /etc/localtime
|
||||
dpkg-reconfigure -f noninteractive tzdata
|
||||
echo OK
|
||||
else
|
||||
echoerr "unkown timezone: <$timezone>, please edit <$HARDEN_CONFIGFILE> and change to a correct value" && exit 98
|
||||
fi
|
||||
else
|
||||
echo "timezone <$timezone> already set!"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function mailer_alert() {
|
||||
local PREFIX="harden:mailer"
|
||||
|
||||
if [[ ! -f /etc/msmtprc ]]; then
|
||||
for i in exim4-config libevent-2.1-7 libgnutls-dane0 libunbound8; do
|
||||
if dpkg -l "$i" 2>/dev/null | grep -q ^ii && echo 'installed'; then
|
||||
echo "purging package <$i> ..."
|
||||
apt purge -y "$i"
|
||||
echo "OK"
|
||||
fi
|
||||
done
|
||||
|
||||
echo "installing <msmtp> ..."
|
||||
sudo /opt/debian-bash/tools/idem_apt_install msmtp msmtp-mta mailutils bsd-mailx
|
||||
echo "OK"
|
||||
|
||||
echo "configuring </etc/aliases>"
|
||||
sudo env current_user="$CURRENT_USER" tera -e --env-key env -o /etc/aliases -t "$MIAOU_BASEDIR/templates/hardened/mailer/aliases.j2" "$HARDEN_CONFIGDIR/hardened.yaml" >/dev/null
|
||||
echo "OK"
|
||||
|
||||
# populate environment variable with fqdn
|
||||
fqdn=$(hostname -f)
|
||||
|
||||
echo "configuring </etc/mail.rc>"
|
||||
sudo env current_user="$CURRENT_USER" fqdn="$fqdn" tera -e --env-key env -o /etc/mail.rc -t "$MIAOU_BASEDIR/templates/hardened/mailer/mail.rc.j2" "$HARDEN_CONFIGDIR/hardened.yaml" >/dev/null
|
||||
echo "OK"
|
||||
|
||||
echo "generating </etc/msmtprc> configuration file ..."
|
||||
sudo env fqdn="$fqdn" tera -e --env-key env -o /etc/msmtprc -t "$MIAOU_BASEDIR/templates/hardened/mailer/msmtprc.j2" "$HARDEN_CONFIGDIR/hardened.yaml" >/dev/null
|
||||
sudo chown root:msmtp /etc/msmtprc
|
||||
sudo chmod 640 /etc/msmtprc
|
||||
echo "OK"
|
||||
else
|
||||
echo "mailer <msmtp> already configured!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function alert_at_boot() {
|
||||
local PREFIX="harden:alert:boot"
|
||||
if ! systemctl is-enabled --quiet on_startup.service 2>/dev/null; then
|
||||
echo "installing <on_startup.service> on systemd..."
|
||||
sudo cp "$MIAOU_BASEDIR/templates/hardened/systemd/on_startup.service" /etc/systemd/system/on_startup.service
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable on_startup.service
|
||||
REBOOT=true
|
||||
echo "OK"
|
||||
else
|
||||
echo "systemd <on_startup.service> already enabled!"
|
||||
fi
|
||||
}
|
||||
|
||||
function show_reboot_on_purpose() {
|
||||
if "$REBOOT"; then
|
||||
PREFIX="harden:reboot" echowarn "we recommend reboot on purpose, Reboot NOW?"
|
||||
else
|
||||
PREFIX="harden" echo "success"
|
||||
fi
|
||||
}
|
||||
|
||||
function disable_systemd_resolved() {
|
||||
PREFIX="harden:systemd:resolved"
|
||||
if file /etc/resolv.conf | grep -q /run/systemd/resolve/stub-resolv.conf; then
|
||||
echo "disabling systemd-resolved..."
|
||||
sudo systemctl stop systemd-resolved.service
|
||||
sudo systemctl disable systemd-resolved.service
|
||||
sudo rm /etc/resolv.conf
|
||||
cat <<EOF | sudo tee /etc/resolv.conf
|
||||
nameserver 1.1.1.1
|
||||
EOF
|
||||
echo "OK"
|
||||
else
|
||||
echo "systemd-resolved already disabled!"
|
||||
fi
|
||||
}
|
||||
|
||||
function alert_at_ssh_password() {
|
||||
local PREFIX="harden:alert:ssh:password"
|
||||
if ! grep -Eq "^session optional pam_exec.so /usr/local/bin/alert_ssh_password.sh" /etc/pam.d/sshd; then
|
||||
echo "installing alert_at_ssh_password..."
|
||||
sudo cp "$MIAOU_BASEDIR/templates/hardened/pam/alert_ssh_password.sh" /usr/local/bin/
|
||||
sudo chmod 700 /usr/local/bin/alert_ssh_password.sh
|
||||
sudo /opt/debian-bash/tools/append_or_replace "^session optional pam_exec.so /usr/local/bin/alert_ssh_password.sh" "session optional pam_exec.so /usr/local/bin/alert_ssh_password.sh" /etc/pam.d/sshd
|
||||
echo "OK"
|
||||
else
|
||||
echo "alert_at_ssh_password already enabled!"
|
||||
fi
|
||||
}
|
||||
|
||||
function customize_motd {
|
||||
local PREFIX="harden:motd:customize"
|
||||
if [[ ! -f /etc/update-motd.d/80-users ]]; then
|
||||
echo "customizing motd..."
|
||||
sudo /opt/debian-bash/tools/idem_apt_install figlet lsb-release
|
||||
sudo rm -f /etc/motd
|
||||
sudo mkdir -p /etc/update-motd.d
|
||||
sudo rm -f /etc/update-motd.d/*
|
||||
sudo cp "$MIAOU_BASEDIR"/templates/hardened/motd/* /etc/update-motd.d/
|
||||
sudo chmod +x /etc/update-motd.d/*
|
||||
echo "OK"
|
||||
else
|
||||
echo "motd already customized!"
|
||||
fi
|
||||
}
|
||||
|
||||
### CONSTANTS
|
||||
### ---------
|
||||
|
||||
MIAOU_BASEDIR=$(readlink -f "$(dirname "$0")/..")
|
||||
readonly HARDEN_CONFIGDIR="$HOME/.config/hardened"
|
||||
readonly HARDEN_CONFIGFILE="$HARDEN_CONFIGDIR/hardened.yaml"
|
||||
|
||||
### MAIN
|
||||
### ----
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$MIAOU_BASEDIR/lib/functions.sh"
|
||||
miaou_init
|
||||
|
||||
REBOOT=false
|
||||
PREFIX="harden"
|
||||
: $PREFIX
|
||||
|
||||
sudo_required
|
||||
install_debian_bash
|
||||
install_mandatory_commands
|
||||
prepare_config_hardened
|
||||
set_current_user
|
||||
check_configuration 2>/dev/null || load_configuration
|
||||
check_configuration
|
||||
pubkey_authorize
|
||||
sshd
|
||||
prepare_proxy
|
||||
prepare_nftables
|
||||
disable_systemd_resolved
|
||||
set_timezone_if_defined
|
||||
mailer_alert
|
||||
alert_at_boot
|
||||
alert_at_ssh_password
|
||||
customize_motd
|
||||
|
||||
show_reboot_on_purpose
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/bin/bash
|
||||
|
||||
MIAOU_DIR="$(dirname "$0")/../.."
|
||||
readonly MIAOU_DIR
|
||||
|
||||
function init_strict() {
|
||||
set -Eeuo pipefail
|
||||
# shellcheck source=/dev/null
|
||||
source "$MIAOU_DIR/lib/functions.sh"
|
||||
# shellcheck source=/dev/null
|
||||
source "/opt/debian-bash/lib/functions.sh"
|
||||
trap 'trap_error $? $LINENO $BASH_LINENO "$BASH_COMMAND" $(printf "::%s" ${FUNCNAME[@]})' ERR
|
||||
}
|
||||
|
||||
## main
|
||||
init_strict
|
||||
sudo_required
|
||||
build_miaou_image "bullseye"
|
||||
Executable
+19
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
|
||||
MIAOU_DIR="$(dirname "$0")/../.."
|
||||
readonly MIAOU_DIR
|
||||
|
||||
function init_strict() {
|
||||
set -Eeuo pipefail
|
||||
# shellcheck source=/dev/null
|
||||
source "$MIAOU_DIR/lib/functions.sh"
|
||||
# shellcheck source=/dev/null
|
||||
source "/opt/debian-bash/lib/functions.sh"
|
||||
|
||||
trap 'trap_error $? $LINENO $BASH_LINENO "$BASH_COMMAND" $(printf "::%s" ${FUNCNAME[@]})' ERR
|
||||
}
|
||||
|
||||
## main
|
||||
init_strict
|
||||
sudo_required
|
||||
build_miaou_image "buster"
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/bin/bash
|
||||
|
||||
# shellcheck source=/dev/null
|
||||
. "$MIAOU_BASEDIR/lib/functions.sh"
|
||||
miaou_init
|
||||
Executable
+409
@@ -0,0 +1,409 @@
|
||||
#!/bin/bash
|
||||
|
||||
MIAOU_BASEDIR=$(readlink -f "$(dirname "$0")/..")
|
||||
# shellcheck source=/dev/null
|
||||
. "$MIAOU_BASEDIR/lib/functions.sh"
|
||||
readonly MIAOU_BASEDIR
|
||||
|
||||
miaou_init
|
||||
|
||||
EXPANDED_CONF="$MIAOU_CONFIGDIR/miaou.expanded.yaml"
|
||||
NEW_GROUP=lxd
|
||||
readonly NEW_GROUP EXPANDED_CONF
|
||||
|
||||
on_exit() {
|
||||
if [[ "$SESSION_RELOAD_REQUIRED" == true ]]; then
|
||||
echo "======================================================"
|
||||
echo "Session Reload is required (due to new group <$NEW_GROUP>)"
|
||||
echo "======================================================"
|
||||
fi
|
||||
if [ -n "${1:-}" ]; then
|
||||
echo "Aborted by $1"
|
||||
elif [ "${status:-}" -ne 0 ]; then
|
||||
echo "Failure (status $status)"
|
||||
fi
|
||||
}
|
||||
|
||||
function prepare_lxd {
|
||||
local PREFIX="lxd:prepare"
|
||||
|
||||
# test group lxd assign to current user
|
||||
if ! groups | grep -q lxd; then
|
||||
echo "define lxd and assign to user <$USER>"
|
||||
sudo groupadd --force "$NEW_GROUP"
|
||||
sudo usermod --append --groups "$NEW_GROUP" "$(whoami)"
|
||||
exec sg "$NEW_GROUP" "exec '$0' $(printf "'%s' " SESSION_RELOAD_REQUIRED "$@")"
|
||||
# no further processing because exec has been called!
|
||||
else
|
||||
echo "user <$USER> already belongs to group <lxd>!"
|
||||
fi
|
||||
|
||||
sudo /opt/debian-bash/tools/idem_apt_install lxd btrfs-progs
|
||||
|
||||
# test lxdbr0
|
||||
if ! lxc network info lxdbr0 &>/dev/null; then
|
||||
echo "bridge <lxdbr0> down, so initialization will use default preseed..."
|
||||
sudo lxd init
|
||||
# cat <<EOF | sudo lxd init --preseed
|
||||
|
||||
# NEW
|
||||
# networks:
|
||||
# - config:
|
||||
# ipv4.address: auto
|
||||
# ipv6.address: none
|
||||
# description: ""
|
||||
# name: lxdbr0
|
||||
# type: ""
|
||||
# project: default
|
||||
# storage_pools:
|
||||
# - config:
|
||||
# source: /dev/sda4
|
||||
# description: ""
|
||||
# name: default
|
||||
# driver: btrfs
|
||||
# profiles:
|
||||
# - config: {}
|
||||
# description: ""
|
||||
# devices:
|
||||
# eth0:
|
||||
# name: eth0
|
||||
# network: lxdbr0
|
||||
# type: nic
|
||||
# root:
|
||||
# path: /
|
||||
# pool: default
|
||||
# type: disk
|
||||
# name: default
|
||||
# projects: []
|
||||
# cluster: null
|
||||
|
||||
# OLD
|
||||
# networks:
|
||||
# - config:
|
||||
# ipv4.address: auto
|
||||
# ipv6.address: none
|
||||
# description: ""
|
||||
# name: lxdbr0
|
||||
# type: ""
|
||||
# project: default
|
||||
# storage_pools:
|
||||
# - config:
|
||||
# source: /dev/sda4
|
||||
# description: ""
|
||||
# name: default
|
||||
# driver: btrfs
|
||||
# profiles:
|
||||
# - config: {}
|
||||
# description: ""
|
||||
# devices:
|
||||
# eth0:
|
||||
# name: eth0
|
||||
# network: lxdbr0
|
||||
# type: nic
|
||||
# root:
|
||||
# path: /
|
||||
# pool: default
|
||||
# type: disk
|
||||
# name: default
|
||||
# projects: []
|
||||
# cluster: null
|
||||
|
||||
echo OK
|
||||
else
|
||||
echo "bridge <lxdbr0> found implies it has been already initialized!"
|
||||
fi
|
||||
|
||||
set_alias 'sameuser' "exec @ARG1@ -- su --whitelist-environment container_hostname - $(whoami)"
|
||||
set_alias 'login' 'exec @ARGS@ --mode interactive -- /bin/bash -c $@${user:-root} - exec su --whitelist-environment container_hostname - '
|
||||
set_alias 'll' 'list -c ns4mDN'
|
||||
|
||||
# test environment container hostname
|
||||
local env_container_hostname=$(lxc profile get default environment.container_hostname)
|
||||
if [[ -z "$env_container_hostname" ]]; then
|
||||
env_container_hostname=$(hostname -s)
|
||||
if env | grep -q container_hostname; then
|
||||
local previous_container_hostname=$(env | grep container_hostname | cut -d '=' -f2)
|
||||
env_container_hostname="$previous_container_hostname $env_container_hostname"
|
||||
fi
|
||||
|
||||
echo -n "set environment container_hostname to <$env_container_hostname> ... "
|
||||
lxc profile set default environment.container_hostname "$env_container_hostname"
|
||||
PREFIX="" echoinfo OK
|
||||
else
|
||||
echo "environment container_hostname <$env_container_hostname> already defined!"
|
||||
fi
|
||||
|
||||
if ! grep -q "root:$(id -u):1" /etc/subuid; then
|
||||
echo -n "subuid, subgid allowing <$(whoami)> ..."
|
||||
printf "root:$(id -u):1\n" | sudo tee -a /etc/subuid /etc/subgid
|
||||
PREFIX="" echoinfo DONE
|
||||
|
||||
# root:1000:1
|
||||
# root:100000:65536
|
||||
# _lxd:100000:65536
|
||||
# <USER>:100000:65536
|
||||
|
||||
else
|
||||
echo "subuid, subgid allowing <$(whoami)> already done!"
|
||||
fi
|
||||
|
||||
if [[ ! -d "$HOME/LXD/SHARED" ]]; then
|
||||
echo -n "$HOME/LXD/SHARED creating ... "
|
||||
mkdir "$HOME/LXD/SHARED" -p
|
||||
PREFIX="" echoinfo DONE
|
||||
else
|
||||
echo "folder <$HOME/LXD/SHARED> already created!"
|
||||
fi
|
||||
|
||||
if [[ ! -d "$HOME/LXD/BACKUP" ]]; then
|
||||
echo -n "$HOME/LXD/SHARED creating ... "
|
||||
mkdir "$HOME/LXD/SHARED" -p
|
||||
PREFIX="" echoinfo DONE
|
||||
else
|
||||
echo "folder <$HOME/LXD/BACKUP> already created!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function set_alias {
|
||||
local name="$1"
|
||||
local command="$2"
|
||||
if ! lxc alias list -f csv | grep -q "^$name,"; then
|
||||
echo -n "define lxc alias $name ..."
|
||||
lxc alias add "$name" "$command"
|
||||
PREFIX="" echoinfo OK
|
||||
else
|
||||
echo "lxc alias "$name" already defined!"
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
function miaou_evalfrombashrc() {
|
||||
local PREFIX="miaou:bashrc"
|
||||
output=$(
|
||||
/opt/debian-bash/tools/append_or_replace \
|
||||
"^eval \"\\$\($MIAOU_BASEDIR/lib/install.sh shellenv\)\"$" \
|
||||
"eval \"\$($MIAOU_BASEDIR/lib/install.sh shellenv)\"" \
|
||||
"$HOME/.bashrc"
|
||||
)
|
||||
|
||||
if [[ "$output" == "appended" ]]; then
|
||||
echo "new path <$MIAOU_BASEDIR> created!"
|
||||
SESSION_RELOAD_REQUIRED=true
|
||||
else
|
||||
echo "path <$MIAOU_BASEDIR> already loaded!"
|
||||
fi
|
||||
}
|
||||
|
||||
function ask_target() {
|
||||
PS3='Choose miaou target purpose: '
|
||||
foods=("Dev" "Beta" "Prod")
|
||||
select ans in "${foods[@]}"; do
|
||||
builtin echo "${ans^^}"
|
||||
break
|
||||
done
|
||||
}
|
||||
|
||||
function check_credential {
|
||||
local PREFIX="check:credential"
|
||||
|
||||
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.username' &&
|
||||
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.shadow' &&
|
||||
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.email' &&
|
||||
check_yaml_defined_value /etc/miaou/defaults.yaml 'credential.password'
|
||||
|
||||
}
|
||||
|
||||
function check_target() {
|
||||
case "${TARGET^^}" in
|
||||
DEV) ;;
|
||||
BETA) ;;
|
||||
PROD) ;;
|
||||
*)
|
||||
if [[ -f /etc/miaou/defaults.yaml ]]; then
|
||||
# load already defined target in expanded conf
|
||||
TARGET=$(grep -Es "^target:" /etc/miaou/defaults.yaml | cut -d ' ' -f2)
|
||||
else
|
||||
TARGET=$(ask_target)
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
TARGET=${TARGET,,} # downcase
|
||||
return 0
|
||||
}
|
||||
|
||||
function miaou_configfiles() {
|
||||
local PREFIX="miaou:config"
|
||||
|
||||
if [[ ! -d /etc/miaou ]]; then
|
||||
echo -n "configuration initializing ..."
|
||||
sudo mkdir -p /etc/miaou
|
||||
sudo chown "$USER" /etc/miaou
|
||||
PREFIX="" echoinfo OK
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/miaou/defaults.yaml ]]; then
|
||||
echo -n "building /etc/miaou/defaults.yaml for the first time..."
|
||||
shadow_passwd=$(sudo grep "$CURRENT_USER" /etc/shadow | cut -d ':' -f2)
|
||||
env current_user="$CURRENT_USER" shadow_passwd="$shadow_passwd" tera -e --env-key env --env-only -t "$MIAOU_BASEDIR/templates/etc/defaults.yaml.j2" -o /etc/miaou/defaults.yaml >/dev/null
|
||||
yq ".target=\"$TARGET\"" /etc/miaou/defaults.yaml -i
|
||||
PREFIX="" echoinfo OK
|
||||
fi
|
||||
|
||||
if [[ ! -f /etc/miaou/miaou.yaml ]]; then
|
||||
echo -n "building /etc/miaou/miaou.yaml for the first time..."
|
||||
cp "$MIAOU_BASEDIR/templates/etc/miaou.yaml.j2" /etc/miaou/miaou.yaml
|
||||
PREFIX="" echoinfo OK
|
||||
fi
|
||||
|
||||
PREVIOUS_TARGET=""
|
||||
echo "expanded configuration stored in <$MIAOU_CONFIGDIR>!"
|
||||
[[ -f "$EXPANDED_CONF" ]] && PREVIOUS_TARGET=$(grep -Es "^target:" "$EXPANDED_CONF" | cut -d ' ' -f2)
|
||||
|
||||
if [[ "$PREVIOUS_TARGET" != "$TARGET" ]]; then
|
||||
if [[ -z "$PREVIOUS_TARGET" ]]; then
|
||||
echo "new target defined <$TARGET>"
|
||||
else
|
||||
echowarnn "TARGET has changed from <$PREVIOUS_TARGET> to <$TARGET>, do you agree?"
|
||||
if askConfirmation N; then
|
||||
echowarn "removing previous settings, please restart <miaou> to apply changes"
|
||||
rm "$MIAOU_CONFIGDIR" -rf
|
||||
else
|
||||
echoerr "TARGET not accepted, exit"
|
||||
exit 102
|
||||
fi
|
||||
fi
|
||||
yq ".target=\"$TARGET\"" /etc/miaou/defaults.yaml -i
|
||||
else
|
||||
echo "target <$TARGET> already defined!"
|
||||
fi
|
||||
}
|
||||
|
||||
function opt_link() {
|
||||
if [[ $MIAOU_BASEDIR != '/opt/miaou' ]]; then
|
||||
if [[ -L '/opt/miaou' && -d '/opt/miaou' && $(readlink /opt/miaou) == "$MIAOU_BASEDIR" ]]; then
|
||||
echo "symbolic link /opt/miaou already set up!"
|
||||
else
|
||||
sudo rm -f /opt/miaou
|
||||
sudo ln -s "$MIAOU_BASEDIR" /opt/miaou
|
||||
echo "symbolic link /opt/miaou successfully defined!"
|
||||
fi
|
||||
else
|
||||
echo "real path /opt/miaou already set up!"
|
||||
fi
|
||||
}
|
||||
|
||||
function miaou_resolver() {
|
||||
local PREFIX="miaou:resolver"
|
||||
bridge=$(ip addr show lxdbr0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)
|
||||
gateway=$(ip route | grep default | cut -d' ' -f3)
|
||||
|
||||
if command -v nmcli &>/dev/null; then
|
||||
if [[ ! -f /etc/NetworkManager/dispatcher.d/50-miaou-resolver ]]; then
|
||||
echo -n "use NetworkManager dispatcher to deal with LXD bridge automatically..."
|
||||
sudo cp "$MIAOU_BASEDIR/templates/network-manager/50-miaou-resolver" /etc/NetworkManager/dispatcher.d/
|
||||
sudo chmod +x /etc/NetworkManager/dispatcher.d/50-miaou-resolver
|
||||
ACTIVE_CONNECTION=$(nmcli -g NAME connection show --active | head -n1)
|
||||
nmcli connection up "$ACTIVE_CONNECTION" &>/dev/null
|
||||
PREFIX="" echoinfo OK
|
||||
else
|
||||
echo "miaou-resolver in NetworkManager dispatcher already initialized!"
|
||||
fi
|
||||
else
|
||||
if ! grep -q "nameserver $bridge" /etc/resolv.conf; then
|
||||
echo "customize resolv.conf from scratch (SERVER)..."
|
||||
sudo tee /etc/resolv.conf &>/dev/null <<EOF
|
||||
nameserver $bridge
|
||||
nameserver $gateway
|
||||
EOF
|
||||
PREFIX="" echoinfo OK
|
||||
else
|
||||
echo "customize resolv.conf already already defined!"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function extra_dev_desktop {
|
||||
# detect if DEV
|
||||
# detect if DESKTOP
|
||||
:
|
||||
}
|
||||
|
||||
function override_lxd_service_to_reload_nftables {
|
||||
local PREFIX="lxd:override"
|
||||
|
||||
if [[ ! -d /etc/systemd/system/lxd.service.d ]]; then
|
||||
echo -n "override lxd service..."
|
||||
sudo mkdir -p /etc/systemd/system/lxd.service.d
|
||||
cat <<EOF | sudo tee /etc/systemd/system/lxd.service.d/override.conf
|
||||
[Service]
|
||||
ExecStartPost=systemctl reload nftables.service
|
||||
EOF
|
||||
sudo systemctl daemon-reload
|
||||
PREFIX="" echo "OK"
|
||||
else
|
||||
echo "lxd service already overridden!"
|
||||
fi
|
||||
}
|
||||
|
||||
function ask_for_credential {
|
||||
local PREFIX="ask:credential"
|
||||
if ! check_credential 2>/dev/null; then
|
||||
echo "further details required, please replace any <TO BE DEFINED> by a proper value ...press any key to open editor"
|
||||
read -rn1
|
||||
editor /etc/miaou/defaults.yaml
|
||||
fi
|
||||
check_credential
|
||||
echo "successfully checked!"
|
||||
}
|
||||
|
||||
### MAIN
|
||||
|
||||
if [[ "${1:-}" == "SESSION_RELOAD_REQUIRED" ]]; then
|
||||
SESSION_RELOAD_REQUIRED=true
|
||||
shift
|
||||
else
|
||||
SESSION_RELOAD_REQUIRED=false
|
||||
fi
|
||||
|
||||
if [[ "${1:-}" == "shellenv" ]]; then
|
||||
unset PREFIX
|
||||
echo "export MIAOU_BASEDIR=$MIAOU_BASEDIR"
|
||||
echo "export PATH=\"\$MIAOU_BASEDIR/scripts\":\$PATH"
|
||||
else
|
||||
|
||||
. "$MIAOU_BASEDIR/lib/init.sh"
|
||||
|
||||
trap 'status=$?; on_exit; exit $status' EXIT
|
||||
trap 'trap - HUP; on_exit SIGHUP; kill -HUP $$' HUP
|
||||
trap 'trap - INT; on_exit SIGINT; kill -INT $$' INT
|
||||
trap 'trap - TERM; on_exit SIGTERM; kill -TERM $$' TERM
|
||||
|
||||
PREFIX="miaou"
|
||||
: $PREFIX
|
||||
TARGET=${1:-}
|
||||
CURRENT_USER=$(id -un)
|
||||
|
||||
check_target
|
||||
sudo_required
|
||||
install_debian_bash
|
||||
install_mandatory_commands
|
||||
prepare_toolbox
|
||||
add_toolbox_sudoers
|
||||
prepare_nftables
|
||||
prepare_lxd "$@"
|
||||
override_lxd_service_to_reload_nftables
|
||||
miaou_resolver
|
||||
miaou_evalfrombashrc
|
||||
miaou_configfiles
|
||||
ask_for_credential
|
||||
prepare_nftables
|
||||
opt_link
|
||||
extra_dev_desktop
|
||||
|
||||
if [[ "$SESSION_RELOAD_REQUIRED" == false ]]; then
|
||||
echoinfo "successful installation"
|
||||
else
|
||||
echowarn "please reload your session, .bashrc needs to be reloaded!"
|
||||
fi
|
||||
fi
|
||||
Reference in New Issue
Block a user