#!/usr/bin/env bash # Rotate secrets: generate new passwords, update secrets.env, restart services. # This script does NOT automatically rotate external MySQL/Redis passwords. # It only regenerates JWT and internal tokens. For MySQL/Redis, manual rotation is required. set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" . "$ROOT_DIR/scripts/lib.sh" load_env ROTATE_JWT="${ROTATE_JWT:-false}" ROTATE_INTERNAL_TOKEN="${ROTATE_INTERNAL_TOKEN:-false}" audit "rotate-secrets" "STARTED" "jwt=$ROTATE_JWT internal_token=$ROTATE_INTERNAL_TOKEN" progress "rotate-secrets" "STARTED" "" ensure_secret_file if [ "$ROTATE_JWT" = "true" ]; then NEW_JWT="$(random_secret)$(random_secret)" set_env_value "$ROOT_DIR/config/secrets.env" "XUQM_JWT_SECRET" "$NEW_JWT" audit "rotate-secrets" "JWT_ROTATED" "new key generated" printf 'JWT secret rotated. All existing tokens will be invalidated on service restart.\n' fi if [ "$ROTATE_INTERNAL_TOKEN" = "true" ]; then NEW_TOKEN="$(random_secret)" set_env_value "$ROOT_DIR/config/secrets.env" "SDK_INTERNAL_TOKEN" "$NEW_TOKEN" set_env_value "$ROOT_DIR/config/secrets.env" "LICENSE_INTERNAL_TOKEN" "$NEW_TOKEN" audit "rotate-secrets" "INTERNAL_TOKEN_ROTATED" "" printf 'Internal tokens rotated.\n' fi # Enforce permissions on secrets.env chmod 600 "$ROOT_DIR/config/secrets.env" printf '\nIMPORTANT: restart services for new secrets to take effect:\n' printf ' docker compose --env-file .env -f docker-compose.yml -f docker-compose.infra.yml restart\n\n' printf 'MySQL/Redis password rotation must be performed manually:\n' printf ' 1. Set new password in the database\n' printf ' 2. Update MYSQL_PASSWORD / REDIS_PASSWORD in config/secrets.env\n' printf ' 3. Restart affected services\n' audit "rotate-secrets" "DONE" "" progress "rotate-secrets" "DONE" ""