#!/bin/bash
# Script para configurar VPN Tailscale en servidor Linux (derivado de RHEL)
# para Proyecto Nasa
# VERSION: 0.9.3
# AUTOR: SEKINFO SAS
# LICENCIA: Código es software libre licenciado bajo GPLv3.
# Se reservan todos los derechos para los datos de configuración (llaves SSH,
# parámetros de conexión Tailscale).
# Se permite el reuso y la republicación solo cuando se omiten o se sustituyen
# los datos de configuración. Los datos que se deben cambiar están en la
# sección nombrado "DATOS DE CONFIGURACIÓN".
set -euo pipefail

#===
# DATOS DE CONFIGURACIÓN
# Se debe cambiar antes de reusar o republicar este script.
IFS='' read -d '' -r LLAVES_SSH << 'EOF' || :
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBbxXYGI/ISUBGgqmcSJvtAyUC/1pdu05/ritCl5YIoe port-andres
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJQL5vWU/7eIb4gJ89boGHtgcz7RS0KFvHOhVTubhx/I ts-pn@ee
EOF

TAILSCALE_LOGIN_SERVER='https://vpn.proyectonasa.com'
# Nota: La preauthkey no otorga acceso al VPN automáticamente. Un administrador
# tiene que autorizar el acceso en el servidor Headscale. La cadena abajo
# representa una preauthkey encriptada con AES-256 con clave derivada con
# PBKDF2. El usuario debe suministrar la contraseña al momento de ejecutar este
# script.
TAILSCALE_PREAUTHKEY_ENCRYPTED='acTuRSYoUKm+cv4Y35SQlJN05gaKX01bMTJAcs+I7U6nM/XC4Bw7qALvxtJQ7zK9xBM7BIRMrjC/jHF1Jc8xiQ=='
ALG='aes-256-cbc'
ITER='200000'
SALT='1016682a7e5d5ed1'
# Se puede generar TAILSCALE_PREAUTHKEY_ENCRYPTED con otra preauthkey con el siguiente (sustiyendo los valores apropiados):
# TAILSCALE_PREAUTHKEY=""
# PASS=""
# TAILSCALE_PREAUTHKEY_ENCRYPTED=$(printf "%s" "$TAILSCALE_PREAUTHKEY" | openssl enc -"$ALG" -pbkdf2 -iter $ITER -salt -S $SALT -pass pass:"$PASS" -A -base64)
# echo $TAILSCALE_PREAUTHKEY_ENCRYPTED

TAILSCALE_HOSTNAME='linux-server'
#===

VERBOSE=0
CMD_OUT=/dev/null
# Modo verboso si la opción "-v" es usada
if [[ "${1:-}" == "-v" ]]; then
    VERBOSE=1
    CMD_OUT=/dev/stdout
fi

main() {
if [[ "$VERBOSE" -eq 1 ]]; then
    set -x
fi

# Configurar SSH
if ! systemctl is-enabled --quiet sshd; then
    systemctl enable --now sshd 2>&1 | grep -v 'Created symlink' || :
fi
mkdir -p /root/.ssh
chmod 700 /root/.ssh/
echo "$LLAVES_SSH" > /root/.ssh/authorized_keys
chmod 600 /root/.ssh/authorized_keys
restorecon -R -v /root/.ssh > "$CMD_OUT"

# Configurar cortafuegos nftables
if systemctl is-enabled --quiet firewalld; then
    systemctl disable --now firewalld > "$CMD_OUT" 2>&1 
fi
if ! systemctl is-enabled --quiet nftables; then
    systemctl enable --now nftables 2>&1 | grep -v 'Created symlink' || :
fi
# shellcheck disable=SC2016
sed -i 's$^#include "/etc/nftables/main.nft"$include "/etc/nftables/main.nft"$' /etc/sysconfig/nftables.conf

cat > /etc/sysconfig/nftables.conf << EOF
flush ruleset

table inet nftables_svc {
	set allowed_protocols {
		type inet_proto
		elements = { icmp, icmpv6 }
	}

	set allowed_interfaces {
		type ifname
		elements = { "lo" }
	}

	set allowed_tcp_dports {
		type inet_service
		elements = { ssh }
	}

	chain allow {
		ct state established,related accept
		meta l4proto @allowed_protocols accept
		iifname @allowed_interfaces accept
		tcp dport @allowed_tcp_dports accept
	}

	chain INPUT {
		type filter hook input priority filter + 20
		policy accept
		jump allow
		reject with icmpx type port-unreachable
	}
}
EOF
systemctl restart nftables

# Configurar VPN Tailscale
cat > /etc/default/tailscaled << EOF
TAILSCALE_NO_LOGS_NO_SUPPORT=true
PORT=41641
EOF
dnf config-manager --add-repo https://pkgs.tailscale.com/stable/rhel/9/tailscale.repo > "$CMD_OUT" 2>&1
dnf install tailscale -y > "$CMD_OUT" 2>&1
mkdir -p /etc/systemd/system/tailscaled.service.d/
cat > /etc/systemd/system/tailscaled.service.d/override.conf << 'EOF'
[Service]
ExecStart=
ExecStart=/usr/sbin/tailscaled --state=/var/lib/tailscale/tailscaled.state --socket=/run/tailscale/tailscaled.sock --port=${PORT} --no-logs-no-support $FLAGS
EOF
systemctl daemon-reload
if ! systemctl is-enabled --quiet tailscaled; then
    systemctl enable --now tailscaled 2>&1 | grep -v 'Created symlink' || :
else
    systemctl restart tailscaled
fi
tailscale up --login-server "$TAILSCALE_LOGIN_SERVER" --authkey "$TAILSCALE_PREAUTHKEY" --hostname "$TAILSCALE_HOSTNAME"
set +x
}

trap_handler() {
    trap - EXIT INT
    local signal=$1
    kill "$spinner_pid" 2>/dev/null
    if [[ $signal -eq 0 ]]; then
        printf "\r¡Se terminó la configuración del VPN con éxito!\n"
    elif [[ $signal -eq 130 ]]; then
        printf "\rEl programa fue interrumpido antes de terminar el proceso\n"
    else
        printf "\rEl programa encontró un error antes de terminar el proceso\n"
    fi
    exit "$signal"
}

spinner() {
    local spin="/-\\|"
    local i=0
    while : ; do
        printf "\rTrabajando... %c" "${spin:$i:1}"
        i=$(( (i+1) % 4 ))
        sleep 0.1
    done
}

# Desencriptar la preauthkey de Tailscale con la contraseña dada por el usuario
read -rp "Contraseña: " PASS
TAILSCALE_PREAUTHKEY=$(printf "%s" "$TAILSCALE_PREAUTHKEY_ENCRYPTED" | openssl enc -d -"$ALG" -pbkdf2 -iter $ITER -salt -S $SALT -pass pass:"$PASS" -A -base64)

if [[ "$VERBOSE" -eq 0 ]]; then
    ( spinner ) &
    spinner_pid=$!
    trap 'trap_handler $?' EXIT INT
fi

main
if [[ "$VERBOSE" -eq 0 ]]; then
  kill "$spinner_pid" 2>/dev/null
fi
