#!/bin/bash # # Credential Rotation Script # # Per DoD/MilSpec requirements (NIST SP 800-53: SC-12, IA-5) # This script assists with rotating credentials across the system # # Usage: # ./scripts/rotate-credentials.sh [credential-type] # # Credential types: # - jwt: JWT signing secret # - db: Database password # - keycloak: Keycloak client secret # - proxmox: Proxmox API tokens # - all: Rotate all credentials # set -euo pipefail # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # Generate a secure random secret generate_secret() { local length=${1:-64} openssl rand -base64 $length | tr -d '\n' | head -c $length } # Rotate JWT secret rotate_jwt_secret() { log_info "Rotating JWT secret..." local new_secret=$(generate_secret 64) # Update in environment or secret management system if [ -f .env ]; then if grep -q "^JWT_SECRET=" .env; then sed -i.bak "s/^JWT_SECRET=.*/JWT_SECRET=${new_secret}/" .env log_info "Updated JWT_SECRET in .env (backup created: .env.bak)" else echo "JWT_SECRET=${new_secret}" >> .env log_info "Added JWT_SECRET to .env" fi else log_warn ".env file not found. Please set JWT_SECRET=${new_secret} manually" fi # If using Kubernetes secrets if command -v kubectl &> /dev/null; then log_info "Updating Kubernetes secret..." kubectl create secret generic jwt-secret \ --from-literal=secret="${new_secret}" \ --dry-run=client -o yaml | kubectl apply -f - fi log_warn "IMPORTANT: Restart all services using JWT_SECRET after rotation" log_warn "All existing JWT tokens will be invalidated" } # Rotate database password rotate_db_password() { log_info "Rotating database password..." local new_password=$(generate_secret 32) # Update in environment if [ -f .env ]; then if grep -q "^DB_PASSWORD=" .env; then sed -i.bak "s/^DB_PASSWORD=.*/DB_PASSWORD=${new_password}/" .env log_info "Updated DB_PASSWORD in .env (backup created: .env.bak)" else echo "DB_PASSWORD=${new_password}" >> .env log_info "Added DB_PASSWORD to .env" fi else log_warn ".env file not found. Please set DB_PASSWORD=${new_password} manually" fi # Update database password log_warn "IMPORTANT: You must update the database password manually:" log_warn " ALTER USER postgres WITH PASSWORD '${new_password}';" # If using Kubernetes secrets if command -v kubectl &> /dev/null; then log_info "Updating Kubernetes secret..." kubectl create secret generic db-credentials \ --from-literal=password="${new_password}" \ --dry-run=client -o yaml | kubectl apply -f - fi } # Rotate Keycloak client secret rotate_keycloak_secret() { log_info "Rotating Keycloak client secret..." local new_secret=$(generate_secret 32) if [ -f .env ]; then if grep -q "^KEYCLOAK_CLIENT_SECRET=" .env; then sed -i.bak "s/^KEYCLOAK_CLIENT_SECRET=.*/KEYCLOAK_CLIENT_SECRET=${new_secret}/" .env log_info "Updated KEYCLOAK_CLIENT_SECRET in .env (backup created: .env.bak)" else echo "KEYCLOAK_CLIENT_SECRET=${new_secret}" >> .env log_info "Added KEYCLOAK_CLIENT_SECRET to .env" fi else log_warn ".env file not found. Please set KEYCLOAK_CLIENT_SECRET=${new_secret} manually" fi log_warn "IMPORTANT: Update Keycloak client secret in Keycloak admin console" log_warn "All existing Keycloak sessions will be invalidated" } # Rotate Proxmox API tokens rotate_proxmox_tokens() { log_info "Rotating Proxmox API tokens..." log_warn "Proxmox API tokens must be rotated manually:" log_warn "1. Log into Proxmox web interface" log_warn "2. Go to Datacenter -> Permissions -> API Tokens" log_warn "3. Revoke old tokens and create new ones" log_warn "4. Update tokens in Kubernetes secrets or configuration" # If using Kubernetes secrets if command -v kubectl &> /dev/null; then log_info "To update Kubernetes secret after creating new token:" log_info " kubectl create secret generic proxmox-credentials \\" log_info " --from-literal=credentials.json='{\"username\":\"root@pam\",\"token\":\"NEW_TOKEN\"}' \\" log_info " --dry-run=client -o yaml | kubectl apply -f -" fi } # Main function main() { local credential_type=${1:-all} log_info "Starting credential rotation (DoD/MilSpec compliance)" log_info "Credential type: ${credential_type}" case "${credential_type}" in jwt) rotate_jwt_secret ;; db|database) rotate_db_password ;; keycloak) rotate_keycloak_secret ;; proxmox) rotate_proxmox_tokens ;; all) log_info "Rotating all credentials..." rotate_jwt_secret echo "" rotate_db_password echo "" rotate_keycloak_secret echo "" rotate_proxmox_tokens ;; *) log_error "Unknown credential type: ${credential_type}" echo "Usage: $0 [jwt|db|keycloak|proxmox|all]" exit 1 ;; esac log_info "Credential rotation complete" log_warn "Remember to:" log_warn " 1. Restart all affected services" log_warn " 2. Verify services are working correctly" log_warn " 3. Update any documentation with new rotation date" log_warn " 4. Archive old credentials securely (if required by policy)" } # Run main function main "$@"