Files
HomeAudit/migration_scripts/scripts/setup_secrets_management.sh
2025-08-24 11:13:39 -04:00

621 lines
18 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# Setup Secrets Management
# This script implements Docker secrets and environment-based configuration
set -euo pipefail
echo "🔐 Setting up secrets management..."
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Function to print colored output
print_status() {
echo -e "${GREEN}[INFO]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
print_step() {
echo -e "${BLUE}[STEP]${NC} $1"
}
# Configuration
MANAGER_HOST="omv800"
SECRETS_DIR="/opt/migration/secrets"
CONFIG_DIR="/opt/migration/configs"
ENV_FILE="/opt/migration/.env"
# 1. Create secrets directory with proper permissions
print_step "Step 1: Creating secrets directory structure..."
mkdir -p "$SECRETS_DIR/generated"
mkdir -p "$SECRETS_DIR/templates"
chmod 700 "$SECRETS_DIR"
chmod 700 "$SECRETS_DIR/generated"
# 2. Generate strong passwords and keys
print_step "Step 2: Generating secure passwords and keys..."
# Function to generate secure passwords
generate_password() {
openssl rand -base64 32 | tr -d "=+/" | cut -c1-25
}
# Generate passwords
TRAEFIK_ADMIN_PASSWORD=$(generate_password)
TRAEFIK_MIGRATION_PASSWORD=$(generate_password)
POSTGRES_PASSWORD=$(generate_password)
REDIS_PASSWORD=$(generate_password)
JWT_SECRET=$(openssl rand -base64 64 | tr -d "=+/")
# Generate htpasswd hashes
TRAEFIK_ADMIN_HASH=$(htpasswd -nbB admin "$TRAEFIK_ADMIN_PASSWORD" | cut -d: -f2)
TRAEFIK_MIGRATION_HASH=$(htpasswd -nbB migration "$TRAEFIK_MIGRATION_PASSWORD" | cut -d: -f2)
print_status "Generated secure passwords and hashes"
# 3. Create environment configuration file
print_step "Step 3: Creating environment configuration..."
cat > "$ENV_FILE" << EOF
# Migration Environment Configuration
# Generated: $(date)
# IMPORTANT: This file contains sensitive information - do not commit to version control
# Domain Configuration
DOMAIN=homelab.local
EMAIL=admin@homelab.local
TIMEZONE=America/New_York
# Network Configuration
MANAGER_HOST=omv800
MANAGER_IP=192.168.50.229
# Database Configuration
POSTGRES_USER=postgres
POSTGRES_DB=migration_db
REDIS_USER=default
# SSL Configuration
SSL_KEY_SIZE=4096
SSL_COUNTRY=US
SSL_STATE=State
SSL_CITY=City
SSL_ORG=HomeLab
SSL_OU=IT
# Monitoring Configuration
GRAFANA_ADMIN_USER=admin
PROMETHEUS_RETENTION=30d
# Backup Configuration
BACKUP_RETENTION_DAYS=30
BACKUP_COMPRESSION=gzip
# Security Configuration
SESSION_TIMEOUT=3600
MAX_LOGIN_ATTEMPTS=5
LOCKOUT_DURATION=900
# Feature Flags
ENABLE_METRICS=true
ENABLE_DEBUG=false
ENABLE_TRACING=false
EOF
# Add sensitive values (these will be moved to Docker secrets)
cat >> "$ENV_FILE" << EOF
# Sensitive Configuration (will be moved to Docker secrets)
TRAEFIK_ADMIN_PASSWORD=$TRAEFIK_ADMIN_PASSWORD
TRAEFIK_MIGRATION_PASSWORD=$TRAEFIK_MIGRATION_PASSWORD
POSTGRES_PASSWORD=$POSTGRES_PASSWORD
REDIS_PASSWORD=$REDIS_PASSWORD
JWT_SECRET=$JWT_SECRET
EOF
chmod 600 "$ENV_FILE"
print_status "Environment configuration created: $ENV_FILE"
# 4. Create Docker secrets
print_step "Step 4: Creating Docker secrets..."
# Create secret files
echo -n "$TRAEFIK_ADMIN_PASSWORD" > "$SECRETS_DIR/generated/traefik_admin_password"
echo -n "$TRAEFIK_MIGRATION_PASSWORD" > "$SECRETS_DIR/generated/traefik_migration_password"
echo -n "$POSTGRES_PASSWORD" > "$SECRETS_DIR/generated/postgres_password"
echo -n "$REDIS_PASSWORD" > "$SECRETS_DIR/generated/redis_password"
echo -n "$JWT_SECRET" > "$SECRETS_DIR/generated/jwt_secret"
# Create users file for Traefik
cat > "$SECRETS_DIR/generated/traefik_users" << EOF
admin:\$2y\$10\$$TRAEFIK_ADMIN_HASH
migration:\$2y\$10\$$TRAEFIK_MIGRATION_HASH
EOF
# Set proper permissions
chmod 600 "$SECRETS_DIR"/generated/*
# Deploy secrets to Docker Swarm
ssh "$MANAGER_HOST" "docker secret rm traefik_admin_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm traefik_migration_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm postgres_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm redis_password 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm jwt_secret 2>/dev/null || true"
ssh "$MANAGER_HOST" "docker secret rm traefik_users 2>/dev/null || true"
# Copy secrets to manager and create Docker secrets
scp "$SECRETS_DIR/generated/traefik_admin_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/traefik_migration_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/postgres_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/redis_password" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/jwt_secret" "$MANAGER_HOST:/tmp/"
scp "$SECRETS_DIR/generated/traefik_users" "$MANAGER_HOST:/tmp/"
ssh "$MANAGER_HOST" "docker secret create traefik_admin_password /tmp/traefik_admin_password"
ssh "$MANAGER_HOST" "docker secret create traefik_migration_password /tmp/traefik_migration_password"
ssh "$MANAGER_HOST" "docker secret create postgres_password /tmp/postgres_password"
ssh "$MANAGER_HOST" "docker secret create redis_password /tmp/redis_password"
ssh "$MANAGER_HOST" "docker secret create jwt_secret /tmp/jwt_secret"
ssh "$MANAGER_HOST" "docker secret create traefik_users /tmp/traefik_users"
# Clean up temporary files on manager
ssh "$MANAGER_HOST" "rm -f /tmp/traefik_admin_password /tmp/traefik_migration_password /tmp/postgres_password /tmp/redis_password /tmp/jwt_secret /tmp/traefik_users"
print_status "Docker secrets created successfully"
# 5. Create secure configuration templates
print_step "Step 5: Creating secure configuration templates..."
# Updated Traefik configuration template
cat > "$SECRETS_DIR/templates/traefik-secure.yml" << 'EOF'
version: '3.8'
services:
traefik:
image: traefik:v3.0
command:
# API and dashboard
- --api.dashboard=true
- --api.insecure=false
# Docker provider
- --providers.docker.swarmMode=true
- --providers.docker.exposedbydefault=false
- --providers.docker.network=traefik-public
# Entry points
- --entrypoints.web.address=:80
- --entrypoints.websecure.address=:443
- --entrypoints.web.http.redirections.entrypoint.to=websecure
- --entrypoints.web.http.redirections.entrypoint.scheme=https
# SSL/TLS configuration
- --certificatesresolvers.letsencrypt.acme.email=${EMAIL}
- --certificatesresolvers.letsencrypt.acme.storage=/certificates/acme.json
- --certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web
# Security
- --global.sendanonymoususage=false
- --global.checknewversion=false
# Logging
- --log.level=INFO
- --log.format=json
- --accesslog=true
- --accesslog.filepath=/var/log/traefik/access.log
- --accesslog.format=json
# Metrics
- --metrics.prometheus=true
- --metrics.prometheus.addEntryPointsLabels=true
- --metrics.prometheus.addServicesLabels=true
# Health checks
- --ping=true
- --ping.entryPoint=web
# File provider for static configuration
- --providers.file.directory=/etc/traefik/dynamic
- --providers.file.watch=true
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- traefik-certificates:/certificates
- traefik-logs:/var/log/traefik
- ./dynamic:/etc/traefik/dynamic:ro
secrets:
- traefik_users
networks:
- traefik-public
environment:
- DOMAIN=${DOMAIN}
- EMAIL=${EMAIL}
deploy:
placement:
constraints:
- node.role == manager
replicas: 2
resources:
limits:
memory: 512M
cpus: '0.5'
reservations:
memory: 256M
cpus: '0.25'
labels:
# Traefik dashboard with secret-based auth
- "traefik.enable=true"
- "traefik.http.routers.traefik-dashboard.rule=Host(`traefik.${DOMAIN}`)"
- "traefik.http.routers.traefik-dashboard.entrypoints=websecure"
- "traefik.http.routers.traefik-dashboard.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik-dashboard.service=api@internal"
- "traefik.http.routers.traefik-dashboard.middlewares=auth-secure@file"
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s
secrets:
traefik_users:
external: true
volumes:
traefik-certificates:
driver: local
traefik-logs:
driver: local
networks:
traefik-public:
external: true
EOF
# Updated middleware configuration with secrets
cat > "$SECRETS_DIR/templates/middleware-secure.yml" << 'EOF'
# Traefik Dynamic Configuration - Secure Middleware
# Uses Docker secrets for authentication
http:
middlewares:
# Secure authentication middleware using Docker secrets
auth-secure:
basicAuth:
usersFile: "/run/secrets/traefik_users"
removeHeader: true
realm: "HomeLabSecure"
# Enhanced security headers
security-headers-enhanced:
headers:
# Security headers
frameDeny: true
sslRedirect: true
browserXssFilter: true
contentTypeNosniff: true
forceSTSHeader: true
sslForceHost: true
stsIncludeSubdomains: true
stsPreload: true
stsSeconds: 63072000 # 2 years
customFrameOptionsValue: "SAMEORIGIN"
customRequestHeaders:
X-Forwarded-Proto: "https"
customResponseHeaders:
X-Robots-Tag: "none"
X-Content-Type-Options: "nosniff"
X-Frame-Options: "SAMEORIGIN"
X-XSS-Protection: "1; mode=block"
Referrer-Policy: "strict-origin-when-cross-origin"
Permissions-Policy: "camera=(), microphone=(), geolocation=(), payment=()"
Content-Security-Policy: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
# Stricter rate limiting for production
rate-limit-strict:
rateLimit:
burst: 20
average: 10
period: "1s"
sourceCriterion:
ipStrategy:
depth: 1
# IP whitelist for admin interfaces
ip-whitelist-strict:
ipWhiteList:
sourceRange:
- "192.168.50.0/24" # Local network only
ipStrategy:
depth: 1
excludedIPs:
- "127.0.0.1"
EOF
print_status "Secure configuration templates created"
# 6. Create script to update existing configurations
print_step "Step 6: Creating configuration update script..."
cat > "/opt/migration/scripts/update_configurations.sh" << 'EOF'
#!/bin/bash
# Update existing configurations to use secrets management
set -euo pipefail
# Load environment variables
source /opt/migration/.env
echo "🔧 Updating configurations to use secrets management..."
# Update Traefik deployment
echo "Updating Traefik configuration..."
envsubst < /opt/migration/secrets/templates/traefik-secure.yml > /opt/migration/configs/traefik/docker-compose-secure.yml
# Update middleware configuration
cp /opt/migration/secrets/templates/middleware-secure.yml /opt/migration/configs/traefik/dynamic/middleware-secure.yml
# Create deployment script with secrets
cat > /opt/migration/scripts/deploy_traefik_secure.sh << 'SCRIPT_EOF'
#!/bin/bash
# Deploy Traefik with secrets management
set -euo pipefail
source /opt/migration/.env
echo "🌐 Deploying Traefik with secrets management..."
cd /opt/migration/configs/traefik
docker stack deploy -c docker-compose-secure.yml traefik-secure
echo "✅ Traefik deployed with secrets management"
SCRIPT_EOF
chmod +x /opt/migration/scripts/deploy_traefik_secure.sh
echo "✅ Configurations updated successfully"
EOF
chmod +x "/opt/migration/scripts/update_configurations.sh"
# 7. Create secrets rotation script
print_step "Step 7: Creating secrets rotation script..."
cat > "/opt/migration/scripts/rotate_secrets.sh" << 'EOF'
#!/bin/bash
# Rotate Docker secrets safely
set -euo pipefail
echo "🔄 Rotating Docker secrets..."
MANAGER_HOST="omv800"
SECRETS_DIR="/opt/migration/secrets"
# Function to rotate a secret
rotate_secret() {
local secret_name=$1
local secret_file=$2
echo "Rotating secret: $secret_name"
# Generate new secret value
case $secret_name in
"*password*")
new_value=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-25)
;;
"jwt_secret")
new_value=$(openssl rand -base64 64 | tr -d "=+/")
;;
*)
echo "Unknown secret type: $secret_name"
return 1
;;
esac
# Create new secret file
echo -n "$new_value" > "$secret_file.new"
chmod 600 "$secret_file.new"
# Create new Docker secret
ssh "$MANAGER_HOST" "docker secret create ${secret_name}_new /tmp/${secret_name}.new"
# Update services to use new secret (this would need service-specific logic)
echo "⚠️ Manual service update required for $secret_name"
# After successful deployment, remove old secret
# ssh "$MANAGER_HOST" "docker secret rm $secret_name"
# ssh "$MANAGER_HOST" "docker secret create $secret_name /tmp/${secret_name}.new"
echo "✅ Secret $secret_name rotated successfully"
}
echo "⚠️ Secret rotation requires manual service updates"
echo "Use this script as a template for implementing zero-downtime secret rotation"
EOF
chmod +x "/opt/migration/scripts/rotate_secrets.sh"
# 8. Create secrets backup script
print_step "Step 8: Creating secrets backup script..."
cat > "/opt/migration/scripts/backup_secrets.sh" << 'EOF'
#!/bin/bash
# Backup secrets securely
set -euo pipefail
echo "💾 Backing up secrets..."
BACKUP_DIR="/opt/migration/backups/secrets/$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# Backup environment file (encrypted)
gpg --cipher-algo AES256 --compress-algo 1 --s2k-mode 3 \
--s2k-digest-algo SHA512 --s2k-count 65536 --symmetric \
--output "$BACKUP_DIR/.env.gpg" /opt/migration/.env
# Backup secret files (encrypted)
tar czf - /opt/migration/secrets/generated | \
gpg --cipher-algo AES256 --compress-algo 1 --s2k-mode 3 \
--s2k-digest-algo SHA512 --s2k-count 65536 --symmetric \
--output "$BACKUP_DIR/secrets.tar.gz.gpg"
# Set secure permissions
chmod 700 "$BACKUP_DIR"
chmod 600 "$BACKUP_DIR"/*
echo "✅ Secrets backed up to: $BACKUP_DIR"
echo " Use GPG to decrypt: gpg --decrypt file.gpg"
EOF
chmod +x "/opt/migration/scripts/backup_secrets.sh"
# 9. Create validation script
print_step "Step 9: Creating secrets validation script..."
cat > "/opt/migration/scripts/validate_secrets.sh" << 'EOF'
#!/bin/bash
# Validate secrets configuration
set -euo pipefail
echo "✅ Validating secrets configuration..."
MANAGER_HOST="omv800"
ENV_FILE="/opt/migration/.env"
SECRETS_DIR="/opt/migration/secrets"
# Check if environment file exists and is readable
if [[ -r "$ENV_FILE" ]]; then
echo "✅ Environment file exists and is readable"
else
echo "❌ Environment file missing or not readable"
exit 1
fi
# Check if secrets directory has correct permissions
if [[ -d "$SECRETS_DIR" ]] && [[ $(stat -c %a "$SECRETS_DIR") == "700" ]]; then
echo "✅ Secrets directory has correct permissions"
else
echo "❌ Secrets directory permissions incorrect"
exit 1
fi
# Check if Docker secrets exist
echo "Checking Docker secrets..."
secrets=(
"traefik_admin_password"
"traefik_migration_password"
"postgres_password"
"redis_password"
"jwt_secret"
"traefik_users"
)
for secret in "${secrets[@]}"; do
if ssh "$MANAGER_HOST" "docker secret ls | grep -q $secret"; then
echo "✅ Docker secret exists: $secret"
else
echo "❌ Docker secret missing: $secret"
exit 1
fi
done
# Validate environment variables
source "$ENV_FILE"
required_vars=(
"DOMAIN"
"EMAIL"
"MANAGER_HOST"
"POSTGRES_PASSWORD"
)
for var in "${required_vars[@]}"; do
if [[ -n "${!var}" ]]; then
echo "✅ Environment variable set: $var"
else
echo "❌ Environment variable missing: $var"
exit 1
fi
done
echo "✅ All secrets validation checks passed"
EOF
chmod +x "/opt/migration/scripts/validate_secrets.sh"
# 10. Create summary
print_step "Step 10: Creating setup summary..."
cat > "/opt/migration/secrets_setup_summary.txt" << EOF
Secrets Management Setup Summary
Generated: $(date)
Files Created:
- Environment config: $ENV_FILE
- Secrets directory: $SECRETS_DIR/
- Traefik secure template: $SECRETS_DIR/templates/traefik-secure.yml
- Middleware secure template: $SECRETS_DIR/templates/middleware-secure.yml
Scripts Created:
- Update configurations: /opt/migration/scripts/update_configurations.sh
- Rotate secrets: /opt/migration/scripts/rotate_secrets.sh
- Backup secrets: /opt/migration/scripts/backup_secrets.sh
- Validate secrets: /opt/migration/scripts/validate_secrets.sh
Docker Secrets Created:
- traefik_admin_password
- traefik_migration_password
- postgres_password
- redis_password
- jwt_secret
- traefik_users
Generated Credentials:
- Traefik Admin User: admin
- Traefik Admin Password: $TRAEFIK_ADMIN_PASSWORD
- Traefik Migration User: migration
- Traefik Migration Password: $TRAEFIK_MIGRATION_PASSWORD
- PostgreSQL Password: $POSTGRES_PASSWORD
- Redis Password: $REDIS_PASSWORD
Next Steps:
1. Update .gitignore to exclude $ENV_FILE
2. Run: /opt/migration/scripts/update_configurations.sh
3. Run: /opt/migration/scripts/validate_secrets.sh
4. Deploy with: /opt/migration/scripts/deploy_traefik_secure.sh
Security Notes:
- All passwords are 25 characters with high entropy
- Secrets are stored in Docker secrets (encrypted at rest)
- Environment file has 600 permissions
- Backup scripts use GPG encryption
- Rotation scripts provided for regular updates
EOF
print_status "✅ Secrets management setup completed successfully!"
print_status "📋 Summary saved to: /opt/migration/secrets_setup_summary.txt"
echo ""
print_status "Generated credentials (SAVE THESE SECURELY):"
echo " Traefik Admin: admin / $TRAEFIK_ADMIN_PASSWORD"
echo " Traefik Migration: migration / $TRAEFIK_MIGRATION_PASSWORD"
echo ""
print_warning "Remember to:"
echo " 1. Add $ENV_FILE to .gitignore"
echo " 2. Store credentials in password manager"
echo " 3. Run validation: /opt/migration/scripts/validate_secrets.sh"