Rustelo/scripts/setup/setup_encryption.sh

498 lines
14 KiB
Bash
Raw Normal View History

2025-07-07 23:53:50 +01:00
#!/bin/bash
# Configuration Encryption Setup Script
# This script helps set up the encryption system for configuration values
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Default values
ROOT_PATH="."
CONFIG_FILE=""
INTERACTIVE=false
FORCE=false
BACKUP=true
ENVIRONMENT="production"
# Function to print colored output
print_color() {
printf "${1}${2}${NC}\n"
}
print_success() {
print_color "$GREEN" "$1"
}
print_error() {
print_color "$RED" "$1"
}
print_warning() {
print_color "$YELLOW" "$1"
}
print_info() {
print_color "$BLUE" " $1"
}
# Function to show help
show_help() {
cat << EOF
Configuration Encryption Setup Script
This script helps you set up and manage the configuration encryption system
for securing sensitive configuration values.
Usage: $0 [OPTIONS]
Options:
-h, --help Show this help message
-r, --root-path PATH Set root path for encryption key (default: .)
-c, --config FILE Configuration file to encrypt values in
-i, --interactive Run in interactive mode
-f, --force Force overwrite existing encryption key
-e, --environment ENV Environment (dev, staging, prod) (default: production)
--no-backup Don't create backups when modifying files
--verify-only Only verify existing encryption setup
Examples:
$0 # Basic setup with interactive prompts
$0 -i # Full interactive setup
$0 -c config.prod.toml # Encrypt values in specific config file
$0 -r /app --environment prod # Setup for production in /app directory
$0 --verify-only # Just verify current setup
The script will:
1. Generate encryption key if it doesn't exist
2. Help you encrypt sensitive configuration values
3. Update configuration files with encrypted values
4. Verify the encryption setup works correctly
Security Notes:
- Never commit the .k file to version control
- Use different keys for different environments
- Backup encryption keys securely
- Rotate keys regularly in production
EOF
}
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_help
exit 0
;;
-r|--root-path)
ROOT_PATH="$2"
shift 2
;;
-c|--config)
CONFIG_FILE="$2"
shift 2
;;
-i|--interactive)
INTERACTIVE=true
shift
;;
-f|--force)
FORCE=true
shift
;;
-e|--environment)
ENVIRONMENT="$2"
shift 2
;;
--no-backup)
BACKUP=false
shift
;;
--verify-only)
VERIFY_ONLY=true
shift
;;
*)
print_error "Unknown option: $1"
show_help
exit 1
;;
esac
done
# Check if we're in a Rust project
if [ ! -f "Cargo.toml" ]; then
print_error "This script must be run from the root of a Rust project"
exit 1
fi
# Check if the crypto tool is available
if ! cargo bin --list | grep -q "config_crypto_tool"; then
print_error "config_crypto_tool binary not found. Please ensure it's built:"
print_info "cargo build --bin config_crypto_tool"
exit 1
fi
# Function to check if encryption key exists
check_encryption_key() {
if [ -f "$ROOT_PATH/.k" ]; then
return 0
else
return 1
fi
}
# Function to generate encryption key
generate_encryption_key() {
print_info "Generating encryption key..."
if check_encryption_key && [ "$FORCE" = false ]; then
print_warning "Encryption key already exists at $ROOT_PATH/.k"
read -p "Do you want to overwrite it? (y/N): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_info "Keeping existing encryption key"
return 0
fi
fi
local force_flag=""
if [ "$FORCE" = true ]; then
force_flag="--force"
fi
if cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" generate-key $force_flag; then
print_success "Encryption key generated at $ROOT_PATH/.k"
# Set proper permissions
chmod 600 "$ROOT_PATH/.k"
print_success "Set secure permissions on encryption key file"
# Verify the key works
if cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" verify; then
print_success "Encryption key verification successful"
else
print_error "Encryption key verification failed"
return 1
fi
else
print_error "Failed to generate encryption key"
return 1
fi
}
# Function to encrypt a value
encrypt_value() {
local value="$1"
local description="$2"
print_info "Encrypting $description..."
if encrypted_value=$(cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" encrypt "$value" 2>/dev/null); then
echo "$encrypted_value"
return 0
else
print_error "Failed to encrypt $description"
return 1
fi
}
# Function to show common values to encrypt
show_common_values() {
cat << EOF
Common configuration values that should be encrypted:
- Database passwords
- Session secrets
- API keys (SendGrid, OAuth providers, etc.)
- SMTP passwords
- Redis URLs with credentials
- JWT secrets
- Third-party service credentials
EOF
}
# Function to encrypt values in configuration file
encrypt_config_values() {
local config_file="$1"
if [ ! -f "$config_file" ]; then
print_error "Configuration file not found: $config_file"
return 1
fi
print_info "Analyzing configuration file: $config_file"
# Create backup if requested
if [ "$BACKUP" = true ]; then
local backup_file="${config_file}.backup.$(date +%Y%m%d_%H%M%S)"
cp "$config_file" "$backup_file"
print_success "Created backup: $backup_file"
fi
# Common sensitive keys that should be encrypted
local sensitive_keys=(
"session.secret"
"database.url"
"oauth.google.client_secret"
"oauth.github.client_secret"
"email.smtp_password"
"email.sendgrid_api_key"
"redis.url"
)
print_info "Checking for sensitive values to encrypt..."
for key in "${sensitive_keys[@]}"; do
# Check if this key exists in the config and is not already encrypted
if grep -q "^${key//./\\.}" "$config_file" 2>/dev/null; then
# Extract the current value
local current_value=$(grep "^${key//./\\.}" "$config_file" | cut -d'"' -f2)
if [[ "$current_value" =~ ^\$\{.*\}$ ]]; then
print_info "Skipping $key (uses environment variable)"
continue
elif [[ "$current_value" == @* ]]; then
print_info "Skipping $key (already encrypted)"
continue
elif [ -n "$current_value" ] && [ "$current_value" != "your-secret-here" ]; then
print_warning "Found potentially sensitive value for $key"
if [ "$INTERACTIVE" = true ]; then
read -p "Encrypt this value? (y/N): " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
if encrypted_value=$(encrypt_value "$current_value" "$key"); then
# Update the configuration file
sed -i.tmp "s|^${key//./\\.}.*|${key} = \"$encrypted_value\"|" "$config_file"
rm -f "$config_file.tmp"
print_success "Encrypted $key"
fi
fi
fi
fi
fi
done
}
# Function to verify encryption setup
verify_encryption_setup() {
print_info "Verifying encryption setup..."
# Check if key exists
if ! check_encryption_key; then
print_error "Encryption key not found at $ROOT_PATH/.k"
return 1
fi
# Check key permissions
if [ "$(stat -c %a "$ROOT_PATH/.k" 2>/dev/null)" != "600" ]; then
print_warning "Encryption key file permissions are not secure"
print_info "Setting secure permissions..."
chmod 600 "$ROOT_PATH/.k"
fi
# Verify key works
if cargo run --bin config_crypto_tool -- --root-path "$ROOT_PATH" verify; then
print_success "Encryption key verification successful"
else
print_error "Encryption key verification failed"
return 1
fi
# Check if .k is in .gitignore
if [ -f ".gitignore" ]; then
if grep -q "^\.k$" ".gitignore" || grep -q "^\.k " ".gitignore"; then
print_success "Encryption key is properly ignored in .gitignore"
else
print_error "Encryption key is NOT in .gitignore - this is a security risk!"
read -p "Add .k to .gitignore? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
echo ".k" >> .gitignore
print_success "Added .k to .gitignore"
fi
fi
else
print_warning ".gitignore file not found"
fi
return 0
}
# Function to run interactive setup
run_interactive_setup() {
print_info "Starting interactive encryption setup..."
echo
# Step 1: Generate or verify encryption key
if check_encryption_key; then
print_success "Encryption key already exists"
read -p "Do you want to verify it? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
verify_encryption_setup
fi
else
print_info "No encryption key found"
read -p "Generate new encryption key? (Y/n): " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Nn]$ ]]; then
generate_encryption_key
fi
fi
echo
# Step 2: Encrypt individual values
print_info "You can now encrypt individual values:"
while true; do
read -p "Enter a value to encrypt (or 'skip' to continue): " value
if [ "$value" = "skip" ] || [ -z "$value" ]; then
break
fi
if encrypted_value=$(encrypt_value "$value" "custom value"); then
print_success "Encrypted value: $encrypted_value"
echo "Use this in your configuration file:"
echo "some_key = \"$encrypted_value\""
fi
echo
done
# Step 3: Encrypt configuration file values
if [ -n "$CONFIG_FILE" ]; then
print_info "Encrypting values in configuration file: $CONFIG_FILE"
encrypt_config_values "$CONFIG_FILE"
else
echo
print_info "Available configuration files:"
for file in config*.toml; do
if [ -f "$file" ]; then
echo " - $file"
fi
done
read -p "Enter configuration file to encrypt values in (or 'skip'): " config_file
if [ "$config_file" != "skip" ] && [ -n "$config_file" ]; then
encrypt_config_values "$config_file"
fi
fi
echo
print_success "Interactive setup completed!"
}
# Function to show security recommendations
show_security_recommendations() {
cat << EOF
${GREEN}Security Recommendations:${NC}
1. ${YELLOW}Never commit the .k file to version control${NC}
- The .k file contains your encryption key
- Add it to .gitignore immediately
- Use different keys for different environments
2. ${YELLOW}Backup your encryption keys securely${NC}
- Store backups in a secure, separate location
- Consider using encrypted backup storage
- Document your backup procedures
3. ${YELLOW}Use proper file permissions${NC}
- Key files should be readable only by the application user
- Use chmod 600 for the .k file
- Monitor file access regularly
4. ${YELLOW}Rotate keys regularly${NC}
- Consider quarterly or yearly key rotation
- Have a key rotation procedure documented
- Test key rotation in staging first
5. ${YELLOW}Monitor and audit${NC}
- Log encryption/decryption operations
- Monitor key file access
- Regular security audits
6. ${YELLOW}Environment separation${NC}
- Use different encryption keys for dev/staging/prod
- Never use production keys in development
- Secure key distribution procedures
EOF
}
# Main execution
main() {
echo
print_info "Configuration Encryption Setup Script"
print_info "Environment: $ENVIRONMENT"
print_info "Root Path: $ROOT_PATH"
echo
# Change to root path
cd "$ROOT_PATH"
# Verify-only mode
if [ "$VERIFY_ONLY" = true ]; then
verify_encryption_setup
exit $?
fi
# Interactive mode
if [ "$INTERACTIVE" = true ]; then
run_interactive_setup
echo
show_security_recommendations
exit 0
fi
# Non-interactive mode
print_info "Running automated setup..."
# Generate encryption key if it doesn't exist
if ! check_encryption_key; then
generate_encryption_key
else
print_success "Encryption key already exists"
verify_encryption_setup
fi
# Encrypt configuration file if specified
if [ -n "$CONFIG_FILE" ]; then
encrypt_config_values "$CONFIG_FILE"
fi
echo
print_success "Encryption setup completed!"
# Show next steps
cat << EOF
${GREEN}Next Steps:${NC}
1. Test your configuration: cargo run --bin config_crypto_tool verify
2. Encrypt sensitive values: cargo run --bin config_crypto_tool encrypt "your-secret"
3. Update your configuration files with encrypted values
4. Ensure .k file is in .gitignore
5. Backup your encryption key securely
${BLUE}Useful Commands:${NC}
- Encrypt value: cargo run --bin config_crypto_tool encrypt "value"
- Decrypt value: cargo run --bin config_crypto_tool decrypt "@encrypted"
- Find encrypted values: cargo run --bin config_crypto_tool find-encrypted -c config.toml
- Interactive mode: cargo run --bin config_crypto_tool interactive
EOF
show_security_recommendations
}
# Run main function
main "$@"