#!/bin/bash
# Enable Data at Rest Encryption for Citadel
# Configures K3s API server to encrypt etcd data using AES-GCM
#
# What this encrypts:
#   - Secrets (credentials, TLS certs, tokens)
#   - ConfigMaps (application configuration)
#   - ServiceAccounts (identity tokens)
#   - PersistentVolumeClaims (storage references)
#   - CustomResourceDefinitions (CRDs)
#
# Requires: root access (modifies K3s server configuration)

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
REPO_DIR="$(dirname "${SCRIPT_DIR}")"

log() { echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*"; }
error() { echo "[ERROR] $*" >&2; }

log "Enabling data at rest encryption for Citadel..."

# Check if running as root
if [[ $EUID -ne 0 ]]; then
    error "This script must be run as root to modify K3s configuration"
    exit 1
fi

# Verify K3s is installed
if ! systemctl is-active --quiet k3s; then
    error "K3s is not running. Install K3s first with scripts/01-install-k3s.sh"
    exit 1
fi

# ----- Step 1: Generate encryption key -----
log "Step 1: Generating AES-GCM encryption key..."

ENCRYPTION_KEY=$(head -c 32 /dev/urandom | base64)
log "Encryption key generated (32 bytes, base64-encoded)"

# ----- Step 2: Deploy encryption config -----
log "Step 2: Deploying encryption configuration..."

ENCRYPTION_CONFIG_DEST="/etc/rancher/k3s/encryption-config.yaml"

# Copy template and substitute the placeholder key
cp "${REPO_DIR}/security/encryption-config.yaml" "${ENCRYPTION_CONFIG_DEST}"
sed -i "s|REPLACE_WITH_BASE64_ENCODED_32_BYTE_KEY|${ENCRYPTION_KEY}|g" "${ENCRYPTION_CONFIG_DEST}"
chmod 600 "${ENCRYPTION_CONFIG_DEST}"
chown root:root "${ENCRYPTION_CONFIG_DEST}"

log "Encryption config deployed to: ${ENCRYPTION_CONFIG_DEST}"

# ----- Step 3: Back up the encryption key -----
log "Step 3: Backing up encryption key..."

KEY_BACKUP_DIR="/etc/rancher/k3s/encryption-keys"
mkdir -p "${KEY_BACKUP_DIR}"
chmod 700 "${KEY_BACKUP_DIR}"

KEY_BACKUP_FILE="${KEY_BACKUP_DIR}/citadel-key-1.$(date +%Y%m%d%H%M%S).key"
echo "${ENCRYPTION_KEY}" > "${KEY_BACKUP_FILE}"
chmod 400 "${KEY_BACKUP_FILE}"
chown root:root "${KEY_BACKUP_FILE}"

log "Key backed up to: ${KEY_BACKUP_FILE}"
log "IMPORTANT: Copy this key to a secure off-node location (vault, HSM, etc.)"

# ----- Step 4: Configure K3s API server -----
log "Step 4: Configuring K3s API server for encryption..."

K3S_CONFIG="/etc/rancher/k3s/config.yaml"

# Backup existing config
if [[ -f "${K3S_CONFIG}" ]]; then
    cp "${K3S_CONFIG}" "${K3S_CONFIG}.backup.$(date +%Y%m%d%H%M%S)"
    log "Backed up existing K3s config"
fi

# Check if encryption-provider-config is already set
if grep -q "encryption-provider-config" "${K3S_CONFIG}" 2>/dev/null; then
    log "Encryption provider already configured in K3s config. Skipping..."
else
    # Check if kube-apiserver-arg section exists
    if grep -q "kube-apiserver-arg:" "${K3S_CONFIG}" 2>/dev/null; then
        # Append to existing kube-apiserver-arg section
        # Find the line and append after it
        sed -i '/^kube-apiserver-arg:/a\  - "encryption-provider-config='"${ENCRYPTION_CONFIG_DEST}"'"' "${K3S_CONFIG}"
    else
        # Create new section
        cat >> "${K3S_CONFIG}" << EOF

# Data at rest encryption for Citadel security baseline
kube-apiserver-arg:
  - "encryption-provider-config=${ENCRYPTION_CONFIG_DEST}"
EOF
    fi
    log "Updated K3s configuration with encryption provider"
fi

# ----- Step 5: Create encrypted volume directory -----
log "Step 5: Creating encrypted volume directory..."

ENCRYPTED_VOL_DIR="/var/lib/citadel/encrypted-volumes"
mkdir -p "${ENCRYPTED_VOL_DIR}"
chmod 700 "${ENCRYPTED_VOL_DIR}"
log "Created: ${ENCRYPTED_VOL_DIR}"

log ""
log "=========================================="
log "Data at Rest Encryption Configuration Complete"
log "=========================================="
log ""
log "IMPORTANT: K3s must be restarted for changes to take effect!"
log ""
log "To restart K3s:"
log "  sudo systemctl restart k3s"
log ""
log "After restart, verify encryption is working:"
log ""
log "  1. Create a test secret:"
log "     kubectl create secret generic encryption-test --from-literal=data=citadel-test"
log ""
log "  2. Read it directly from etcd (should be encrypted):"
log "     ETCDCTL_API=3 etcdctl \\"
log "       --endpoints=https://127.0.0.1:2379 \\"
log "       --cert=/var/lib/rancher/k3s/server/tls/etcd/server-client.crt \\"
log "       --key=/var/lib/rancher/k3s/server/tls/etcd/server-client.key \\"
log "       --cacert=/var/lib/rancher/k3s/server/tls/etcd/server-ca.crt \\"
log "       get /registry/secrets/default/encryption-test | hexdump -C"
log ""
log "  3. Verify the output shows 'k8s:enc:aesgcm:v1:citadel-key-1' prefix"
log "     (NOT plaintext secret data)"
log ""
log "  4. Re-encrypt all existing secrets with the new key:"
log "     kubectl get secrets --all-namespaces -o json | kubectl replace -f -"
log ""
log "Encryption key backup: ${KEY_BACKUP_FILE}"
log "Move this key to a secure vault before deleting the backup."
log "=========================================="

# ----- Optional: Restart K3s now -----
read -p "Restart K3s now to apply encryption? [y/N] " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    log "Restarting K3s..."
    systemctl restart k3s

    log "Waiting for K3s to be ready..."
    sleep 10
    export KUBECONFIG=/etc/rancher/k3s/k3s.yaml
    kubectl wait --for=condition=Ready nodes --all --timeout=120s
    log "K3s restarted successfully!"

    # Verify encryption is working
    log "Verifying encryption..."
    kubectl create secret generic citadel-encryption-test \
        --from-literal=verification=citadel-encrypted-$(date +%s) \
        --dry-run=client -o yaml | kubectl apply -f - 2>/dev/null || true

    sleep 2

    # Check if the secret exists and API server is serving
    if kubectl get secret citadel-encryption-test &>/dev/null; then
        log "Encryption verification: API server is serving encrypted secrets"
        kubectl delete secret citadel-encryption-test --ignore-not-found
    else
        error "Could not verify encryption. Check K3s logs: journalctl -u k3s"
    fi
else
    log "Skipping restart. Remember to restart K3s manually:"
    log "  sudo systemctl restart k3s"
fi
