docker-compose-nas/manage-auth.sh
2025-04-26 02:45:09 +08:00

302 lines
12 KiB
Bash
Executable File

#!/bin/bash
# Authentication Management Script for docker-compose-nas
# Enables or disables Authelia authentication for specific services
# Created: April 26, 2025
set -e
# Color definitions
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[0;33m'
BLUE='\033[0;34m'
CYAN='\033[0;36m'
BOLD='\033[1m'
NC='\033[0m' # No Color
# Files
COMPOSE_FILE="docker-compose.yml"
TIMESTAMP=$(date +"%Y%m%d-%H%M%S")
BACKUP_FILE="docker-compose.${TIMESTAMP}.bak"
# Print section header
print_header() {
echo -e "\n${CYAN}${BOLD}$1${NC}"
echo -e "${CYAN}$(printf '=%.0s' $(seq 1 ${#1}))${NC}"
}
# Create a backup of the docker-compose.yml file
create_backup() {
echo -e "${BLUE}Creating backup of $COMPOSE_FILE as $BACKUP_FILE...${NC}"
cp "$COMPOSE_FILE" "$BACKUP_FILE"
}
# Get the current auth status for a service
get_auth_status() {
local service=$1
# Check if the service has authelia-auth middleware
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
# Service has middlewares, but no authelia-auth
echo "disabled"
else
echo "unknown"
fi
}
# Enable authentication for a service
enable_auth() {
local service=$1
echo -e "${BLUE}Enabling authentication for $service...${NC}"
# Check if the service exists in the compose file
if ! grep -q "container_name: $service" "$COMPOSE_FILE"; then
echo -e "${RED}Service $service not found in $COMPOSE_FILE${NC}"
return 1
fi
# Update the middlewares configuration
# This is a bit complex because different services have different middleware configurations
# We need to find the existing middlewares line and add authelia-auth if it doesn't exist
# First, find the service section
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
# Find the next service or EOF
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
# Extract the service section
local service_section=$(sed -n "${service_start},${next_service}p" "$COMPOSE_FILE")
# Find if there's a middlewares line
if echo "$service_section" | grep -q "traefik.http.routers.$service.middlewares="; then
# Get the middlewares line
local middlewares_line=$(echo "$service_section" | grep "traefik.http.routers.$service.middlewares=")
# Check if authelia-auth is already in the middlewares
if echo "$middlewares_line" | grep -q "authelia-auth@docker"; then
echo -e "${GREEN}Authentication already enabled for $service${NC}"
return 0
fi
# Add authelia-auth to the middlewares
# Different patterns depending on what's in the middlewares line
if echo "$middlewares_line" | grep -q "middlewares=$"; then
# Empty middlewares
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
# Already has some middleware with @docker
sed -i "s|traefik.http.routers.$service.middlewares=\(.*\)@docker|traefik.http.routers.$service.middlewares=\1,authelia-auth@docker|" "$COMPOSE_FILE"
else
# Has middlewares but no @docker suffix
sed -i "s|traefik.http.routers.$service.middlewares=\(.*\)|traefik.http.routers.$service.middlewares=\1,authelia-auth@docker|" "$COMPOSE_FILE"
fi
else
# No middlewares line, add one
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
# Insert the middlewares line after the rule line
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 authentication for a service
disable_auth() {
local service=$1
echo -e "${BLUE}Disabling authentication for $service...${NC}"
# Check if the service exists in the compose file
if ! grep -q "container_name: $service" "$COMPOSE_FILE"; then
echo -e "${RED}Service $service not found in $COMPOSE_FILE${NC}"
return 1
fi
# Update the middlewares configuration by removing authelia-auth
# First, find if there's a middlewares line with authelia-auth
if grep -q "traefik.http.routers.$service.middlewares=.*authelia-auth@docker" "$COMPOSE_FILE"; then
# Simple case: only authelia-auth
if grep -q "traefik.http.routers.$service.middlewares=authelia-auth@docker" "$COMPOSE_FILE"; then
# Remove authelia-auth@docker, leaving only the label prefix
sed -i "s|traefik.http.routers.$service.middlewares=authelia-auth@docker|traefik.http.routers.$service.middlewares=|" "$COMPOSE_FILE"
# authelia-auth is at the beginning with a comma
elif grep -q "traefik.http.routers.$service.middlewares=authelia-auth@docker," "$COMPOSE_FILE"; then
# Remove authelia-auth@docker,
sed -i "s|traefik.http.routers.$service.middlewares=authelia-auth@docker,|traefik.http.routers.$service.middlewares=|" "$COMPOSE_FILE"
# authelia-auth is at the end with a comma before it
elif grep -q "traefik.http.routers.$service.middlewares=.*,authelia-auth@docker" "$COMPOSE_FILE"; then
# Remove ,authelia-auth@docker
sed -i "s|,authelia-auth@docker||" "$COMPOSE_FILE"
# authelia-auth is in the middle
elif grep -q "traefik.http.routers.$service.middlewares=.*,authelia-auth@docker,.*" "$COMPOSE_FILE"; then
# Remove ,authelia-auth@docker
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}"
fi
return 0
}
# List services and their auth status
list_services() {
print_header "Services Authentication Status"
echo -e "${BLUE}Checking services in $COMPOSE_FILE...${NC}"
echo -e "${CYAN}SERVICE\t\tAUTH STATUS${NC}"
echo -e "${CYAN}-------\t\t-----------${NC}"
# Find all container names
local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}')
for service in $services; do
# Skip infrastructure containers
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
continue
fi
local status=$(get_auth_status "$service")
# Pad service name for better formatting
printf "${BOLD}%-20s${NC}" "$service"
case "$status" in
"enabled")
echo -e "${GREEN}Enabled${NC}"
;;
"disabled")
echo -e "${YELLOW}Disabled${NC}"
;;
*)
echo -e "${RED}Unknown${NC}"
;;
esac
done
}
# Display help
show_help() {
print_header "Authentication Management Script"
echo -e "Usage: $0 [options]"
echo -e ""
echo -e "Options:"
echo -e " ${CYAN}list${NC} List all services and their auth status"
echo -e " ${CYAN}enable <service>${NC} Enable authentication for a service"
echo -e " ${CYAN}disable <service>${NC} Disable authentication for a service"
echo -e " ${CYAN}enable-all${NC} Enable authentication for all services"
echo -e " ${CYAN}disable-all${NC} Disable authentication for all services"
echo -e " ${CYAN}help${NC} Show this help message"
echo -e ""
echo -e "Examples:"
echo -e " $0 list"
echo -e " $0 enable jellyfin"
echo -e " $0 disable homepage"
echo -e " $0 enable-all"
echo -e ""
}
# Main function
main() {
if [ $# -eq 0 ]; then
show_help
exit 0
fi
# Create backup of compose file
create_backup
case "$1" in
"list")
list_services
;;
"enable")
if [ -z "$2" ]; then
echo -e "${RED}Error: No service specified${NC}"
echo -e "Usage: $0 enable <service>"
exit 1
fi
enable_auth "$2"
;;
"disable")
if [ -z "$2" ]; then
echo -e "${RED}Error: No service specified${NC}"
echo -e "Usage: $0 disable <service>"
exit 1
fi
disable_auth "$2"
;;
"enable-all")
print_header "Enabling Authentication for All Services"
local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}')
for service in $services; do
# Skip infrastructure containers
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
continue
fi
enable_auth "$service"
done
;;
"disable-all")
print_header "Disabling Authentication for All Services"
local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}')
for service in $services; do
# Skip infrastructure containers
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
continue
fi
disable_auth "$service"
done
;;
"help")
show_help
;;
*)
echo -e "${RED}Error: Unknown command: $1${NC}"
show_help
exit 1
;;
esac
echo -e "\n${GREEN}${BOLD}Done!${NC}"
echo -e "${BLUE}Original configuration backed up to: $BACKUP_FILE${NC}"
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}"
}
main "$@"