sync dari sicabe-doc/deploy @ e8f8fde

This commit is contained in:
2026-10-11 18:13:03 +07:00
parent 6e4dfb69ef
commit 9f454b6e8e
12 changed files with 191 additions and 29 deletions
+42 -5
View File
@@ -96,6 +96,30 @@ PUBLIC_URL_ENDPOINTS = {
"MINIO_CONSOLE_PUBLIC_URL": ("minio", "http://{addr}:12901"),
}
def _ext_url(ext: str, template: str, port: str = "") -> str:
"""URL untuk komponen EKSTERNAL dari `components.<c>.address`.
Bila operator menulis **URL penuh** (mengandung `://`, mis.
`https://sso.example.com`) → pakai APA ADANYA: skema + host + port dihormati
(default port per skema, mis. https→443, TIDAK ditulis bila default). Bila hanya
host/IP polos (perilaku lama) → susun dari `template` + `port` seperti sebelumnya.
"""
scheme, host, p = inventory.parse_address(ext)
if scheme:
# Buang port bila = default skema (https→443), supaya `https://host`, bukan
# `https://host:443` (ekuivalen, tapi lebih bersih & cocok utk issuer/URL publik).
show = p and p != inventory._DEFAULT_SCHEME_PORT.get(scheme)
return f"{scheme}://{host}" + (f":{p}" if show else "")
if port and "{port}" in template:
return template.format(addr=host, port=(p if p else port))
return template.format(addr=host)
def _keycloak_external_scheme(doc: dict) -> str:
"""Skema URL Keycloak eksternal ('' bila bukan URL penuh). Untuk sslRequired."""
return inventory.parse_address(inventory.external_address(doc, "keycloak") or "")[0]
# SENGAJA TIDAK diarahkan ke IP: KEYCLOAK_URL / TRINO_URL dan var `*_URL` lain yang
# bersifat identitas (issuer OIDC harus stabil — lihat R10 §4.10.1: pakai DNS
# internal, bukan IP). Itu milik operator dan harus sudah benar di `cluster.yml`
@@ -195,7 +219,7 @@ def _is_topology_var(line: str) -> bool:
"""
key = line.split("=", 1)[0].strip()
owned = {
"EXTERNAL_SERVICES", "LOCAL_SERVICES", "KEYCLOAK_SSL_REQUIRED",
"EXTERNAL_SERVICES", "LOCAL_SERVICES", "KEYCLOAK_SSL_REQUIRED", "KEYCLOAK_INTERNAL_URL",
"KC_PROXY_HEADERS", "TRINO_PROCESS_FORWARDED", "CLUSTER_DOMAIN", "TRAEFIK_BIND_ADDR",
*ENDPOINT_VARS, *URL_ENDPOINT_VARS,
*inventory.PUBLIC_URL_SERVICES, # KEYCLOAK_PUBLIC_URL, GRAFANA_PUBLIC_URL, …
@@ -458,7 +482,10 @@ def endpoint_lines(doc: dict, host: str, plan: dict) -> list[str]:
for var, component in ENDPOINT_VARS.items():
ext = inventory.external_address(doc, component)
if ext:
lines.append(f"{var}={ext}") # EKSTERNAL (pihak lain) → alamat tetap
# EKSTERNAL → HOST saja (buang skema/port bila operator menulis URL penuh,
# mis. `https://sso.example.com` → `sso.example.com`). URL lengkapnya
# ditangani `*_URL` / KEYCLOAK_INTERNAL_URL, bukan var `*_HOST`.
lines.append(f"{var}={inventory.parse_address(ext)[1]}")
continue
owners = placement.get(component)
if not owners:
@@ -467,6 +494,13 @@ def endpoint_lines(doc: dict, host: str, plan: dict) -> list[str]:
lines.append(f"{var}={component}") # SE-HOST → nama service
else:
lines.append(f"{var}={plan[owners[0]]['address']}") # LINTAS host → alamat
# Keycloak: URL server→server (token/jwks/Grafana). Hanya ditulis bila Keycloak
# EKSTERNAL memakai URL PENUH (mis. https://sso.example.com) agar skema+port
# dihormati; selain itu compose/script memakai default
# `http://${KEYCLOAK_HOST:-keycloak}:${KEYCLOAK_INTERNAL_PORT:-8080}`.
kc_ext = inventory.external_address(doc, "keycloak")
if kc_ext and inventory.parse_address(kc_ext)[0]:
lines.append(f"KEYCLOAK_INTERNAL_URL={_ext_url(kc_ext, '')}")
disabled = [n for n, v in inventory.enabled_components(doc).items() if v is False]
if disabled:
# Komponen `enabled: false` = tidak dijalankan di host mana pun → installer
@@ -498,7 +532,7 @@ def public_url_lines(doc: dict, plan: dict | None = None) -> list[str]:
for var, (component, tmpl) in PUBLIC_URL_ENDPOINTS.items():
ext = inventory.external_address(doc, component)
if ext:
resolved[var] = tmpl.format(addr=ext) # eksternal → alamat tetap
resolved[var] = _ext_url(ext, tmpl) # eksternal → URL penuh dihormati
continue
owners = placement.get(component)
if not owners:
@@ -523,8 +557,11 @@ def tls_policy_lines(doc: dict) -> list[str]:
tls.mode `edge`/`full` -> `external` (ada Traefik/TLS di depan)
"""
edge = inventory.tls_mode(doc) != "none"
# Keycloak EKSTERNAL ber-URL `https://…` juga menuntut sslRequired=external (permintaan
# dari alamat non-lokal lewat TLS di depannya).
ext_https = _keycloak_external_scheme(doc) == "https"
return [
f"KEYCLOAK_SSL_REQUIRED={'external' if edge else 'none'}",
f"KEYCLOAK_SSL_REQUIRED={'external' if (edge or ext_https) else 'none'}",
# Di belakang Traefik, Keycloak WAJIB memercayai X-Forwarded-* — tanpa itu
# permintaan HTTPS dari proxy dianggap HTTP (redirect salah / tuntutan HTTPS).
# Sengaja KOSONG saat tanpa proxy: memasangnya membuat Keycloak memercayai
@@ -665,7 +702,7 @@ def url_endpoint_lines(doc: dict, host: str, plan: dict, env_path=None) -> list[
for var, (component, template) in URL_ENDPOINT_VARS.items():
ext = inventory.external_address(doc, component)
if ext:
lines.append(f"{var}={template.format(addr=ext, port=_endpoint_port(var, env_path))}")
lines.append(f"{var}={_ext_url(ext, template, _endpoint_port(var, env_path))}")
continue
owners = placement.get(component)
if not owners: