feat(auth): Enhance authentication management with yq support for YAML parsing
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
a74707dc1f
commit
f4409eb258
248
update-setup.sh
248
update-setup.sh
@ -31,6 +31,16 @@ AUTHELIA_CONFIG_BACKUP="authelia/configuration.${TIMESTAMP}.bak"
|
||||
COMPOSE_FILE="docker-compose.yml"
|
||||
COMPOSE_BACKUP="docker-compose.${TIMESTAMP}.bak"
|
||||
|
||||
# Check if yq is installed
|
||||
check_yq() {
|
||||
if ! command -v yq &> /dev/null; then
|
||||
echo -e "${YELLOW}Warning: 'yq' is not installed. While not required, it provides better YAML handling.${NC}"
|
||||
echo -e "${YELLOW}Installation instructions: https://github.com/mikefarah/yq#install${NC}"
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
# Print section header
|
||||
print_header() {
|
||||
echo -e "\n${CYAN}${BOLD}$1${NC}"
|
||||
@ -368,14 +378,31 @@ generate_passphrase() {
|
||||
# PART 4: Authentication Management
|
||||
##################################################
|
||||
|
||||
# Get the current auth status for a service
|
||||
get_auth_status() {
|
||||
local service=$1
|
||||
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"
|
||||
|
||||
# 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
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
else
|
||||
echo "unknown"
|
||||
# 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"
|
||||
else
|
||||
echo "unknown"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
@ -383,6 +410,66 @@ 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
|
||||
@ -443,6 +530,63 @@ disable_auth() {
|
||||
local service=$1
|
||||
echo -e "${BLUE}Disabling authentication for $service...${NC}"
|
||||
|
||||
# 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}"
|
||||
return 1
|
||||
@ -473,39 +617,91 @@ disable_auth() {
|
||||
list_services() {
|
||||
print_header "Services Authentication Status"
|
||||
|
||||
# Check if file exists
|
||||
if ! check_file "$COMPOSE_FILE"; then
|
||||
echo -e "${RED}Error: $COMPOSE_FILE doesn't exist${NC}"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Show a warning if we're not creating a backup for this operation
|
||||
echo -e "${BLUE}Checking services in $COMPOSE_FILE...${NC}"
|
||||
echo -e "${CYAN}SERVICE\t\tAUTH STATUS${NC}"
|
||||
echo -e "${CYAN}-------\t\t-----------${NC}"
|
||||
|
||||
local services=$(grep "container_name:" "$COMPOSE_FILE" | awk '{print $3}')
|
||||
local service_count=0
|
||||
|
||||
for service in $services; do
|
||||
if [[ "$service" == "redis" || "$service" == "authelia" || "$service" == "traefik" || "$service" == "tailscale" || "$service" == "watchtower" || "$service" == "autoheal" || "$service" == "middlewares" ]]; then
|
||||
continue
|
||||
fi
|
||||
# Use yq if available for more reliable parsing
|
||||
if command -v yq &> /dev/null; then
|
||||
# Get all services from the docker-compose.yml file
|
||||
local services=$(yq e '.services | keys | .[]' "$COMPOSE_FILE" 2>/dev/null)
|
||||
|
||||
local status=$(get_auth_status "$service")
|
||||
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
|
||||
|
||||
printf "${BOLD}%-20s${NC}" "$service"
|
||||
# Check if this service has Traefik router configured
|
||||
local has_router=$(yq e ".services.$service.labels[] | select(contains(\"traefik.http.routers.$service\"))" "$COMPOSE_FILE" 2>/dev/null)
|
||||
if [ -n "$has_router" ]; then
|
||||
local status=$(get_auth_status "$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
|
||||
done
|
||||
# Format the output with padding
|
||||
printf "${BOLD}%-20s${NC}" "$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
|
||||
else
|
||||
# Fallback to using grep for parsing (less reliable)
|
||||
# First identify 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
|
||||
|
||||
# Look specifically for router configuration for this service
|
||||
if grep -q "traefik.http.routers.$service" "$COMPOSE_FILE"; then
|
||||
local status=$(get_auth_status "$service")
|
||||
|
||||
printf "${BOLD}%-20s${NC}" "$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
|
||||
fi
|
||||
|
||||
if [ $service_count -eq 0 ]; then
|
||||
echo -e "${YELLOW}No services found with authentication status.${NC}"
|
||||
echo -e "${YELLOW}This could indicate that no services are configured with Traefik routers,${NC}"
|
||||
echo -e "${YELLOW}or that the compose file has an unexpected structure.${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user