diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3fe1b2d --- /dev/null +++ b/.gitignore @@ -0,0 +1,9 @@ + +# user configurations +*.env +!example.env + +# generated files +combustion/config +files/etc/ssh/sshd_config.d/sshd_server.conf +files/*.pub diff --git a/combustion/modules/install b/combustion/modules/install new file mode 100755 index 0000000..2b37205 --- /dev/null +++ b/combustion/modules/install @@ -0,0 +1,10 @@ +#!/usr/bin/env sh + +echo " ... installing packages" + +if [ -z "$combustion_install_packages" ]; then + exit 0 +fi + +# no-op for now +# todo detect package manager and install packages \ No newline at end of file diff --git a/combustion/modules/install_zypper b/combustion/modules/install_zypper new file mode 100755 index 0000000..38b17fa --- /dev/null +++ b/combustion/modules/install_zypper @@ -0,0 +1,7 @@ +#!/usr/bin/env sh + +echo " ... zypper install" + +# todo: possibly check for package managers? + +zypper install -y --auto-agree-with-product-licenses $combustion_install_packages diff --git a/combustion/modules/upgrade b/combustion/modules/upgrade new file mode 100755 index 0000000..8c982f7 --- /dev/null +++ b/combustion/modules/upgrade @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +# no-op +# todo: detect package manager and run that \ No newline at end of file diff --git a/combustion/modules/upgrade_zypper b/combustion/modules/upgrade_zypper new file mode 100755 index 0000000..b4bf82c --- /dev/null +++ b/combustion/modules/upgrade_zypper @@ -0,0 +1,4 @@ +#!/usr/bin/env sh + +echo " ... dist upgrade" +zypper --no-cd dup -y --auto-agree-with-product-licenses \ No newline at end of file diff --git a/combustion/script b/combustion/script new file mode 100755 index 0000000..5659c89 --- /dev/null +++ b/combustion/script @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# combustion: network + +if [ -z "$TTY" ]; then + TTY=/dev/tty0 + echo "TTY was not set, use $TTY" >> "$TTY" +fi + +echo "Combusting..." >> "$TTY" + +if ! [ -f config ]; then + echo "[combustion] script: missing config file" >> "$TTY" + exit 1 +fi + +#set -a # automatically export all variables +source config +#set +a + +## Mount /var and /home so user can be created smoothly +# (already mounted via igniton) +#mount /var +#mount /home + +for module in $modules; do + echo "[combustion] Running module $module ..." >> "$TTY" + "./modules/$module" >> "$TTY" + echo "[combustion] Module $module done." >> "$TTY" +done + +## Clear up mounts +#umount /var +#umount /home + +echo "Combustion done" >> "$TTY" diff --git a/example.env b/example.env new file mode 100644 index 0000000..b7c749e --- /dev/null +++ b/example.env @@ -0,0 +1,11 @@ +ign_hostname= +ign_user= +# hash, created with e.g. `mkpasswd --method=yescrypt` from the whois package or `openssl passwd -6` +ign_password_hash='' +ign_ssh_public_key_location= +ign_sshd_port= + +combustion_script_modules="" +combustion_install_packages="" + +combustion_ntfy_topic= \ No newline at end of file diff --git a/files/etc/ssh/sshd_config.d/port_forwarding.conf b/files/etc/ssh/sshd_config.d/port_forwarding.conf new file mode 100644 index 0000000..291fc8e --- /dev/null +++ b/files/etc/ssh/sshd_config.d/port_forwarding.conf @@ -0,0 +1,9 @@ +AllowStreamLocalForwarding yes +AllowTcpForwarding yes +PermitTunnel yes +MaxSessions 64 + +PrintLastLog yes + +StreamLocalBindUnlink yes +GatewayPorts yes \ No newline at end of file diff --git a/files/etc/ssh/sshd_config.d/security.conf b/files/etc/ssh/sshd_config.d/security.conf new file mode 100644 index 0000000..1dec4aa --- /dev/null +++ b/files/etc/ssh/sshd_config.d/security.conf @@ -0,0 +1,14 @@ +# Check if the file modes and ownership of the user’s files and +# home directory are correct before allowing them to login +StrictModes yes + +# Disable password authentication and allow only public key authentication +# for all users +PasswordAuthentication no +PermitRootLogin no + +# Length of time the server waits for a user to log in and complete the +# connection. The default is 120 seconds: +LoginGraceTime 60 +# Limit the number of failed connection attempts. The default is 6 +MaxAuthTries 4 diff --git a/files/firstbootreboot.service b/files/firstbootreboot.service new file mode 100644 index 0000000..3cbf046 --- /dev/null +++ b/files/firstbootreboot.service @@ -0,0 +1,11 @@ +[Unit] +Description=First Boot Reboot + +[Service] +Type=oneshot +ExecStart=rm /etc/systemd/system/firstbootreboot.service +ExecStart=rm /etc/systemd/system/default.target.wants/firstbootreboot.service +ExecStart=systemctl reboot + +[Install] +WantedBy=default.target diff --git a/generate-ignition.sh b/generate-ignition.sh new file mode 100755 index 0000000..d40547a --- /dev/null +++ b/generate-ignition.sh @@ -0,0 +1,66 @@ +#!/usr/bin/env sh + +# determine butane binary +if [ -z "$ign_butane_bin" ]; then + if command -v butane &> /dev/null; then + ign_butane_bin=$(command -v butane) + elif command -v podman &> /dev/null; then + ign_butane_bin="podman run -i --rm --volume ${PWD}:/pwd --workdir /pwd --security-opt label=disable quay.io/coreos/butane:release" + elif command -v docker &> /dev/null; then + ign_butane_bin="docker run -i --rm --volume ${PWD}:/pwd --workdir /pwd --security-opt label=disable quay.io/coreos/butane:release" + else + echo "ign_butane_bin is not set and could not find a butane or podman/docker binary." + exit 1 + fi +fi + +if ! command -v envsubst &> /dev/null; then + echo "envsubst from the gettext package required for env substitute is missing. Aborting..." + exit 1 +fi + +# go through required env vars and ask for value if not set +if [ -z "${ign_hostname}" ]; then + read -p "ign_hostname is not set. Set value: " ign_hostname + export ign_hostname +fi + +if [ -z "${ign_user}" ]; then + read -p "ign_user is not set. Set value: " ign_user + export ign_user +fi + +if [ -z "$ign_password_hash" ]; then + echo "No password hash set in ign_password_hash - generating a new one?" + if command -v mkpasswd &> /dev/null; then + export ign_password_hash=$(mkpasswd --method=yescrypt) + elif command -v openssl &> /dev/null; then + export ign_password_hash=$(openssl passwd -6) + else + echo "Neither mkpasswd nor openssl found for generating a password. Exiting." + exit 1 + fi +fi + +if [ -z "$ign_ssh_public_key" ]; then + if [ -z "${ign_ssh_public_key_location}" ]; then + read -p "ign_ssh_public_key_location is not set. Set value: " ign_ssh_public_key_location + fi + export ign_ssh_public_key=$(cat "$ign_ssh_public_key_location") +fi + + +printf "\n---------\nUsing the following configuration:\n\n" +env | grep ign_ +printf "\n---------\n" +read -p "Continue with this configuration? [Y/n] " confirmation +case $confirmation in + Y|y|'') echo ;; + *) echo "Aborted..." ; exit 0 ;; +esac + +envsubst files/etc/ssh/sshd_config.d/sshd_server.conf + +# substitute these variables via sed and feed it into butane +envsubst ignition/config.ign diff --git a/ignition/.gitignore b/ignition/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/ignition/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/templates/combustion.conf b/templates/combustion.conf new file mode 100644 index 0000000..326bce7 --- /dev/null +++ b/templates/combustion.conf @@ -0,0 +1,4 @@ +combustion_script_modules="$combustion_script_modules" +combustion_install_packages="$combustion_install_packages" + +NTFY_TOPIC="$compustion_ntfy_topic" \ No newline at end of file diff --git a/templates/ignition.yaml b/templates/ignition.yaml new file mode 100644 index 0000000..a33a79d --- /dev/null +++ b/templates/ignition.yaml @@ -0,0 +1,43 @@ +variant: fcos +version: 1.5.0 + +storage: + filesystems: + - path: /home + device: /dev/disk/by-label/ROOT + format: btrfs + wipe_filesystem: false + mount_options: + - "subvol=/@/home" + # var is mounted by default: https://en.opensuse.org/Portal:MicroOS/Ignition#Mounts + trees: + - local: etc + path: /etc + files: + - path: /etc/hostname + mode: 0644 + overwrite: true + contents: + inline: "$ign_hostname" + - path: /etc/sudoers.d/$ign_user + mode: 0644 + overwrite: true + contents: + inline: "$ign_user ALL=(ALL) ALL" # NOPASSWD: ALL + +systemd: + units: + - name: firstbootreboot.service + enabled: true + contents_local: firstbootreboot.service + +passwd: + users: + - name: $ign_user + # hash, created with e.g. `openssl passwd -6` or `mkpasswd --method=yescrypt` from the whois package + password_hash: "$ign_password_hash" + ssh_authorized_keys: + - "$ign_ssh_public_key" + # ssh_authorized_keys_local: + # - $ign_ssh_public_key_location + diff --git a/templates/sshd_server.conf b/templates/sshd_server.conf new file mode 100644 index 0000000..4e56e28 --- /dev/null +++ b/templates/sshd_server.conf @@ -0,0 +1,5 @@ +# alternative port than the default 22, to avoid most scrape attempts +Port $ign_sshd_port + +# allow only the following users to login +AllowUsers $ign_user