feat(update-setup): Update to support the new authelia/configuration.yml
Some checks failed
/ validate-docker-compose (push) Has been cancelled
Some checks failed
/ validate-docker-compose (push) Has been cancelled
This commit is contained in:
parent
026d24a3ae
commit
ba889f9c38
877
update-setup.sh
877
update-setup.sh
@ -272,503 +272,250 @@ update_authelia_config() {
|
||||
# Update secrets in temp file if they existed in the backup
|
||||
if [[ -n "$existing_jwt_secret" && "$existing_jwt_secret" != '""' && "$existing_jwt_secret" != "null" ]]; then
|
||||
yq e -i '.identity_validation.reset_password.jwt_secret = strenv(existing_jwt_secret)' --env existing_jwt_secret="$existing_jwt_secret" "$TEMP_CONFIG"
|
||||
fi
|
||||
if [[ -n "$existing_session_secret" && "$existing_session_secret" != '""' && "$existing_session_secret" != "null" ]]; then
|
||||
yq e -i '.session.secret = strenv(existing_session_secret)' --env existing_session_secret="$existing_session_secret" "$TEMP_CONFIG"
|
||||
fi
|
||||
if [[ -n "$existing_storage_key" && "$existing_storage_key" != '""' && "$existing_storage_key" != "null" ]]; then
|
||||
yq e -i '.storage.encryption_key = strenv(existing_storage_key)' --env existing_storage_key="$existing_storage_key" "$TEMP_CONFIG"
|
||||
fi
|
||||
if [[ -n "$existing_redis_pass" && "$existing_redis_pass" != '""' && "$existing_redis_pass" != "null" ]]; then
|
||||
yq e -i '.session.redis.password = strenv(existing_redis_pass)' --env existing_redis_pass="$existing_redis_pass" "$TEMP_CONFIG"
|
||||
fi
|
||||
# Preserve entire notifier block if it existed
|
||||
if [[ -n "$existing_notifier" && "$existing_notifier" != "{}" && "$existing_notifier" != "null" ]]; then
|
||||
yq e -i '.notifier = load("'"$AUTHELIA_CONFIG_BACKUP"'").notifier' "$TEMP_CONFIG"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Apply domain settings from .env using yq
|
||||
echo -e "${BLUE}Applying Tailscale domain settings: ${CYAN}$FULL_HOSTNAME${NC}"
|
||||
yq e -i '.session.cookies[0].domain = strenv(TAILNET_DOMAIN)' --env TAILNET_DOMAIN="$TAILNET_DOMAIN" "$TEMP_CONFIG"
|
||||
yq e -i '.session.cookies[0].authelia_url = "https://" + strenv(FULL_HOSTNAME)' --env FULL_HOSTNAME="$FULL_HOSTNAME" "$TEMP_CONFIG"
|
||||
yq e -i '.session.cookies[0].default_redirection_url = "https://" + strenv(FULL_HOSTNAME) + "/home"' --env FULL_HOSTNAME="$FULL_HOSTNAME" "$TEMP_CONFIG"
|
||||
yq e -i '.access_control.rules[0].domain = strenv(WILDCARD_DOMAIN)' --env WILDCARD_DOMAIN="$WILDCARD_DOMAIN" "$TEMP_CONFIG"
|
||||
yq e -i '.access_control.rules[1].domain = strenv(TAILNET_DOMAIN)' --env TAILNET_DOMAIN="$TAILNET_DOMAIN" "$TEMP_CONFIG"
|
||||
|
||||
# Replace the original file with the updated temporary file
|
||||
mv "$TEMP_CONFIG" "$AUTHELIA_CONFIG"
|
||||
echo -e "${GREEN}Authelia configuration updated using yq.${NC}"
|
||||
|
||||
else
|
||||
echo -e "${YELLOW}Warning: 'yq' not found. Falling back to 'sed' for Authelia configuration.${NC}"
|
||||
echo -e "${YELLOW}This method is less robust and might not preserve all existing settings perfectly.${NC}"
|
||||
|
||||
# Copy example over if updating existing file (backup already created)
|
||||
if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then
|
||||
cp "$AUTHELIA_CONFIG_EXAMPLE" "$AUTHELIA_CONFIG"
|
||||
fi
|
||||
|
||||
# Use sed to replace placeholders - less reliable than yq
|
||||
# Note: This assumes the example file uses specific placeholders like 'your-tailnet.ts.net'
|
||||
echo -e "${BLUE}Applying Tailscale domain settings using sed: ${CYAN}$FULL_HOSTNAME${NC}"
|
||||
sed -i "s/\*.your-tailnet.ts.net/\*.$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG"
|
||||
sed -i "s/your-tailnet.ts.net/$TAILNET_DOMAIN/g" "$AUTHELIA_CONFIG" # Replace base domain too
|
||||
sed -i "s|tailscale-nas.your-tailnet.ts.net|$FULL_HOSTNAME|g" "$AUTHELIA_CONFIG" # Replace full hostname
|
||||
|
||||
# Attempt to preserve secrets using sed (very fragile)
|
||||
if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then
|
||||
echo -e "${YELLOW}Attempting to preserve secrets using sed (may be unreliable)...${NC}"
|
||||
local existing_jwt_secret=$(grep -oP 'jwt_secret:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "")
|
||||
local existing_session_secret=$(grep -oP 'session:\s*\n\s*secret:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") # More specific grep
|
||||
local existing_storage_key=$(grep -oP 'storage:\s*\n\s*encryption_key:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") # More specific grep
|
||||
local existing_redis_pass=$(grep -oP 'redis:\s*\n\s*host:.*\n\s*port:.*\n\s*password:\s*\K\S+' "$AUTHELIA_CONFIG_BACKUP" || echo "") # More specific grep
|
||||
|
||||
if [[ -n "$existing_jwt_secret" ]]; then sed -i "s|jwt_secret:.*|jwt_secret: $existing_jwt_secret|" "$AUTHELIA_CONFIG"; fi
|
||||
if [[ -n "$existing_session_secret" ]]; then sed -i "/session:/,/redis:/ s|secret:.*|secret: $existing_session_secret|" "$AUTHELIA_CONFIG"; fi # Target within session block
|
||||
if [[ -n "$existing_storage_key" ]]; then sed -i "/storage:/,/authentication_backend:/ s|encryption_key:.*|encryption_key: $existing_storage_key|" "$AUTHELIA_CONFIG"; fi # Target within storage block
|
||||
if [[ -n "$existing_redis_pass" ]]; then sed -i "/redis:/,/database_index:/ s|password:.*|password: $existing_redis_pass|" "$AUTHELIA_CONFIG"; fi # Target within redis block
|
||||
fi
|
||||
echo -e "${GREEN}Authelia configuration updated using sed.${NC}"
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}${BOLD}Authelia Configuration Update Complete!${NC}"
|
||||
if [ -f "$AUTHELIA_CONFIG_BACKUP" ]; then
|
||||
echo -e "${BLUE}${BOLD}Note:${NC} Original config backed up to: $AUTHELIA_CONFIG_BACKUP"
|
||||
fi
|
||||
}
|
||||
|
||||
##################################################
|
||||
# PART 3: Update Service Configurations
|
||||
# PART 5: Authelia Account Management
|
||||
##################################################
|
||||
# PART 4: Authelia Policy Management
|
||||
##################################################
|
||||
|
||||
update_arr_config() {
|
||||
local container=$1
|
||||
local path=$2
|
||||
# Get the current policy for a service from Authelia config
|
||||
# Usage: get_authelia_policy <service_name> <config_file>
|
||||
# Output: policy (e.g., one_factor, bypass), not_found, or error
|
||||
get_authelia_policy() {
|
||||
local service=$1
|
||||
local config_file=$2
|
||||
|
||||
echo -e "${BLUE}Updating ${container} configuration...${NC}"
|
||||
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config.xml ]; do sleep 1; done
|
||||
sed -i.bak "s/<UrlBase><\/UrlBase>/<UrlBase>\/$path<\/UrlBase>/" "${CONFIG_ROOT:-.}"/"$container"/config.xml && rm "${CONFIG_ROOT:-.}"/"$container"/config.xml.bak
|
||||
|
||||
CONTAINER_NAME_UPPER=$(echo "$container" | tr '[:lower:]' '[:upper:]')
|
||||
sed -i.bak 's/^'"${CONTAINER_NAME_UPPER}"'_API_KEY=.*/'"${CONTAINER_NAME_UPPER}"'_API_KEY='"$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config.xml)"'/' .env && rm .env.bak
|
||||
|
||||
echo -e "${GREEN}Update of ${container} configuration complete, restarting...${NC}"
|
||||
docker compose restart "$container"
|
||||
}
|
||||
|
||||
update_qbittorrent_config() {
|
||||
local container=$1
|
||||
|
||||
echo -e "${BLUE}Updating ${container} configuration...${NC}"
|
||||
docker compose stop "$container"
|
||||
until [ -f "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf ]; do sleep 1; done
|
||||
sed -i.bak '/WebUI\\ServerDomains=*/a WebUI\\Password_PBKDF2="@ByteArray(ARQ77eY1NUZaQsuDHbIMCA==:0WMRkYTUWVT9wVvdDtHAjU9b3b7uB8NR1Gur2hmQCvCDpm39Q+PsJRJPaCU51dEiz+dTzh8qbPsL8WkFljQYFQ==)"' "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf && rm "${CONFIG_ROOT:-.}"/"$container"/qBittorrent/qBittorrent.conf.bak
|
||||
|
||||
echo -e "${GREEN}Update of ${container} configuration complete, restarting...${NC}"
|
||||
docker compose start "$container"
|
||||
}
|
||||
|
||||
update_bazarr_config() {
|
||||
local container=$1
|
||||
|
||||
echo -e "${BLUE}Updating ${container} configuration...${NC}"
|
||||
until [ -f "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml ]; do sleep 1; done
|
||||
sed -i.bak "s/base_url: ''/base_url: '\/$container'/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
sed -i.bak "s/use_radarr: false/use_radarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
sed -i.bak "s/use_sonarr: false/use_sonarr: true/" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
|
||||
until [ -f "${CONFIG_ROOT:-.}"/sonarr/config.xml ]; do sleep 1; done
|
||||
SONARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/sonarr/config.xml)
|
||||
sed -i.bak "/sonarr:/,/^radarr:/ { s/apikey: .*/apikey: $SONARR_API_KEY/; s/base_url: .*/base_url: \/sonarr/; s/ip: .*/ip: sonarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
|
||||
until [ -f "${CONFIG_ROOT:-.}"/radarr/config.xml ]; do sleep 1; done
|
||||
RADARR_API_KEY=$(sed -n 's/.*<ApiKey>\(.*\)<\/ApiKey>.*/\1/p' "${CONFIG_ROOT:-.}"/radarr/config.xml)
|
||||
sed -i.bak "/radarr:/,/^sonarr:/ { s/apikey: .*/apikey: $RADARR_API_KEY/; s/base_url: .*/base_url: \/radarr/; s/ip: .*/ip: radarr/ }" "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml && rm "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml.bak
|
||||
|
||||
sed -i.bak 's/^BAZARR_API_KEY=.*/BAZARR_API_KEY='"$(sed -n 's/.*apikey: \(.*\)*/\1/p' "${CONFIG_ROOT:-.}"/"$container"/config/config/config.yaml | head -n 1)"'/' .env && rm .env.bak
|
||||
|
||||
echo -e "${GREEN}Update of ${container} configuration complete, restarting...${NC}"
|
||||
docker compose restart "$container"
|
||||
}
|
||||
|
||||
update_service_configs() {
|
||||
print_header "Service Configuration Update Tool"
|
||||
|
||||
echo -e "${BLUE}This will update service configurations for running containers${NC}"
|
||||
echo -e "${BLUE}It will set proper URL bases and extract API keys${NC}"
|
||||
echo -e "${YELLOW}Continue? [y/N]:${NC}"
|
||||
read -r answer
|
||||
if [[ ! "$answer" =~ ^[Yy]$ ]]; then
|
||||
echo -e "${RED}Service configuration update cancelled.${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Check if Docker is running
|
||||
if ! docker ps > /dev/null 2>&1; then
|
||||
echo -e "${RED}Error: Docker is not running or you don't have permission to use it.${NC}"
|
||||
echo -e "${YELLOW}Make sure Docker is running and you have proper permissions.${NC}"
|
||||
if ! check_file "$config_file"; then
|
||||
echo "error: config file not found"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Checking for running containers to update...${NC}"
|
||||
for container in $(docker ps --format '{{.Names}}'); do
|
||||
if [[ "$container" =~ ^(radarr|sonarr|lidarr|prowlarr)$ ]]; then
|
||||
update_arr_config "$container" "$container"
|
||||
elif [[ "$container" =~ ^(bazarr)$ ]]; then
|
||||
update_bazarr_config "$container"
|
||||
elif [[ "$container" =~ ^(qbittorrent)$ ]]; then
|
||||
update_qbittorrent_config "$container"
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n${GREEN}${BOLD}Service Configuration Update Complete!${NC}"
|
||||
}
|
||||
|
||||
##################################################
|
||||
# Additional utility functions
|
||||
##################################################
|
||||
|
||||
generate_passphrase() {
|
||||
local words=(
|
||||
"apple" "banana" "cherry" "dragon" "eagle" "forest" "guitar" "harbor"
|
||||
"island" "jungle" "kitchen" "lemon" "mountain" "notebook" "ocean"
|
||||
"planet" "quiet" "river" "summer" "tiger" "umbrella" "village"
|
||||
"winter" "xylophone" "yellow" "zebra" "anchor" "beaver" "candle"
|
||||
"dolphin" "elephant" "falcon" "giraffe" "hamster" "iguana" "jaguar"
|
||||
)
|
||||
|
||||
local separators=( "-" "_" "." "+" "=" "*" "~" "^" "@" "#" "%" "&" "!" "?" )
|
||||
|
||||
local random_num=$((RANDOM % 900 + 100))
|
||||
|
||||
local selected_words=()
|
||||
for i in {1..3}; do
|
||||
local index=$((RANDOM % ${#words[@]}))
|
||||
selected_words+=(${words[$index]})
|
||||
done
|
||||
|
||||
local separator1=${separators[$((RANDOM % ${#separators[@]}))]}
|
||||
local separator2=${separators[$((RANDOM % ${#separators[@]}))]}
|
||||
|
||||
echo "${selected_words[0]}${separator1}${selected_words[1]}${separator2}${selected_words[2]}${random_num}"
|
||||
}
|
||||
|
||||
##################################################
|
||||
# PART 4: Authentication Management
|
||||
##################################################
|
||||
|
||||
# Get the current auth status for a service
|
||||
get_auth_status() {
|
||||
local service=$1
|
||||
|
||||
# Use yq if available for more reliable YAML parsing
|
||||
if command -v yq &> /dev/null; then
|
||||
local middlewares=$(yq e ".services.$service.labels[] | select(contains(\"traefik.http.routers.$service.middlewares=\"))" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -n "$middlewares" ]; then
|
||||
if echo "$middlewares" | grep -q "authelia-auth"; then
|
||||
echo "enabled"
|
||||
else
|
||||
echo "disabled"
|
||||
fi
|
||||
if check_yq; then
|
||||
# Find the rule matching the path_regex for the service
|
||||
# Note: This assumes path_regex is unique enough for the service (e.g., ^/service.*)
|
||||
local policy=$(yq e ".access_control.rules[] | select(.path_regex == \"^/${service}.*\") | .policy" "$config_file" 2>/dev/null)
|
||||
if [ -n "$policy" ] && [ "$policy" != "null" ]; then
|
||||
echo "$policy"
|
||||
else
|
||||
echo "unknown"
|
||||
# Check if a rule exists for the service path at all
|
||||
local rule_exists=$(yq e ".access_control.rules[] | select(.path_regex == \"^/${service}.*\")" "$config_file" 2>/dev/null)
|
||||
if [ -n "$rule_exists" ] && [ "$rule_exists" != "null" ]; then
|
||||
echo "error: policy not found in rule" # Rule exists but policy couldn't be read
|
||||
else
|
||||
echo "not_found" # No rule found for this service path
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Fall back to grep if yq isn't available
|
||||
if grep -q "traefik.http.routers.$service.middlewares=.*authelia-auth" "$COMPOSE_FILE"; then
|
||||
echo "enabled"
|
||||
elif grep -q "traefik.http.routers.$service.middlewares=" "$COMPOSE_FILE"; then
|
||||
echo "disabled"
|
||||
# Fall back to grep if yq isn't available (less reliable)
|
||||
# This is fragile and depends heavily on formatting
|
||||
local policy_line=$(grep -A 1 "path_regex: '^/${service}.*'" "$config_file" | grep "policy:")
|
||||
if [ -n "$policy_line" ]; then
|
||||
echo "$policy_line" | awk '{print $2}'
|
||||
else
|
||||
echo "unknown"
|
||||
echo "not_found"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
enable_auth() {
|
||||
local service=$1
|
||||
echo -e "${BLUE}Enabling authentication for $service...${NC}"
|
||||
|
||||
# Check if service exists in the compose file
|
||||
# Use yq if available for more reliable parsing
|
||||
if command -v yq &> /dev/null; then
|
||||
# Check if service exists
|
||||
local service_exists=$(yq e ".services.$service" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -z "$service_exists" ] || [ "$service_exists" == "null" ]; then
|
||||
echo -e "${RED}Service $service not found in $COMPOSE_FILE${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if auth is already enabled
|
||||
local middlewares=$(yq e ".services.$service.labels[] | select(contains(\"traefik.http.routers.$service.middlewares=\"))" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -n "$middlewares" ] && echo "$middlewares" | grep -q "authelia-auth"; then
|
||||
echo -e "${GREEN}Authentication already enabled for $service${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create a temporary file for editing with yq
|
||||
local temp_file="${COMPOSE_FILE}.tmp"
|
||||
|
||||
# Check if there's already a middlewares label
|
||||
if [ -n "$middlewares" ]; then
|
||||
# Modify the existing middlewares label to include authelia-auth
|
||||
if echo "$middlewares" | grep -q "middlewares=$"; then
|
||||
# Empty middlewares
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=authelia-auth@docker\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
elif echo "$middlewares" | grep -q "middlewares=.*@docker"; then
|
||||
# Has other middlewares with @docker
|
||||
local current_value=$(echo "$middlewares" | sed 's/.*middlewares=\(.*\)@docker.*/\1/')
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=${current_value},authelia-auth@docker\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
else
|
||||
# Has middlewares without @docker
|
||||
local current_value=$(echo "$middlewares" | sed 's/.*middlewares=\(.*\).*/\1/')
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=${current_value},authelia-auth@docker\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
fi
|
||||
else
|
||||
# Need to add a new middlewares label
|
||||
# Check if the service has any labels
|
||||
local has_labels=$(yq e ".services.$service.labels" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -z "$has_labels" ] || [ "$has_labels" == "null" ]; then
|
||||
# Add a new labels array with the middlewares
|
||||
yq e ".services.$service.labels = [\"traefik.http.routers.$service.middlewares=authelia-auth@docker\"]" "$COMPOSE_FILE" > "$temp_file"
|
||||
else
|
||||
# Add the middlewares to the existing labels
|
||||
yq e ".services.$service.labels += [\"traefik.http.routers.$service.middlewares=authelia-auth@docker\"]" "$COMPOSE_FILE" > "$temp_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Replace the original file if the temp file was created successfully
|
||||
if [ $? -eq 0 ] && [ -f "$temp_file" ]; then
|
||||
mv "$temp_file" "$COMPOSE_FILE"
|
||||
echo -e "${GREEN}Authentication enabled for $service${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}Failed to update the compose file with yq. Falling back to sed.${NC}"
|
||||
rm -f "$temp_file" # Clean up if the temp file exists
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fall back to the existing implementation if yq is not available or failed
|
||||
if ! grep -q "container_name: $service" "$COMPOSE_FILE"; then
|
||||
echo -e "${RED}Service $service not found in $COMPOSE_FILE${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local service_start=$(grep -n "container_name: $service" "$COMPOSE_FILE" | cut -d':' -f1)
|
||||
if [ -z "$service_start" ]; then
|
||||
echo -e "${RED}Could not find service $service in $COMPOSE_FILE${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local next_service=$(tail -n +$((service_start+1)) "$COMPOSE_FILE" | grep -n "container_name:" | head -1 | cut -d':' -f1)
|
||||
if [ -n "$next_service" ]; then
|
||||
next_service=$((service_start + next_service))
|
||||
else
|
||||
next_service=$(wc -l < "$COMPOSE_FILE")
|
||||
fi
|
||||
|
||||
local service_section=$(sed -n "${service_start},${next_service}p" "$COMPOSE_FILE")
|
||||
|
||||
if echo "$service_section" | grep -q "traefik.http.routers.$service.middlewares="; then
|
||||
local middlewares_line=$(echo "$service_section" | grep "traefik.http.routers.$service.middlewares=")
|
||||
|
||||
if echo "$middlewares_line" | grep -q "authelia-auth@docker"; then
|
||||
echo -e "${GREEN}Authentication already enabled for $service${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if echo "$middlewares_line" | grep -q "middlewares=$"; then
|
||||
sed -i "s|traefik.http.routers.$service.middlewares=|traefik.http.routers.$service.middlewares=authelia-auth@docker|" "$COMPOSE_FILE"
|
||||
elif echo "$middlewares_line" | grep -q "middlewares=.*@docker"; then
|
||||
sed -i "s|traefik.http.routers.$service.middlewares=\(.*\)@docker|traefik.http.routers.$service.middlewares=\1,authelia-auth@docker|" "$COMPOSE_FILE"
|
||||
else
|
||||
sed -i "s|traefik.http.routers.$service.middlewares=\(.*\)|traefik.http.routers.$service.middlewares=\1,authelia-auth@docker|" "$COMPOSE_FILE"
|
||||
fi
|
||||
else
|
||||
local labels_line=$(echo "$service_section" | grep -n "labels:" | cut -d':' -f1)
|
||||
if [ -z "$labels_line" ]; then
|
||||
echo -e "${RED}Could not find labels section for service $service${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local rule_line=$(echo "$service_section" | grep -n "traefik.http.routers.$service.rule=" | cut -d':' -f1)
|
||||
if [ -n "$rule_line" ]; then
|
||||
rule_line=$((service_start + rule_line))
|
||||
sed -i "${rule_line}a \ \ \ \ \ \ - traefik.http.routers.$service.middlewares=authelia-auth@docker" "$COMPOSE_FILE"
|
||||
else
|
||||
echo -e "${RED}Could not find rule line for service $service${NC}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Authentication enabled for $service${NC}"
|
||||
return 0
|
||||
}
|
||||
|
||||
disable_auth() {
|
||||
# Set the policy for a service in Authelia config
|
||||
# Usage: set_authelia_policy <service_name> <policy> <config_file>
|
||||
set_authelia_policy() {
|
||||
local service=$1
|
||||
echo -e "${BLUE}Disabling authentication for $service...${NC}"
|
||||
local policy=$2
|
||||
local config_file=$3
|
||||
local backup_file="${config_file}.${TIMESTAMP}.bak"
|
||||
|
||||
# Use yq if available for more reliable parsing
|
||||
if command -v yq &> /dev/null; then
|
||||
# Check if service exists
|
||||
local service_exists=$(yq e ".services.$service" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -z "$service_exists" ] || [ "$service_exists" == "null" ]; then
|
||||
echo -e "${RED}Service $service not found in $COMPOSE_FILE${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if auth is already disabled
|
||||
local middlewares=$(yq e ".services.$service.labels[] | select(contains(\"traefik.http.routers.$service.middlewares=\"))" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -n "$middlewares" ] && ! echo "$middlewares" | grep -q "authelia-auth"; then
|
||||
echo -e "${GREEN}Authentication already disabled for $service${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Create a temporary file for editing with yq
|
||||
local temp_file="${COMPOSE_FILE}.tmp"
|
||||
|
||||
# Extract current middlewares
|
||||
if [ -n "$middlewares" ]; then
|
||||
if echo "$middlewares" | grep -q "traefik.http.routers.$service.middlewares=authelia-auth@docker$"; then
|
||||
# Only authelia-auth@docker, replace with empty
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
elif echo "$middlewares" | grep -q "traefik.http.routers.$service.middlewares=authelia-auth@docker,"; then
|
||||
# authelia-auth@docker at start with comma
|
||||
local remaining=$(echo "$middlewares" | sed 's/.*middlewares=authelia-auth@docker,\(.*\)/\1/')
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=${remaining}\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
elif echo "$middlewares" | grep -q "traefik.http.routers.$service.middlewares=.*,authelia-auth@docker$"; then
|
||||
# authelia-auth@docker at end with comma
|
||||
local remaining=$(echo "$middlewares" | sed 's/\(.*\),authelia-auth@docker$/\1/')
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=${remaining}\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
elif echo "$middlewares" | grep -q "traefik.http.routers.$service.middlewares=.*,authelia-auth@docker,.*"; then
|
||||
# authelia-auth@docker in the middle with commas
|
||||
local remaining=$(echo "$middlewares" | sed 's/\(.*\),authelia-auth@docker,\(.*\)/\1,\2/')
|
||||
yq e ".services.$service.labels |= map(. | select(contains(\"traefik.http.routers.$service.middlewares=\")) |= \"traefik.http.routers.$service.middlewares=${remaining}\" // .)" "$COMPOSE_FILE" > "$temp_file"
|
||||
else
|
||||
echo -e "${RED}Could not determine how to remove authelia-auth from middlewares for $service${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Replace the original file if the temp file was created successfully
|
||||
if [ $? -eq 0 ] && [ -f "$temp_file" ]; then
|
||||
mv "$temp_file" "$COMPOSE_FILE"
|
||||
echo -e "${GREEN}Authentication disabled for $service${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}Failed to update the compose file with yq. Falling back to sed.${NC}"
|
||||
rm -f "$temp_file" # Clean up if the temp file exists
|
||||
fi
|
||||
else
|
||||
echo -e "${GREEN}No middlewares found for $service, authentication is already disabled${NC}"
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fall back to the existing implementation if yq is not available or failed
|
||||
if ! grep -q "container_name: $service" "$COMPOSE_FILE"; then
|
||||
echo -e "${RED}Service $service not found in $COMPOSE_FILE${NC}"
|
||||
if ! check_file "$config_file"; then
|
||||
echo -e "${RED}Error: Authelia configuration file '$config_file' not found.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if grep -q "traefik.http.routers.$service.middlewares=.*authelia-auth@docker" "$COMPOSE_FILE"; then
|
||||
if grep -q "traefik.http.routers.$service.middlewares=authelia-auth@docker" "$COMPOSE_FILE"; then
|
||||
sed -i "s|traefik.http.routers.$service.middlewares=authelia-auth@docker|traefik.http.routers.$service.middlewares=|" "$COMPOSE_FILE"
|
||||
elif grep -q "traefik.http.routers.$service.middlewares=authelia-auth@docker," "$COMPOSE_FILE"; then
|
||||
sed -i "s|traefik.http.routers.$service.middlewares=authelia-auth@docker,|traefik.http.routers.$service.middlewares=|" "$COMPOSE_FILE"
|
||||
elif grep -q "traefik.http.routers.$service.middlewares=.*,authelia-auth@docker" "$COMPOSE_FILE"; then
|
||||
sed -i "s|,authelia-auth@docker||" "$COMPOSE_FILE"
|
||||
elif grep -q "traefik.http.routers.$service.middlewares=.*,authelia-auth@docker,.*" "$COMPOSE_FILE"; then
|
||||
sed -i "s|,authelia-auth@docker,|,|" "$COMPOSE_FILE"
|
||||
else
|
||||
echo -e "${RED}Could not determine how to remove authelia-auth from middlewares for $service${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Authentication disabled for $service${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Authentication already disabled for $service${NC}"
|
||||
if [[ "$policy" != "one_factor" && "$policy" != "two_factor" && "$policy" != "deny" && "$policy" != "bypass" ]]; then
|
||||
echo -e "${RED}Error: Invalid policy '$policy'. Must be one of: one_factor, two_factor, deny, bypass.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
echo -e "${BLUE}Setting policy for service '$service' to '$policy' in '$config_file'...${NC}"
|
||||
|
||||
# Create backup if it doesn't exist for this run
|
||||
if [ ! -f "$backup_file" ]; then
|
||||
create_backup "$config_file" "$backup_file"
|
||||
fi
|
||||
|
||||
# Use yq if available
|
||||
if check_yq; then
|
||||
# Check if the rule exists first using the path_regex
|
||||
local rule_index=$(yq e ".access_control.rules | map(.path_regex == \"^/${service}.*\") | indexOf(true)" "$config_file" 2>/dev/null)
|
||||
|
||||
if [ "$rule_index" == "-1" ] || [ -z "$rule_index" ]; then
|
||||
echo -e "${YELLOW}Warning: No rule found for service path '^/${service}.*' in '$config_file'.${NC}"
|
||||
echo -e "${YELLOW}Attempting to add a new rule...${NC}"
|
||||
|
||||
# Get the tailnet domain from .env for the new rule
|
||||
local TAILNET_DOMAIN=$(grep -oP "^TAILSCALE_TAILNET_DOMAIN=\K.*" "$ENV_FILE" | tr -d '"' | tr -d "'")
|
||||
if [ -z "$TAILNET_DOMAIN" ]; then
|
||||
echo -e "${RED}Error: Could not read TAILSCALE_TAILNET_DOMAIN from $ENV_FILE. Cannot add rule.${NC}"
|
||||
return 1
|
||||
fi
|
||||
local WILDCARD_DOMAIN="*.${TAILNET_DOMAIN}"
|
||||
|
||||
# Add the new rule to the access_control.rules array
|
||||
# Places it before the generic domain rule if it exists, otherwise at the end
|
||||
# This assumes a generic rule like "- domain: '*.domain.tld'" exists near the end
|
||||
yq e -i ".access_control.rules |= select(.domain != \"${WILDCARD_DOMAIN}\" or .path_regex != null) + [{\"domain\": \"${WILDCARD_DOMAIN}\", \"path_regex\": \"^/${service}.*\", \"policy\": \"${policy}\"}] + select(.domain == \"${WILDCARD_DOMAIN}\" and .path_regex == null)" "$config_file"
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}Added new rule for '$service' with policy '$policy'.${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}Error: Failed to add new rule for '$service' using yq.${NC}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
# Rule exists, update the policy at the found index
|
||||
yq e -i "(.access_control.rules[$rule_index].policy) = \"$policy\"" "$config_file"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}Policy for '$service' updated to '$policy'.${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}Error: Failed to update policy for '$service' using yq.${NC}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
else
|
||||
# Fallback to sed (much less reliable, especially for adding rules)
|
||||
echo -e "${YELLOW}Warning: 'yq' not found. Using 'sed' which is less reliable for YAML manipulation.${NC}"
|
||||
# Check if rule exists (simple grep)
|
||||
if grep -q "path_regex: '^/${service}.*'" "$config_file"; then
|
||||
# Attempt to find the line number of path_regex and update the policy line below it
|
||||
local line_num=$(grep -n "path_regex: '^/${service}.*'" "$config_file" | head -n 1 | cut -d: -f1) # Use head -n 1 just in case
|
||||
if [ -n "$line_num" ]; then
|
||||
# Assuming policy is the next line (fragile!)
|
||||
local policy_line_num=$((line_num + 1))
|
||||
# Check if the next line actually contains 'policy:'
|
||||
if sed -n "${policy_line_num}p" "$config_file" | grep -q "policy:"; then
|
||||
sed -i "${policy_line_num}s/policy:.*/policy: $policy/" "$config_file"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "${GREEN}Policy for '$service' updated to '$policy' (using sed).${NC}"
|
||||
return 0
|
||||
else
|
||||
echo -e "${RED}Error: Failed to update policy line using sed.${NC}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}Error: Could not reliably find policy line for '$service' using sed (expected on line $policy_line_num).${NC}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}Error: Could not find line number for service '$service' using sed.${NC}"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
echo -e "${RED}Error: Rule for service '$service' not found. Cannot add rule using sed.${NC}"
|
||||
return 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
list_services() {
|
||||
print_header "Services Authentication Status"
|
||||
# List services and their Authelia policy status
|
||||
list_authelia_services() {
|
||||
print_header "Authelia Service Policy Status"
|
||||
|
||||
# Check if file exists
|
||||
if ! check_file "$COMPOSE_FILE"; then
|
||||
echo -e "${RED}Error: $COMPOSE_FILE doesn't exist${NC}"
|
||||
if ! check_file "$AUTHELIA_CONFIG"; then
|
||||
echo -e "${RED}Error: Authelia configuration file '$AUTHELIA_CONFIG' not found.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo -e "${BLUE}Checking services in $COMPOSE_FILE...${NC}"
|
||||
echo -e "${CYAN}SERVICE\t\tAUTH STATUS${NC}"
|
||||
echo -e "${CYAN}-------\t\t-----------${NC}"
|
||||
echo -e "${BLUE}Checking service policies in $AUTHELIA_CONFIG...${NC}"
|
||||
echo -e "${CYAN}SERVICE\t\tPOLICY${NC}"
|
||||
echo -e "${CYAN}-------\t\t------${NC}"
|
||||
|
||||
local service_count=0
|
||||
local processed_services="" # Track processed services
|
||||
|
||||
# Get all router names from the labels
|
||||
# This pattern is specific to how your docker-compose.yml format works
|
||||
local router_lines=$(grep -n "traefik.http.routers" "$COMPOSE_FILE")
|
||||
# Use yq to get all rules with path_regex if available
|
||||
if check_yq; then
|
||||
# Extract path_regex and policy for rules that have path_regex
|
||||
local rules_data=$(yq e '.access_control.rules[] | select(has("path_regex")) | {"path": .path_regex, "policy": .policy}' "$AUTHELIA_CONFIG")
|
||||
|
||||
# Process each router line to get service names
|
||||
while IFS= read -r line; do
|
||||
local line_num=$(echo "$line" | cut -d: -f1)
|
||||
local router_config=$(echo "$line" | cut -d: -f2-)
|
||||
# Process each rule found
|
||||
while IFS= read -r line; do
|
||||
# Extract service name from path_regex (e.g., "^/sonarr.*" -> "sonarr")
|
||||
local path_regex=$(echo "$line" | grep -oP 'path: \K.*' | tr -d '"' | tr -d "'")
|
||||
local policy=$(echo "$line" | grep -oP 'policy: \K.*' | tr -d '"' | tr -d "'")
|
||||
|
||||
# Extract service name from router definition
|
||||
if [[ "$router_config" =~ traefik\.http\.routers\.([^.]+) ]]; then
|
||||
local service="${BASH_REMATCH[1]}"
|
||||
if [[ "$path_regex" =~ ^\^/([a-zA-Z0-9_-]+)\.\* ]]; then
|
||||
local service="${BASH_REMATCH[1]}"
|
||||
|
||||
# Skip infrastructure containers
|
||||
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Skip duplicate entries - only handle each service once
|
||||
if [[ "$processed_services" == *"$service"* ]]; then
|
||||
continue
|
||||
fi
|
||||
processed_services="$processed_services $service"
|
||||
|
||||
# Find if this router has a middlewares configuration, with or without authelia
|
||||
local status="unknown"
|
||||
# Look for middlewares for this service
|
||||
if grep -q "traefik.http.routers.$service.middlewares=.*authelia-auth" "$COMPOSE_FILE"; then
|
||||
status="enabled"
|
||||
elif grep -q "traefik.http.routers.$service.middlewares=" "$COMPOSE_FILE"; then
|
||||
# Has middlewares but no authelia-auth
|
||||
if ! grep -q "traefik.http.routers.$service.middlewares=.*authelia-auth" "$COMPOSE_FILE"; then
|
||||
status="disabled"
|
||||
# Skip duplicates if multiple rules somehow match the same pattern start
|
||||
if [[ "$processed_services" == *"$service"* ]]; then
|
||||
continue
|
||||
fi
|
||||
processed_services="$processed_services $service"
|
||||
|
||||
printf "${BOLD}%-20s${NC}" "$service"
|
||||
case "$policy" in
|
||||
"one_factor"|"two_factor")
|
||||
echo -e "${GREEN}${policy}${NC}"
|
||||
;;
|
||||
"bypass")
|
||||
echo -e "${YELLOW}${policy}${NC}"
|
||||
;;
|
||||
"deny")
|
||||
echo -e "${RED}${policy}${NC}"
|
||||
;;
|
||||
*)
|
||||
echo -e "${MAGENTA}Unknown ($policy)${NC}"
|
||||
;;
|
||||
esac
|
||||
service_count=$((service_count + 1))
|
||||
fi
|
||||
# Use yq -N to prevent splitting lines with spaces
|
||||
done <<< "$(echo "$rules_data" | yq -N e '.' -)"
|
||||
|
||||
printf "${BOLD}%-20s${NC}" "$service"
|
||||
else
|
||||
# Fallback to grep (less reliable)
|
||||
echo -e "${YELLOW}Warning: yq not found, using grep (may miss services or show duplicates).${NC}"
|
||||
# Find lines with path_regex, then try to get the policy line after
|
||||
grep -n "path_regex: '^/.*" "$AUTHELIA_CONFIG" | while IFS=: read -r line_num line_content; do
|
||||
if [[ "$line_content" =~ path_regex:\ \'^\/([a-zA-Z0-9_-]+)\.\*\' ]]; then
|
||||
local service="${BASH_REMATCH[1]}"
|
||||
# Skip duplicates
|
||||
if [[ "$processed_services" == *"$service"* ]]; then
|
||||
continue
|
||||
fi
|
||||
processed_services="$processed_services $service"
|
||||
|
||||
case "$status" in
|
||||
"enabled")
|
||||
echo -e "${GREEN}Enabled${NC}"
|
||||
service_count=$((service_count + 1))
|
||||
;;
|
||||
"disabled")
|
||||
echo -e "${YELLOW}Disabled${NC}"
|
||||
service_count=$((service_count + 1))
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown${NC}"
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
done <<< "$router_lines"
|
||||
# Try to get policy from the next line (very fragile)
|
||||
local policy_line_num=$((line_num + 1))
|
||||
local policy=$(sed -n "${policy_line_num}p" "$AUTHELIA_CONFIG" | grep "policy:" | awk '{print $2}')
|
||||
|
||||
printf "${BOLD}%-20s${NC}" "$service"
|
||||
if [ -n "$policy" ]; then
|
||||
case "$policy" in
|
||||
"one_factor"|"two_factor") echo -e "${GREEN}${policy}${NC}" ;;
|
||||
"bypass") echo -e "${YELLOW}${policy}${NC}" ;;
|
||||
"deny") echo -e "${RED}${policy}${NC}" ;;
|
||||
*) echo -e "${MAGENTA}Unknown ($policy)${NC}" ;;
|
||||
esac
|
||||
else
|
||||
echo -e "${RED}Unknown (could not read policy)${NC}"
|
||||
fi
|
||||
service_count=$((service_count + 1))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
if [ $service_count -eq 0 ]; then
|
||||
echo -e "${YELLOW}No services found with authentication status.${NC}"
|
||||
echo -e "${YELLOW}This could indicate an issue with detecting middlewares in your docker-compose.yml.${NC}"
|
||||
echo -e "${YELLOW}No services with path_regex rules found in $AUTHELIA_CONFIG.${NC}"
|
||||
echo -e "${YELLOW}Only services explicitly defined with path_regex rules are listed.${NC}"
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
|
||||
cleanup_backups() {
|
||||
print_header "Backup Files Cleanup"
|
||||
|
||||
@ -844,104 +591,89 @@ cleanup_backups() {
|
||||
fi
|
||||
}
|
||||
|
||||
manage_auth() {
|
||||
print_header "Authentication Management"
|
||||
# Interactive menu for managing Authelia policies
|
||||
manage_authelia_policies() {
|
||||
print_header "Authelia Policy Management"
|
||||
|
||||
echo -e "${BLUE}This tool lets you control which services require authentication${NC}"
|
||||
echo -e "${BLUE}Choose an option:${NC}"
|
||||
echo -e " ${CYAN}1. ${NC}List services and their authentication status"
|
||||
echo -e " ${CYAN}2. ${NC}Enable authentication for a service"
|
||||
echo -e " ${CYAN}3. ${NC}Disable authentication for a service"
|
||||
echo -e " ${CYAN}4. ${NC}Enable authentication for all services"
|
||||
echo -e " ${CYAN}5. ${NC}Disable authentication for all services"
|
||||
echo -e " ${CYAN}6. ${NC}Return to main menu"
|
||||
echo
|
||||
if ! check_file "$AUTHELIA_CONFIG"; then
|
||||
echo -e "${RED}Error: Authelia configuration file '$AUTHELIA_CONFIG' not found.${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local choice
|
||||
while true; do
|
||||
echo -e "${YELLOW}Enter your choice [1-6]: ${NC}"
|
||||
echo -e "\n${BLUE}Choose an option:${NC}"
|
||||
echo -e " ${CYAN}1. ${NC}List services and their current Authelia policy"
|
||||
echo -e " ${CYAN}2. ${NC}Set Authelia policy for a service"
|
||||
echo -e " ${CYAN}3. ${NC}Return to main menu"
|
||||
echo
|
||||
|
||||
local choice
|
||||
echo -e "${YELLOW}Enter your choice [1-3]: ${NC}"
|
||||
read -r choice
|
||||
|
||||
case "$choice" in
|
||||
1)
|
||||
list_services
|
||||
list_authelia_services
|
||||
;;
|
||||
2)
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
|
||||
echo -e "${BLUE}Enter the service name to enable authentication for:${NC}"
|
||||
echo -e "${BLUE}Enter the service name to set the policy for (e.g., sonarr, radarr):${NC}"
|
||||
read -r service
|
||||
if [ -z "$service" ]; then
|
||||
echo -e "${RED}No service name provided.${NC}"
|
||||
continue
|
||||
fi
|
||||
enable_auth "$service"
|
||||
|
||||
echo -e "${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down${NC}"
|
||||
echo -e " ${CYAN}docker compose up -d${NC}"
|
||||
echo -e "${BLUE}Select the desired policy for '$service':${NC}"
|
||||
echo -e " ${CYAN}1. ${GREEN}one_factor${NC} (Requires login)"
|
||||
echo -e " ${CYAN}2. ${GREEN}two_factor${NC} (Requires login + 2FA)"
|
||||
echo -e " ${CYAN}3. ${YELLOW}bypass${NC} (No login required)"
|
||||
echo -e " ${CYAN}4. ${RED}deny${NC} (Access denied)"
|
||||
echo -e " ${CYAN}5. ${NC}Cancel"
|
||||
|
||||
local policy_choice
|
||||
local policy=""
|
||||
while true; do
|
||||
echo -e "${YELLOW}Enter policy choice [1-5]: ${NC}"
|
||||
read -r policy_choice
|
||||
case "$policy_choice" in
|
||||
1) policy="one_factor"; break ;;
|
||||
2) policy="two_factor"; break ;;
|
||||
3) policy="bypass"; break ;;
|
||||
4) policy="deny"; break ;;
|
||||
5) policy=""; break ;; # Cancel
|
||||
*) echo -e "${RED}Invalid choice.${NC}" ;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [ -z "$policy" ]; then
|
||||
echo -e "${YELLOW}Policy change cancelled.${NC}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Call the function to set the policy
|
||||
set_authelia_policy "$service" "$policy" "$AUTHELIA_CONFIG"
|
||||
|
||||
# Check the return status of set_authelia_policy
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "\n${YELLOW}Remember to restart Authelia for the policy change to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose restart authelia${NC}"
|
||||
else
|
||||
echo -e "${RED}Failed to set policy. Please check errors above.${NC}"
|
||||
# Optionally offer to restore backup here
|
||||
fi
|
||||
;;
|
||||
3)
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
|
||||
echo -e "${BLUE}Enter the service name to disable authentication for:${NC}"
|
||||
read -r service
|
||||
if [ -z "$service" ]; then
|
||||
echo -e "${RED}No service name provided.${NC}"
|
||||
continue
|
||||
fi
|
||||
disable_auth "$service"
|
||||
|
||||
echo -e "${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down${NC}"
|
||||
echo -e " ${CYAN}docker compose up -d${NC}"
|
||||
;;
|
||||
4)
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
|
||||
echo -e "${BLUE}Enabling authentication for all services...${NC}"
|
||||
local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}')
|
||||
for service in $services; do
|
||||
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
enable_auth "$service"
|
||||
done
|
||||
|
||||
echo -e "${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down${NC}"
|
||||
echo -e " ${CYAN}docker compose up -d${NC}"
|
||||
;;
|
||||
5)
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
|
||||
echo -e "${BLUE}Disabling authentication for all services...${NC}"
|
||||
local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}')
|
||||
for service in $services; do
|
||||
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
disable_auth "$service"
|
||||
done
|
||||
|
||||
echo -e "${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down${NC}"
|
||||
echo -e " ${CYAN}docker compose up -d${NC}"
|
||||
;;
|
||||
6)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Invalid choice. Please try again.${NC}"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo
|
||||
echo # Add a newline for better readability between menu iterations
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
##################################################
|
||||
# PART 5: Authelia Account Management
|
||||
##################################################
|
||||
@ -1119,22 +851,22 @@ show_help() {
|
||||
echo -e " ${CYAN}update-services${NC} Update configurations for running *arr/qBittorrent/Bazarr containers"
|
||||
echo -e " (sets URL base, extracts API keys to .env)."
|
||||
echo -e " ${CYAN}manage-accounts${NC} Interactively add/update Authelia users in users_database.yml."
|
||||
echo -e " ${CYAN}list-auth${NC} List authentication status for all services in docker-compose.yml."
|
||||
echo -e " ${CYAN}enable-auth <service>${NC} Enable Authelia authentication for a specific service."
|
||||
echo -e " ${CYAN}disable-auth <service>${NC} Disable Authelia authentication for a specific service."
|
||||
echo -e " ${CYAN}enable-all-auth${NC} Enable Authelia authentication for all applicable services."
|
||||
echo -e " ${CYAN}disable-all-auth${NC} Disable Authelia authentication for all applicable services."
|
||||
echo -e " ${CYAN}manage-policies${NC} Interactively manage Authelia access policies for services."
|
||||
echo -e " ${CYAN}list-policies${NC} List services and their current Authelia policy."
|
||||
echo -e " ${CYAN}set-policy <svc> <pol>${NC} Set Authelia policy for a service (e.g., 'one_factor', 'bypass')."
|
||||
echo -e " ${CYAN}cleanup${NC} Interactively clean up old backup files (.bak)."
|
||||
echo -e " ${CYAN}all${NC} Run 'update-env', 'update-authelia', and 'update-services'."
|
||||
echo -e " ${CYAN}help${NC} Show this help message."
|
||||
echo -e ""
|
||||
echo -e "${BLUE}Examples:${NC}"
|
||||
echo -e " $0 update-authelia"
|
||||
echo -e " $0 enable-auth sonarr"
|
||||
echo -e " $0 set-policy sonarr one_factor"
|
||||
echo -e " $0 set-policy radarr bypass"
|
||||
echo -e " $0 manage-policies"
|
||||
echo -e " $0 all"
|
||||
echo -e ""
|
||||
echo -e "${YELLOW}Note:${NC} Some commands require Docker to be running and may restart containers."
|
||||
echo -e "${YELLOW}Authentication changes require a stack restart ('docker compose down && docker compose up -d').${NC}"
|
||||
echo -e "${YELLOW}Policy changes require an Authelia restart ('docker compose restart authelia').${NC}"
|
||||
}
|
||||
|
||||
# Check if any arguments were provided
|
||||
@ -1155,77 +887,28 @@ case "$1" in
|
||||
update_service_configs
|
||||
;;
|
||||
manage-accounts)
|
||||
manage_authelia_accounts # This function remains interactive
|
||||
manage_authelia_accounts # Interactive
|
||||
;;
|
||||
list-auth)
|
||||
list_services
|
||||
manage-policies)
|
||||
manage_authelia_policies # Interactive
|
||||
;;
|
||||
enable-auth)
|
||||
if [ -z "$2" ]; then
|
||||
echo -e "${RED}Error: No service specified.${NC}" >&2
|
||||
echo -e "Usage: $0 enable-auth <service>" >&2
|
||||
list-policies)
|
||||
list_authelia_services
|
||||
;;
|
||||
set-policy)
|
||||
if [ -z "$2" ] || [ -z "$3" ]; then
|
||||
echo -e "${RED}Error: Service name and policy are required.${NC}" >&2
|
||||
echo -e "Usage: $0 set-policy <service_name> <policy>${NC}" >&2
|
||||
echo -e "Valid policies: one_factor, two_factor, bypass, deny" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! check_file "$COMPOSE_FILE"; then exit 1; fi
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
enable_auth "$2"
|
||||
echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down && docker compose up -d${NC}"
|
||||
;;
|
||||
disable-auth)
|
||||
if [ -z "$2" ]; then
|
||||
echo -e "${RED}Error: No service specified.${NC}" >&2
|
||||
echo -e "Usage: $0 disable-auth <service>" >&2
|
||||
exit 1
|
||||
if ! check_file "$AUTHELIA_CONFIG"; then exit 1; fi
|
||||
# Backup is handled within set_authelia_policy if needed
|
||||
set_authelia_policy "$2" "$3" "$AUTHELIA_CONFIG"
|
||||
if [ $? -eq 0 ]; then
|
||||
echo -e "\n${YELLOW}Remember to restart Authelia for the policy change to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose restart authelia${NC}"
|
||||
fi
|
||||
if ! check_file "$COMPOSE_FILE"; then exit 1; fi
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
disable_auth "$2"
|
||||
echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down && docker compose up -d${NC}"
|
||||
;;
|
||||
enable-all-auth)
|
||||
if ! check_file "$COMPOSE_FILE"; then exit 1; fi
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
echo -e "${BLUE}Enabling authentication for all applicable services...${NC}"
|
||||
# Use yq if available for more reliable service list, otherwise fallback to grep
|
||||
local services_list
|
||||
if check_yq; then
|
||||
services_list=$(yq e '.services | keys | .[]' "$COMPOSE_FILE")
|
||||
else
|
||||
services_list=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $NF}') # Less reliable
|
||||
fi
|
||||
|
||||
for service in $services_list; do
|
||||
# Skip infrastructure/excluded containers
|
||||
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
|
||||
continue
|
||||
fi
|
||||
enable_auth "$service"
|
||||
done
|
||||
echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down && docker compose up -d${NC}"
|
||||
;;
|
||||
disable-all-auth)
|
||||
if ! check_file "$COMPOSE_FILE"; then exit 1; fi
|
||||
create_backup "$COMPOSE_FILE" "$COMPOSE_BACKUP"
|
||||
echo -e "${BLUE}Disabling authentication for all applicable services...${NC}"
|
||||
local services_list
|
||||
if check_yq; then
|
||||
services_list=$(yq e '.services | keys | .[]' "$COMPOSE_FILE")
|
||||
else
|
||||
services_list=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $NF}') # Less reliable
|
||||
fi
|
||||
|
||||
for service in $services_list; do
|
||||
# Skip infrastructure/excluded containers
|
||||
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
|
||||
continue
|
||||
fi
|
||||
disable_auth "$service"
|
||||
done
|
||||
echo -e "\n${YELLOW}Remember to restart the stack for changes to take effect:${NC}"
|
||||
echo -e " ${CYAN}docker compose down && docker compose up -d${NC}"
|
||||
;;
|
||||
cleanup)
|
||||
cleanup_backups
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user