Files
Sankofa/scripts/rotate-credentials.sh

198 lines
5.9 KiB
Bash
Raw Normal View History

#!/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 "$@"