#!/usr/bin/env bash # ============================================================================= # export-trino-ca.sh — segarkan pin CA TLS Trino milik panel. # # Trino menyajikan sertifikat **self-signed** dari `keystore.p12` # (http-server.https.keystore.*). Setiap kali keystore diregenerasi — install.sh, # generate-trino-keystore.sh, atau container Trino dibuat ulang — cert-nya # berubah, sehingga pin CA panel (`.ca/trino.crt`) jadi basi dan SEMUA panggilan # Trino HTTPS gagal dengan: # DEPTH_ZERO_SELF_SIGNED_CERT # → /api/query mengembalikan 500 "fetch failed" # → kartu "Data Catalog" di SQL IDE tampil "gagal load catalog" # # Script ini mengekspor cert Trino yang berlaku ke file pin, dengan backup, dan # idempoten (tidak menulis bila sudah sinkron). # # Sumber cert: # 1. endpoint live (default) — via `openssl s_client`; paling akurat karena # persis cert yang harus dipercaya panel. # 2. keystore.p12 — set TRINO_KEYSTORE (berguna saat endpoint belum hidup). # # Config via env (default cocok dgn deploy sicabe-doc & panel .env): # TRINO_CA_HOST host:port Trino HTTPS (default: localhost:12443) # TRINO_CA_SNI SNI server name (default: host dari TRINO_CA_HOST) # TRINO_CA_FILE file pin CA panel (default: /.ca/trino.crt) # TRINO_KEYSTORE path keystore.p12 (opsional; bila di-set, dipakai) # TRINO_KEYSTORE_PASS password keystore (default: trino_ssl_dev) # # Contoh: # ./scripts/export-trino-ca.sh # TRINO_CA_HOST=trino.example.com:12443 ./scripts/export-trino-ca.sh # TRINO_KEYSTORE=/path/sicabe-doc/deploy/config/trino/keystore.p12 \ # ./scripts/export-trino-ca.sh # # Setelah dijalankan: RESTART panel (koneksi TLS di-memoize per proses). Agent # config tidak perlu restart — ia membaca file ini setiap request. # ============================================================================= set -euo pipefail REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" TRINO_CA_HOST="${TRINO_CA_HOST:-localhost:12443}" TRINO_CA_SNI="${TRINO_CA_SNI:-${TRINO_CA_HOST%%:*}}" TRINO_CA_FILE="${TRINO_CA_FILE:-$REPO_ROOT/.ca/trino.crt}" TRINO_KEYSTORE="${TRINO_KEYSTORE:-}" TRINO_KEYSTORE_PASS="${TRINO_KEYSTORE_PASS:-trino_ssl_dev}" command -v openssl >/dev/null 2>&1 || { echo "ERROR: openssl tidak ditemukan di PATH" >&2; exit 1; } TMP="$(mktemp)" # cert hasil ekspor LIVE="$(mktemp)" # cert dari endpoint live (untuk cross-check) trap 'rm -f "$TMP" "$LIVE"' EXIT is_pem_cert() { [ -s "$1" ] && grep -q -- "-----BEGIN CERTIFICATE-----" "$1"; } fp_of() { openssl x509 -in "$1" -noout -fingerprint -sha256 | cut -d= -f2 | tr -d ':'; } # ── 1. Ambil cert ──────────────────────────────────────────────────────────── if [ -n "$TRINO_KEYSTORE" ]; then [ -f "$TRINO_KEYSTORE" ] || { echo "ERROR: keystore tidak ditemukan: $TRINO_KEYSTORE" >&2; exit 1; } echo "→ Mengekspor cert dari keystore: $TRINO_KEYSTORE" # -legacy diperlukan OpenSSL 3 untuk PKCS#12 lama (RC2-40). Bila tidak # didukung/berbeda, coba tanpa flag tersebut. if ! openssl pkcs12 -in "$TRINO_KEYSTORE" -nokeys -clcerts \ -passin "pass:$TRINO_KEYSTORE_PASS" -legacy 2>/dev/null \ | openssl x509 -outform PEM > "$TMP" 2>/dev/null || ! is_pem_cert "$TMP"; then openssl pkcs12 -in "$TRINO_KEYSTORE" -nokeys -clcerts \ -passin "pass:$TRINO_KEYSTORE_PASS" 2>/dev/null \ | openssl x509 -outform PEM > "$TMP" 2>/dev/null || true fi else echo "→ Mengambil cert dari endpoint live: https://$TRINO_CA_HOST" echo | openssl s_client -connect "$TRINO_CA_HOST" -servername "$TRINO_CA_SNI" 2>/dev/null \ | openssl x509 -outform PEM > "$TMP" 2>/dev/null || true fi if ! is_pem_cert "$TMP"; then echo "ERROR: gagal mengekspor sertifikat (sumber: ${TRINO_KEYSTORE:-https://$TRINO_CA_HOST})" >&2 [ -z "$TRINO_KEYSTORE" ] && echo " Pastikan Trino hidup & port HTTPS benar (TRINO_CA_HOST)." >&2 exit 1 fi NEW_FP="$(fp_of "$TMP")" echo " subject : $(openssl x509 -in "$TMP" -noout -subject | sed 's/^subject=//')" echo " sha256 : $NEW_FP" # ── 2. Tulisan hanya bila berubah (idempoten) ──────────────────────────────── if [ -f "$TRINO_CA_FILE" ] && [ "$(fp_of "$TRINO_CA_FILE")" = "$NEW_FP" ]; then echo "✓ $TRINO_CA_FILE sudah sinkron — tidak ada perubahan." exit 0 fi mkdir -p "$(dirname "$TRINO_CA_FILE")" if [ -f "$TRINO_CA_FILE" ]; then BAK="${TRINO_CA_FILE}.bak-$(date +%Y%m%d-%H%M%S)" cp -p "$TRINO_CA_FILE" "$BAK" echo "→ Backup pin lama: $BAK" echo " (fingerprint lama: $(fp_of "$BAK"))" fi install -m 600 "$TMP" "$TRINO_CA_FILE" echo "✓ Pin CA diperbarui: $TRINO_CA_FILE" # ── 3. Cross-check dengan endpoint live (bila sumbernya keystore) ──────────── if [ -n "$TRINO_KEYSTORE" ]; then if echo | openssl s_client -connect "$TRINO_CA_HOST" -servername "$TRINO_CA_SNI" 2>/dev/null \ | openssl x509 -outform PEM > "$LIVE" 2>/dev/null && is_pem_cert "$LIVE"; then if [ "$(fp_of "$LIVE")" = "$NEW_FP" ]; then echo "✓ Cocok dengan cert yang disajikan https://$TRINO_CA_HOST" else echo "WARN: cert keystore BERBEDA dari yang disajikan https://$TRINO_CA_HOST" >&2 echo " Restart Trino, lalu jalankan ulang script ini." >&2 exit 1 fi else echo "! https://$TRINO_CA_HOST tidak bisa dihubungi — cross-check dilewati." fi fi cat <<'EOF' Langkah berikutnya: • RESTART panel (Next.js) — koneksi TLS di-memoize per proses: kill $(ss -ltnp | grep ':3000' | grep -oE 'pid=[0-9]+' | cut -d= -f2) && npm run dev • Agent config TIDAK perlu restart (baca file ini setiap request). • Uji cepat: POST /api/query {"query":"SHOW CATALOGS"} → harus 200. EOF