Files

130 lines
6.1 KiB
Bash
Raw Permalink Normal View History

2026-10-13 23:07:35 +07:00
#!/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"
#
2026-10-14 01:20:29 +07:00
# Mode file 0644 (sertifikat PUBLIK, bukan secret) supaya terbaca oleh proses
# panel yang berjalan sebagai user LAIN di container (uid 1001) — dengan 0600
# panel di container mendapat "Permission denied" → CA dianggap tak ada.
#
2026-10-13 23:07:35 +07:00
# 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: <repo>/.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
2026-10-14 01:20:29 +07:00
install -m 644 "$TMP" "$TRINO_CA_FILE"
2026-10-13 23:07:35 +07:00
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