#!/bin/bash # Issue a new API key for the Traefik CrowdSec bouncer. # # This is the action crowdsec.config and the install script both point at when # the key is lost or should be replaced. cscli cannot re-issue a key for an # existing bouncer, so rotating means delete + re-add; the privileged helper # does both and rewrites /etc/crowdsec/traefik_bouncer.key. # # The old key stops working the instant the bouncer is deleted, and Traefik # holds the key file open — so Traefik is restarted afterwards to pick up the new # one. Between those two points requests are authenticated with a dead key, which # is why this is a deliberate action and not something the installer does on its # own. appCrowdsecRotateBouncerKey() { local app_name="crowdsec" local result result=$(runCrowdsec bouncer-traefik-rotate 2>&1) if [[ "$result" != GENERATED:* ]]; then isError "Could not rotate the Traefik bouncer key: $result" isNotice "The previous key may already have been revoked — check 'cscli bouncers list' before retrying." return 1 fi local bouncer_key="${result#GENERATED:}" isSuccessful "New Traefik bouncer API key issued." # Mirror it the same way the installer does, so the config page and the key # file agree. updateConfigOption escapes the value, writes as the owner of # the containers tree, and re-sources. local cfg_file="${containers_dir}${app_name}/${app_name}.config" if [[ -f "$cfg_file" ]]; then updateConfigOption "CFG_CROWDSEC_TRAEFIK_LAPI_KEY" "$bouncer_key" "$cfg_file" else isNotice "crowdsec.config is not deployed — the key is in /etc/crowdsec/traefik_bouncer.key only." fi # Traefik reads the key from the bind-mounted file at startup, so it keeps # presenting the revoked key until it restarts. Without this the rotation # looks successful while every bouncer check fails with 403. if [[ -d "${containers_dir}traefik" ]]; then dockerComposeRestart traefik checkSuccess "Restarting Traefik to load the new bouncer key" else isNotice "Traefik is not installed here — nothing to restart." fi }