Add comprehensive encrypted environment variable system with AES-256 encryption. Security Features: - AES-256-CBC encryption with PBKDF2 (100k iterations) - Root-only encryption key (/root/.tilbudgivern-secure/) - Encrypted .env.enc files safe to commit to git - Plaintext .env files only exist at runtime - Auto-cleanup on shutdown Components: - setup-encrypted-env.sh: Encrypt .env → .env.enc - decrypt-env.sh: Decrypt .env.enc → .env - start-secure.sh: Decrypt + start application - test-encryption.sh: Test encryption/decryption - tilbudgivern-secure.service: Systemd service Documentation: - ENCRYPTED_ENV_README.md: Overview and quick start - ENCRYPTED_ENV_QUICKSTART.md: Quick reference guide - docs/ENCRYPTED_ENV_SECURITY.md: Complete security guide Threat Model: ✅ User account compromise: Credentials safe ✅ Git repository leak: Only encrypted files exposed ✅ File system read: Encrypted files useless ❌ Root compromise: Defense in depth This ensures attackers need root access to decrypt credentials.
219 lines
6.1 KiB
Bash
Executable File
219 lines
6.1 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
################################################################################
|
|
# Environment Decryption Script
|
|
#
|
|
# This script decrypts .env.enc files for application use.
|
|
# Must be run as root to access the encryption key.
|
|
#
|
|
# Usage:
|
|
# sudo ./decrypt-env.sh # Decrypt all
|
|
# sudo ./decrypt-env.sh backend # Decrypt backend only
|
|
# sudo ./decrypt-env.sh --temp # Decrypt to /tmp (auto-cleanup)
|
|
################################################################################
|
|
|
|
set -e # Exit on error
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
SECURE_DIR="/root/.tilbudgivern-secure"
|
|
KEY_FILE="$SECURE_DIR/encryption.key"
|
|
|
|
# Colors
|
|
RED='\033[0;31m'
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
NC='\033[0m'
|
|
|
|
USE_TEMP=false
|
|
TARGET_ENV=""
|
|
|
|
log_info() {
|
|
echo -e "${GREEN}[INFO]${NC} $1"
|
|
}
|
|
|
|
log_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
|
}
|
|
|
|
log_error() {
|
|
echo -e "${RED}[ERROR]${NC} $1"
|
|
}
|
|
|
|
check_root() {
|
|
if [[ $EUID -ne 0 ]]; then
|
|
log_error "This script must be run as root"
|
|
echo "Please run: sudo $0 $*"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
check_key_exists() {
|
|
if [[ ! -f "$KEY_FILE" ]]; then
|
|
log_error "Encryption key not found: $KEY_FILE"
|
|
log_error "Please run setup-encrypted-env.sh first"
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
decrypt_env_file() {
|
|
local encrypted_file=$1
|
|
local decrypted_file="${encrypted_file%.enc}"
|
|
local app_user=${2:-"alex"} # Default to alex, can be overridden
|
|
|
|
if [[ ! -f "$encrypted_file" ]]; then
|
|
log_warn "Encrypted file not found: $encrypted_file (skipping)"
|
|
return
|
|
fi
|
|
|
|
log_info "Decrypting: $encrypted_file"
|
|
|
|
# Decrypt using AES-256-CBC
|
|
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 \
|
|
-in "$encrypted_file" \
|
|
-out "$decrypted_file" \
|
|
-pass file:"$KEY_FILE"
|
|
|
|
# Set permissions for application user
|
|
chmod 600 "$decrypted_file"
|
|
chown "$app_user:$app_user" "$decrypted_file"
|
|
|
|
log_info "Created: $decrypted_file (owned by $app_user)"
|
|
}
|
|
|
|
decrypt_to_temp() {
|
|
local encrypted_file=$1
|
|
local basename=$(basename "$encrypted_file" .enc)
|
|
local temp_file="/tmp/$basename.$$"
|
|
|
|
if [[ ! -f "$encrypted_file" ]]; then
|
|
log_warn "Encrypted file not found: $encrypted_file (skipping)"
|
|
return
|
|
fi
|
|
|
|
log_info "Decrypting to temp: $temp_file"
|
|
|
|
openssl enc -d -aes-256-cbc -pbkdf2 -iter 100000 \
|
|
-in "$encrypted_file" \
|
|
-out "$temp_file" \
|
|
-pass file:"$KEY_FILE"
|
|
|
|
chmod 600 "$temp_file"
|
|
|
|
echo "$temp_file"
|
|
}
|
|
|
|
cleanup_decrypted_files() {
|
|
log_info "Cleaning up decrypted .env files..."
|
|
|
|
local env_files=(
|
|
"$PROJECT_ROOT/backend/.env"
|
|
"$PROJECT_ROOT/frontend/.env"
|
|
"$PROJECT_ROOT/frontend/.env.production"
|
|
"$PROJECT_ROOT/_config/.env.ordrestyring"
|
|
)
|
|
|
|
for env_file in "${env_files[@]}"; do
|
|
if [[ -f "$env_file" ]]; then
|
|
shred -u "$env_file" 2>/dev/null || rm -f "$env_file"
|
|
log_info "Removed: $env_file"
|
|
fi
|
|
done
|
|
}
|
|
|
|
parse_args() {
|
|
while [[ $# -gt 0 ]]; do
|
|
case $1 in
|
|
--temp)
|
|
USE_TEMP=true
|
|
shift
|
|
;;
|
|
--cleanup)
|
|
check_root
|
|
cleanup_decrypted_files
|
|
exit 0
|
|
;;
|
|
backend|frontend|config)
|
|
TARGET_ENV=$1
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
echo "Usage: $0 [OPTIONS] [TARGET]"
|
|
echo ""
|
|
echo "OPTIONS:"
|
|
echo " --temp Decrypt to /tmp instead of original location"
|
|
echo " --cleanup Remove all decrypted .env files"
|
|
echo " -h, --help Show this help message"
|
|
echo ""
|
|
echo "TARGET:"
|
|
echo " backend Decrypt only backend/.env"
|
|
echo " frontend Decrypt only frontend/.env files"
|
|
echo " config Decrypt only config files"
|
|
echo " (none) Decrypt all files"
|
|
exit 0
|
|
;;
|
|
*)
|
|
log_error "Unknown option: $1"
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
}
|
|
|
|
main() {
|
|
parse_args "$@"
|
|
|
|
log_info "Starting environment decryption..."
|
|
|
|
check_root
|
|
check_key_exists
|
|
|
|
# Determine which files to decrypt
|
|
declare -A FILES_TO_DECRYPT
|
|
|
|
case "$TARGET_ENV" in
|
|
backend)
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/backend/.env.enc"]="backend"
|
|
;;
|
|
frontend)
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/frontend/.env.enc"]="frontend"
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/frontend/.env.production.enc"]="frontend"
|
|
;;
|
|
config)
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/_config/.env.ordrestyring.enc"]="config"
|
|
;;
|
|
*)
|
|
# Decrypt all
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/backend/.env.enc"]="backend"
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/frontend/.env.enc"]="frontend"
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/frontend/.env.production.enc"]="frontend"
|
|
FILES_TO_DECRYPT["$PROJECT_ROOT/_config/.env.ordrestyring.enc"]="config"
|
|
;;
|
|
esac
|
|
|
|
if [[ "$USE_TEMP" == true ]]; then
|
|
log_info "Decrypting to temporary files..."
|
|
for encrypted_file in "${!FILES_TO_DECRYPT[@]}"; do
|
|
temp_file=$(decrypt_to_temp "$encrypted_file")
|
|
if [[ -n "$temp_file" ]]; then
|
|
echo "export ENV_FILE_${FILES_TO_DECRYPT[$encrypted_file]^^}='$temp_file'"
|
|
fi
|
|
done
|
|
else
|
|
log_info "Decrypting to original locations..."
|
|
for encrypted_file in "${!FILES_TO_DECRYPT[@]}"; do
|
|
decrypt_env_file "$encrypted_file" "alex"
|
|
done
|
|
|
|
echo ""
|
|
log_info "✅ Decryption complete!"
|
|
echo ""
|
|
log_warn "SECURITY REMINDER:"
|
|
echo " - Decrypted .env files are in place"
|
|
echo " - They are owned by the application user"
|
|
echo " - Run with --cleanup when done testing"
|
|
fi
|
|
}
|
|
|
|
main "$@"
|