Add "remove a protected domain" to Authelia's existing-install menu
add_authelia_domain() (menu option 1) had no reverse operation -- once a domain was added there was no way to undo it short of hand-editing configuration.yml and the Caddyfile. remove_authelia_domain() (new option 2) does the reverse cleanly: removes the access_control.rules entry, the session.cookies entry, and the auth.<domain> Caddy portal block for one domain, verified against a synthetic multi-domain configuration.yml before shipping. Warns loudly that any service still pointed at the removed domain will stop authenticating, and requires confirmation before touching anything. The menu's own text now also flags the likely real mistake this surfaces: adding a domain that's actually just a SUBDOMAIN of an apex already on the instance creates a *.subdomain.apex wildcard rule that doesn't match the bare subdomain itself, plus a redundant separate auth.subdomain.apex portal -- when the subdomain was already covered by the existing apex's own wildcard rule and portal all along. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SpKTLpwAgZNooTacWeQLuc
This commit is contained in:
+135
-13
@@ -225,44 +225,50 @@ install_authelia() {
|
||||
echo ""
|
||||
echo " 1) Add another protected domain to this instance (non-destructive —"
|
||||
echo " one Authelia+Redis, multiple independent apex domains/logins)"
|
||||
echo " 2) Add a new user (creates a users.yml entry + password hash)"
|
||||
echo " 3) Manage an existing user (email, password reset, 2FA reset/exempt,"
|
||||
echo " 2) Remove a protected domain added this way (undoes option 1 for one"
|
||||
echo " domain — other services still pointed at it will stop authenticating)"
|
||||
echo " 3) Add a new user (creates a users.yml entry + password hash)"
|
||||
echo " 4) Manage an existing user (email, password reset, 2FA reset/exempt,"
|
||||
echo " promote/demote admin, per-service access, delete)"
|
||||
echo " 4) Register an app to log in VIA Authelia (OIDC/SSO — e.g. ActualBudget,"
|
||||
echo " 5) Register an app to log in VIA Authelia (OIDC/SSO — e.g. ActualBudget,"
|
||||
echo " Vaultwarden, or any other app with its own \"Enable OpenID\" setting)"
|
||||
echo " 5) Reconfigure from scratch (regenerates secrets/users — breaks"
|
||||
echo " 6) Reconfigure from scratch (regenerates secrets/users — breaks"
|
||||
echo " existing sessions for every domain already on this instance)"
|
||||
echo " 6) Show who has universal vs. service-scoped access"
|
||||
echo " 7) Change \"Remember me\" session duration (stay logged in longer)"
|
||||
echo " 8) Leave as-is"
|
||||
echo " 7) Show who has universal vs. service-scoped access"
|
||||
echo " 8) Change \"Remember me\" session duration (stay logged in longer)"
|
||||
echo " 9) Leave as-is"
|
||||
echo ""
|
||||
local EXISTING_CHOICE=""
|
||||
prompt_text " Choice [1/2/3/4/5/6/7/8]:" "8" EXISTING_CHOICE
|
||||
prompt_text " Choice [1/2/3/4/5/6/7/8/9]:" "9" EXISTING_CHOICE
|
||||
case "$EXISTING_CHOICE" in
|
||||
1)
|
||||
add_authelia_domain
|
||||
return 0
|
||||
;;
|
||||
2)
|
||||
add_authelia_user
|
||||
remove_authelia_domain
|
||||
return 0
|
||||
;;
|
||||
3)
|
||||
edit_authelia_user
|
||||
add_authelia_user
|
||||
return 0
|
||||
;;
|
||||
4)
|
||||
_authelia_add_oidc_client
|
||||
edit_authelia_user
|
||||
return 0
|
||||
;;
|
||||
5)
|
||||
: # fall through to the full reinstall flow below
|
||||
_authelia_add_oidc_client
|
||||
return 0
|
||||
;;
|
||||
6)
|
||||
: # fall through to the full reinstall flow below
|
||||
;;
|
||||
7)
|
||||
_authelia_report_access_scope
|
||||
return 0
|
||||
;;
|
||||
7)
|
||||
8)
|
||||
_authelia_set_remember_me
|
||||
return 0
|
||||
;;
|
||||
@@ -732,6 +738,122 @@ CADDY_AUTH_BLOCK2
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Removes the auth.<domain> Caddy portal block add_authelia_domain() writes —
|
||||
# same bounded-block technique used elsewhere in this repo for Caddy site
|
||||
# blocks (find the opening "<domain> {" line, walk forward to the matching
|
||||
# unindented "}"), just keyed on "auth.<domain> {" instead of a service
|
||||
# domain or a reverse_proxy marker.
|
||||
_authelia_remove_caddy_portal_block() {
|
||||
local domain="$1"
|
||||
local caddy_file="$DOCKER_DIR/caddy/Caddyfile"
|
||||
[ -f "$caddy_file" ] || return 0
|
||||
|
||||
local domain_line end_line start_line
|
||||
domain_line="$(grep -nx "auth.${domain} {" "$caddy_file" | head -1 | cut -d: -f1)"
|
||||
[ -z "$domain_line" ] && return 0
|
||||
|
||||
start_line="$domain_line"
|
||||
if [ "$domain_line" -gt 1 ] && sed -n "$((domain_line - 1))p" "$caddy_file" | grep -qE '^# '; then
|
||||
start_line=$((domain_line - 1))
|
||||
fi
|
||||
|
||||
end_line="$(tail -n "+$domain_line" "$caddy_file" | grep -nx '}' | head -1 | cut -d: -f1)"
|
||||
if [ -z "$end_line" ]; then
|
||||
log_warning "Could not find the end of auth.${domain}'s Caddy block — leaving it as-is."
|
||||
return 1
|
||||
fi
|
||||
end_line=$((domain_line + end_line - 1))
|
||||
|
||||
sed -i "${start_line},${end_line}d" "$caddy_file"
|
||||
log_info "Removed the auth.${domain} Caddy portal block."
|
||||
docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^caddy$" && \
|
||||
{ docker exec -w /etc/caddy caddy caddy reload 2>/dev/null && log_success "Caddy reloaded" \
|
||||
|| log_warning "Reload manually: docker exec caddy caddy reload --config /etc/caddy/Caddyfile"; }
|
||||
}
|
||||
|
||||
# Reverse of add_authelia_domain() — removes one apex domain's
|
||||
# access_control.rules entry, session.cookies entry, and its auth.<domain>
|
||||
# Caddy portal block from this instance. Undoes a domain added by mistake
|
||||
# (wrong value entered, or a domain that turned out to already be covered by
|
||||
# an existing apex's wildcard rule — see the menu's own warning text). Does
|
||||
# NOT touch any other domain already on this instance, and does NOT find or
|
||||
# fix whatever individual services still point "import authelia"/forward_auth
|
||||
# at this instance for the removed domain — those start failing to
|
||||
# authenticate (no session-cookie scope left to complete a login against)
|
||||
# the moment this runs, so this is for cleaning up a domain that's not
|
||||
# actually in use this way, not a way to quietly de-protect a live service.
|
||||
remove_authelia_domain() {
|
||||
local AUTHELIA_DIR="$DOCKER_DIR/authelia"
|
||||
local CONFIG_FILE="$AUTHELIA_DIR/config/configuration.yml"
|
||||
|
||||
if [ ! -f "$CONFIG_FILE" ]; then
|
||||
log_warning "No configuration.yml found at $CONFIG_FILE — install Authelia first."
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo " Domains currently on this Authelia instance:"
|
||||
grep -oE '^ - domain: "\*\.[^"]+"' "$CONFIG_FILE" | sed -E 's/^ - domain: "\*\.(.+)"$/ - \1/'
|
||||
echo ""
|
||||
echo " Note: this removes a whole apex domain entry added via 'Add another"
|
||||
echo " protected domain' — if you meant to protect a SUBDOMAIN of an apex"
|
||||
echo " already listed above, you don't need this at all: it's already covered"
|
||||
echo " by that apex's wildcard rule and session-cookie scope. Just point that"
|
||||
echo " subdomain's Caddy block at this instance's existing auth.<apex> portal"
|
||||
echo " instead of adding it here as its own entry."
|
||||
echo ""
|
||||
local RM_DOMAIN=""
|
||||
prompt_text " Domain to remove (as shown above, e.g. example.com):" "" RM_DOMAIN
|
||||
if [ -z "$RM_DOMAIN" ]; then
|
||||
log_warning "No domain entered — nothing to do."
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! grep -qF "\"*.${RM_DOMAIN}\"" "$CONFIG_FILE" 2>/dev/null; then
|
||||
log_warning "$RM_DOMAIN isn't configured on this instance — nothing to do."
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log_warning "This removes ${RM_DOMAIN}'s access rule, session-cookie scope, and its"
|
||||
log_warning "auth.${RM_DOMAIN} login portal from THIS Authelia instance."
|
||||
log_warning "Any service still using 'import authelia' or forward_auth pointed at"
|
||||
log_warning "${RM_DOMAIN} will start failing to authenticate — reconfigure or remove"
|
||||
log_warning "those first if they're still live."
|
||||
local CONFIRM_RM=""
|
||||
prompt_yn " Continue? (y/n):" "n" CONFIRM_RM
|
||||
[[ "$CONFIRM_RM" =~ ^[Yy]$ ]] || { log_info "Cancelled — nothing changed."; return 0; }
|
||||
|
||||
# ── access_control.rules: remove the "- domain: "*.X"" + "policy: ..." pair ──
|
||||
awk -v domain="$RM_DOMAIN" '
|
||||
BEGIN { skip=0 }
|
||||
skip == 1 { skip=0; next }
|
||||
$0 == " - domain: \"*." domain "\"" { skip=1; next }
|
||||
{ print }
|
||||
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
|
||||
|
||||
# ── session.cookies: remove the "- domain: X" + 2 following lines ─────────
|
||||
awk -v domain="$RM_DOMAIN" '
|
||||
BEGIN { skip=0 }
|
||||
skip > 0 { skip--; next }
|
||||
$0 == " - domain: " domain { skip=2; next }
|
||||
{ print }
|
||||
' "$CONFIG_FILE" > "$CONFIG_FILE.tmp" && mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
|
||||
|
||||
chown 1000:1000 "$CONFIG_FILE" 2>/dev/null || true
|
||||
log_success "Removed ${RM_DOMAIN} from $CONFIG_FILE"
|
||||
|
||||
_authelia_remove_caddy_portal_block "$RM_DOMAIN"
|
||||
|
||||
local RESTART_AUTH=""
|
||||
prompt_yn " Restart Authelia to apply? (y/n):" "y" RESTART_AUTH
|
||||
if [ "$RESTART_AUTH" = "y" ] || [ "$RESTART_AUTH" = "Y" ]; then
|
||||
(cd "$AUTHELIA_DIR" && docker compose restart authelia 2>/dev/null) \
|
||||
&& log_success "Authelia restarted" \
|
||||
|| log_warning "Restart failed — check: docker compose logs authelia"
|
||||
fi
|
||||
}
|
||||
|
||||
# Picks "count" random characters from "charset" using an unbiased-enough
|
||||
# per-byte modulo draw from /dev/urandom. Not part of lib/common.sh's shared
|
||||
# generate_password (that one is deliberately alphanumeric-only — see its
|
||||
|
||||
Reference in New Issue
Block a user