non-interactive --yes: ask() assumes prompt default (no read); timezone defaults UTC; --username implies force-create; create-user name defaults to mk under --yes
This commit is contained in:
parent
34137d185e
commit
8930e7aa76
@ -2,9 +2,15 @@
|
|||||||
# prompt.sh — plain y/N prompts.
|
# prompt.sh — plain y/N prompts.
|
||||||
|
|
||||||
# ask "prompt?" [default y|n] -> sets REPLY
|
# ask "prompt?" [default y|n] -> sets REPLY
|
||||||
|
# Under ${ALL:-0} (the --yes flag) assume the stated default without
|
||||||
|
# reading stdin, so a fully non-interactive run never blocks on a read.
|
||||||
ask() {
|
ask() {
|
||||||
local p="$1" d="${2:-y}" hint
|
local p="$1" d="${2:-y}" hint
|
||||||
if [[ "$d" == "y" ]]; then hint="[Y/n]"; else hint="[y/N]"; fi
|
if [[ "$d" == "y" ]]; then hint="[Y/n]"; else hint="[y/N]"; fi
|
||||||
|
if (( ${ALL:-0} )); then
|
||||||
|
REPLY="$d"
|
||||||
|
return
|
||||||
|
fi
|
||||||
read -rp "$p $hint " REPLY
|
read -rp "$p $hint " REPLY
|
||||||
[[ -z "$REPLY" ]] && REPLY="$d"
|
[[ -z "$REPLY" ]] && REPLY="$d"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,6 +14,7 @@
|
|||||||
# - Root + no SUDO_USER + Debian/Ubuntu -> ask y/N (optional, apt works as root).
|
# - Root + no SUDO_USER + Debian/Ubuntu -> ask y/N (optional, apt works as root).
|
||||||
# - --create-user flag -> force prompt regardless.
|
# - --create-user flag -> force prompt regardless.
|
||||||
# - --username NAME -> override default name, no prompt.
|
# - --username NAME -> override default name, no prompt.
|
||||||
|
# - --yes (no --username) -> default to 'mk' silently (no stall).
|
||||||
#
|
#
|
||||||
# Passwordless, no user password (NOPASSWD). Idempotent: re-runs re-sync
|
# Passwordless, no user password (NOPASSWD). Idempotent: re-runs re-sync
|
||||||
# authorized_keys + sudoers rather than failing.
|
# authorized_keys + sudoers rather than failing.
|
||||||
@ -40,7 +41,8 @@ run_create_user() {
|
|||||||
_handle_direct_root() {
|
_handle_direct_root() {
|
||||||
local should_create=0
|
local should_create=0
|
||||||
|
|
||||||
if (( CREATE_USER )); then
|
if (( CREATE_USER )) || [[ -n "${USERNAME_ARG:-}" ]]; then
|
||||||
|
[[ -n "${USERNAME_ARG:-}" ]] && log "--username given: forcing user creation"
|
||||||
should_create=1
|
should_create=1
|
||||||
elif [[ "$DISTRO" == "arch" ]]; then
|
elif [[ "$DISTRO" == "arch" ]]; then
|
||||||
# AUR/makepkg cannot run as root — we genuinely need a non-root sudoer.
|
# AUR/makepkg cannot run as root — we genuinely need a non-root sudoer.
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
# 50-hardening — system defaults. Each sub-step y/N, all idempotent.
|
# 50-hardening — system defaults. Each sub-step y/N, all idempotent.
|
||||||
|
|
||||||
step_name="hardening"
|
step_name="hardening"
|
||||||
step_desc="ssh, ufw, updates, unattended, tz, hostname, swap, locale, fail2ban, angie config"
|
step_desc="ssh, ufw, updates, unattended, tz, hostname, swap, locale, fail2ban, angie config + built-in ACME"
|
||||||
step_run="run_hardening"
|
step_run="run_hardening"
|
||||||
|
|
||||||
run_hardening() {
|
run_hardening() {
|
||||||
@ -15,6 +15,7 @@ run_hardening() {
|
|||||||
_h_locale
|
_h_locale
|
||||||
_h_fail2ban
|
_h_fail2ban
|
||||||
_h_angie_config
|
_h_angie_config
|
||||||
|
_h_angie_acme
|
||||||
ok "hardening pass complete"
|
ok "hardening pass complete"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,8 +105,12 @@ _h_tz_hostname() {
|
|||||||
if command -v timedatectl >/dev/null 2>&1; then
|
if command -v timedatectl >/dev/null 2>&1; then
|
||||||
if yn "Set timezone (default UTC)?" y; then
|
if yn "Set timezone (default UTC)?" y; then
|
||||||
local tz="${REPLY_TZ:-}"
|
local tz="${REPLY_TZ:-}"
|
||||||
read -rp " timezone [UTC]: " tz
|
if (( ${ALL:-0} )); then
|
||||||
[[ -z "$tz" ]] && tz="UTC"
|
tz="UTC"; ok "--yes: timezone defaulting to UTC"
|
||||||
|
else
|
||||||
|
read -rp " timezone [UTC]: " tz
|
||||||
|
[[ -z "$tz" ]] && tz="UTC"
|
||||||
|
fi
|
||||||
sudo_ timedatectl set-timezone "$tz" && ok "timezone set to $tz"
|
sudo_ timedatectl set-timezone "$tz" && ok "timezone set to $tz"
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
@ -368,3 +373,85 @@ fi
|
|||||||
EOF
|
EOF
|
||||||
sudo_ chmod +x /usr/local/bin/angie-enable /usr/local/bin/angie-disable
|
sudo_ chmod +x /usr/local/bin/angie-enable /usr/local/bin/angie-disable
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── angie built-in ACME (Let's Encrypt) ────────────────────────────────────
|
||||||
|
# No certbot: Angie ships http_acme and fetches/renews certs itself.
|
||||||
|
# Bootstrap can't know your domain/email, so we ship an example TLS server
|
||||||
|
# target + an `angie-issue` helper that creates the live acme_client on demand.
|
||||||
|
_h_angie_acme() {
|
||||||
|
if ! command -v angie >/dev/null 2>&1; then
|
||||||
|
echo " skip angie ACME (angie not installed)"; return
|
||||||
|
fi
|
||||||
|
if ! yn "Ship Angie built-in ACME template + angie-issue helper?" y; then
|
||||||
|
echo " skip angie ACME"; return
|
||||||
|
fi
|
||||||
|
|
||||||
|
local d=/etc/angie
|
||||||
|
# example TLS server target — NOT auto-enabled (.example, so angie-enable won't glob it)
|
||||||
|
if [[ ! -f "$d/targets/example-https.conf.example" ]]; then
|
||||||
|
sudo_ tee "$d/targets/example-https.conf.example" >/dev/null <<'EOF'
|
||||||
|
# Template for a TLS host using Angie built-in ACME.
|
||||||
|
# Use it via the helper: angie-issue <domain> [you@email]
|
||||||
|
# Or by hand: copy to targets/<domain>.conf, fill <DOMAIN>, then: angie-enable <domain>
|
||||||
|
server {
|
||||||
|
listen 80;
|
||||||
|
listen [::]:80;
|
||||||
|
listen 443 ssl;
|
||||||
|
listen [::]:443 ssl;
|
||||||
|
http2 on;
|
||||||
|
server_name <DOMAIN>;
|
||||||
|
|
||||||
|
acme default; # add this server_name to the shared 'default' ACME certificate
|
||||||
|
ssl_certificate $acme_cert_default;
|
||||||
|
ssl_certificate_key $acme_cert_key_default;
|
||||||
|
|
||||||
|
# http -> https redirect
|
||||||
|
if ($scheme = http) { return 301 https://$host$request_uri; }
|
||||||
|
|
||||||
|
location / {
|
||||||
|
# replace with your app / proxy_pass upstream;
|
||||||
|
return 200 "angie + builtin ACME ok\n";
|
||||||
|
add_header Content-Type text/plain;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo_ tee /usr/local/bin/angie-issue >/dev/null <<'EOF'
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# angie-issue <domain> [email] — create a TLS host backed by Angie built-in ACME.
|
||||||
|
# First call (needs email) writes /etc/angie/modules/http/acme.conf with the
|
||||||
|
# shared 'default' acme_client; every call writes targets/<domain>.conf and enables it.
|
||||||
|
# All enabled domains using `acme default` share one cert covering all their server_names.
|
||||||
|
set -euo pipefail
|
||||||
|
domain="${1:-}"; email="${2:-}"
|
||||||
|
[ -n "$domain" ] || { echo "usage: angie-issue <domain> [email]" >&2; exit 2; }
|
||||||
|
acme_conf=/etc/angie/modules/http/acme.conf
|
||||||
|
|
||||||
|
if [ ! -f "$acme_conf" ]; then
|
||||||
|
[ -n "$email" ] || { echo "first-time: also pass your email for Let's Encrypt" >&2; exit 2; }
|
||||||
|
cat > "$acme_conf" <<ACME
|
||||||
|
# managed by angie-issue — Angie built-in ACME (Let's Encrypt)
|
||||||
|
# resolver is required by the acme_client directive (http context).
|
||||||
|
resolver 1.1.1.1 8.8.8.8 valid=300s ipv6=off;
|
||||||
|
acme_client default https://acme-v02.api.letsencrypt.org/directory email=${email};
|
||||||
|
ACME
|
||||||
|
echo "wrote $acme_conf (email=${email})"
|
||||||
|
else
|
||||||
|
echo "_existing $acme_conf (shared default client)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
target=/etc/angie/targets/${domain}.conf
|
||||||
|
sed -e "s|<DOMAIN>|${domain}|g" /etc/angie/targets/example-https.conf.example > "$target"
|
||||||
|
echo "wrote $target"
|
||||||
|
ln -sfn "../targets/${domain}.conf" /etc/angie/_on/${domain}.conf
|
||||||
|
echo "enabled: $domain"
|
||||||
|
sudo angie -t
|
||||||
|
sudo systemctl reload angie && echo "angie reloaded — certificate is obtained automatically."
|
||||||
|
EOF
|
||||||
|
sudo_ chmod +x /usr/local/bin/angie-issue
|
||||||
|
|
||||||
|
ok "angie ACME ready: example host at $d/targets/example-https.conf.example"
|
||||||
|
echo " issue a cert: angie-issue <domain> you@email"
|
||||||
|
echo " then reload picks it up; Angie renews automatically before expiry."
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user