498 lines
14 KiB
Bash
498 lines
14 KiB
Bash
![]() |
#!/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 "$@"
|