# =============================================================================
# Britive Bridge — REFERENCE configuration
# =============================================================================
# This file documents EVERY configuration setting, with its default value and a
# description. It is a reference, not a ready-to-run config — most settings can be
# omitted to accept the default. Copy the sections you need.
#
# Precedence: built-in defaults  <  this YAML file  <  environment variables.
#
# Environment overrides (take precedence over the YAML below):
#   BRIDGE_ROLE                 cluster role: single | session | proxy | orchestrator  (-> cluster.role)
#   BRIDGE_DATASTORE_HOST       datastore host                                          (-> server.datastore.host)
#   BRIDGE_DATASTORE_PORT       datastore port                                          (-> server.datastore.port)
#   BRIDGE_DATASTORE_USER       datastore user                                          (-> server.datastore.user)
#   BRIDGE_DATASTORE_PASSWORD   datastore password                                      (-> server.datastore.password)
#   BRIDGE_DATASTORE_NAME       datastore database name                                 (-> server.datastore.name)
#   BRIDGE_DATASTORE_SSLMODE    datastore sslmode                                       (-> server.datastore.sslmode)
#   BRIDGE_HOST_KEY_SEED        deterministic SSH host-key seed                         (-> ssh.native.host_key_seed)
#   BRIDGE_LDAP_BIND_PASSWORD   LDAP service-account password                           (-> server.auth.ldap.bind_password)
#   BRIDGE_TLS_ENABLED          true/false override for API HTTPS                        (-> server.tls.enabled)
#   BRITIVE_TENANT              Britive tenant subdomain or full tenant URL             (-> server.auth.britive.tenant)
#   BRIDGE_LICENSE              inline signed license blob ("payload.sig")              (-> server.license.key)
#   BRIDGE_LICENSE_PATH         path to a file containing the license blob              (-> server.license.path)
#   BRITIVE_BROKER_AUTH_TOKEN   broker pool token; also enables automatic license        (env-only)
#                               retrieval from the platform
#   BRITIVE_BROKER_TENANT_SUBDOMAIN tenant used by broker startup and as license         (env-only)
#                               retrieval fallback when server.auth.britive.tenant is unset
#   BRIDGE_ENCRYPTION_KEY_B64   base64 32-byte key encrypting checkout payloads in PG   (env-only; no YAML field)
#   BRIDGE_ENCRYPTION_KEY_FILE  file containing checkout encryption key                  (env-only; no YAML field)
#   BRIDGE_CLUSTER_TOKEN        shared secret for intra-cluster calls (dispatch/admin)  (env-only; cluster mode)
#   BRIDGE_WORKER_ID            worker identity (orchestrator injects it)               (env-only; cluster mode)
#   BRIDGE_WORKER_ADDR          worker's routable address/pod IP                        (env-only; cluster mode)
#   BRIDGE_CLUSTER_ADDR         override the address this instance advertises           (env-only; cluster mode)
#   BRIDGE_NAMESPACE            k8s namespace for the provisioner                       (env-only; k8s provisioner)
#
# PostgreSQL is MANDATORY in every mode (single-container and cluster). It stores
# checkouts, session metadata, and (in cluster mode) the worker/leader registries.
# Configure it under server.datastore (discrete fields; no DSN string).
#
# Ports: listen settings are bare port numbers (e.g. 22, 8443). The bridge binds
# all interfaces (":PORT"); to bind a specific interface, write "HOST:PORT".
#
# Each protocol is mode-scoped into two blocks, each with its own `enabled`
# (default false — EVERYTHING is off until you turn it on), so settings live under
# the mode they apply to:
#   native   — a raw TCP listener clients reach with their normal client
#              (ssh, mysql, psql, mstsc, …). native.listen is the listen port.
#   browser  — the web UI client (needs the web tier, server.listen).
# Shared settings (idle_timeout, etc.) sit at the protocol top level.
#
# Recording is enabled by default. A checkout opts out per-session with
# record_session: false. Server-side recording settings are where files land
# (recording.output_dir) and output-body redaction for WinRM/RESTCONF.
# =============================================================================


# --- Server (API + web tier, datastore, auth, recording) ----------------------
server:
  listen: 443                    # API + browser-WebSocket + admin listen port. Required. (default 443)
  log_level: "info"              # trace | debug | info | warn | error. "trace" = firehose diagnostics. (default "info")
  landing_enabled: false         # Serve a public landing page at "/". (default false; otherwise "/" -> /user-sessions)
  picker_enabled: false          # Serve an authenticated checkout picker at "/picker". (default false)
  trusted_proxies: []            # Upstream proxy CIDRs/IPs whose X-Forwarded-For / X-Real-IP are honored when
                                 # recording the client IP. Empty = trust no headers, use the unspoofable direct
                                 # peer. Set to the fronting LB/proxy network when behind one. (default [])
  # The browser SQL client is auto-enabled whenever any database protocol below has
  # browser.enabled: true — there is no separate toggle.
  tls:
    enabled: true                # Serve HTTPS on server.listen. (default true). Set false for plaintext (e.g. behind a TLS-terminating LB).
    cert_path: "/data/certs/api-cert.pem"   # Leaf cert; auto-generated if missing. (default shown)
    key_path:  "/data/certs/api-key.pem"    # Leaf key;  auto-generated if missing. (default shown)

  # --- Datastore (PostgreSQL; mandatory in all modes) ---
  # Discrete fields only (each overridable via BRIDGE_DATASTORE_*). No DSN string.
  datastore:
    host: "localhost"            # (default "localhost")
    port: 5432                   # (default 5432)
    user: "bridge"               # (default "bridge")
    password: ""                 # (default "")
    name: "bridge"               # database name (default "bridge")
    sslmode: "disable"           # disable | require | verify-ca | verify-full (default "disable")

  # --- Authentication (web-UI login) ---
  # Login authenticates users for browser access. Production roles and admin
  # access are controlled by the configured identity provider and checkout roles.
  auth:
    # Enabled login methods. britive is the default; ldap is optional (and britive
    # optional if ldap is chosen). An empty list ([]) means no web login.
    types:
      - britive
    britive:                     # used when "britive" is in types — Britive OAuth (Authorization Code + PKCE)
      tenant: ""                 # tenant subdomain (e.g. "acme") or full tenant URL (e.g. "https://acme.britive-app.com").
                                 # Required when britive is enabled. Env: BRITIVE_TENANT.
      scopes: ["openid"]         # scopes requested at /authorize. (default ["openid"])
      redirect_url: ""           # exact OAuth redirect_uri registered with the IdP; set when behind a TLS-
                                 # terminating L4 LB (NLB) that drops X-Forwarded-Proto. "" = derived from the request.
      client_id: ""              # OPTIONAL explicit public client id; "" = derived from the tenant (tenant-scoped
                                 # PKCE needs no app registration). (default "")
      client_id_prefix: "britive-bridge-"  # prefix for the derived client id. (default shown)
    ldap:                        # used when "ldap" is in types
      server: ""                 # ldap://host:389 or ldaps://host:636. Required.
      tls: false                 # Use StartTLS with the ldap:// scheme. (default false)
      bind_dn: ""                # Service-account DN used to search. Required.
      bind_password: ""          # Service-account password. Env: BRIDGE_LDAP_BIND_PASSWORD.
      base_dn: ""                # Search base for user lookups. Required.
      user_filter: "(uid={{username}})"  # Search filter; {{username}} is substituted. (default shown)
      tls_insecure: false        # Skip LDAP TLS cert verification (dev only). (default false)

  # --- Session recording ---
  # Recording is ALWAYS ON. A checkout opts out of its own recording with
  # record_session: false (omitted/true = recorded). Server-side settings are
  # where files land and whether WinRM/RESTCONF response/output bodies are redacted.
  recording:
    output_dir: "/data/recordings"  # Where recordings are written. Required. In cluster mode a SHARED
                                    # volume (session workers write; proxy/UI reads for playback). (default shown)
    redact_response_bodies: true    # Mask secrets in recorded response/output bodies (WinRM stdout/stderr,
                                    # RESTCONF response_body). A checkout may override per-session. (default true)

  # --- License (tenant-bound; online retrieval or offline fallback) ---
  # The bridge enforces a Britive-signed license. With no valid license it runs in
  # LIMITED mode: browser-only sessions for ssh/telnet/rdp/vnc/k8sexec, and no live
  # viewing, session control, downloads, or more than one session per checkout.
  # Supply a license here (or via BRIDGE_LICENSE / BRIDGE_LICENSE_PATH); it is loaded
  # into the datastore on boot (no-op if already present) and can also be installed/
  # replaced from the admin console. The post-expiry grace window is a fixed 30 days
  # (not configurable). Omit this block entirely to start unlicensed (limited mode).
  #
  # AUTOMATIC RETRIEVAL: when BRITIVE_BROKER_AUTH_TOKEN is set, the orchestrator
  # (while leader) and single-node deployments fetch the license from the Britive
  # platform on boot and then refresh it daily. The endpoint is derived from the
  # configured Britive tenant; BRITIVE_BROKER_TENANT_SUBDOMAIN is used as a fallback
  # when server.auth.britive.tenant is unset. The platform license takes precedence
  # over key/path (which then act as a first-boot fallback), and auto-managed
  # licenses replace in place — no growing list of stale licenses. When the token is
  # unset, only the offline key/path below are used.
  license:
    key: ""                      # inline signed "payload.sig" license blob. Env: BRIDGE_LICENSE. (default "")
    path: ""                     # path to a file containing the blob. Env: BRIDGE_LICENSE_PATH. (default "")


# --- SSH ----------------------------------------------------------------------
ssh:
  native:                              # raw SSH listener (clients: `ssh user%target@bridge`)
    enabled: false                     # (default false)
    listen: 22                         # native SSH listen port (default 22)
    host_key_path: "/data/keys/host_key"  # SSH host key file (default shown)
    host_key_auto_generate: true       # generate an ED25519 host key if missing (default true)
    host_key_seed: ""                  # deterministic host-key seed — same seed = same fingerprint across
                                       # restarts/replicas (needed for stable keys across ephemeral cluster
                                       # session workers). Env: BRIDGE_HOST_KEY_SEED. (default "")
    max_auth_tries: 3                  # max client auth attempts before disconnect (default 3)
    banner: ""                         # pre-auth banner shown to clients before login (default "" = none)
    server_version: "SSH-2.0-BritiveBridge"  # SSH version string presented to clients (default shown)
  browser:                             # browser SSH terminal (rendered server-side)
    enabled: false                     # (default false)
    font_name: "monospace"             # terminal font (default "monospace")
    font_size: 14                      # terminal font size (default 14)
    color_scheme: "gray-black"         # terminal color scheme (default "gray-black")
    scrollback: 5000                   # terminal scrollback lines (default 5000)
  idle_timeout: "30m"                  # shared: idle session timeout (default 30m)
  allow_insecure_host_key: true        # shared: skip BACKEND host-key verification (JIT dynamic targets) (default true)


# --- Telnet -------------------------------------------------------------------
telnet:
  native:
    enabled: false                     # raw Telnet listener (default false)
    listen: 23                         # native Telnet listen port (default 23)
  browser:
    enabled: false                     # browser Telnet terminal (direct WebSocket) (default false)
  idle_timeout: "30m"                  # shared (default 30m)


# --- RDP ----------------------------------------------------------------------
rdp:
  native:                              # native RDP listener (mstsc/xfreerdp/Mac RD)
    enabled: false                     # (default false)
    listen: 3389                       # native RDP listen port (default 3389)
    tls_cert: "/data/certs/rdp-cert.pem"  # cert presented to RDP clients; auto-generated if missing
    tls_key:  "/data/certs/rdp-key.pem"   # key for the client-facing TLS leg
    header_position: "bottom"          # branded chrome strip: "bottom" (footer) or "top"; cannot be disabled (default "bottom")
  browser:                             # browser RDP via WebSocket (/rdp/ws) + default display geometry
    enabled: false                     # (default false)
    default_width: 1600                # default screen width px (default 1600)
    default_height: 900                # default screen height px (default 900)
    default_dpi: 144                   # default DPI (default 144)
  allow_insecure_cert: true            # shared: skip backend RDP/VNC server cert verification (default true)
  idle_timeout: "30m"                  # shared: idle session timeout (default 30m)
  # RDP file-copy / clipboard / drive-redirection are configured PER CHECKOUT
  # (not here) — the customer toggles a feature and the bridge handles the rest.


# --- VNC (browser only; no native VNC listener) -------------------------------
vnc:
  browser:
    enabled: false                     # browser VNC via WebSocket (default false)
  # Like RDP, VNC display/clipboard tunables are set per checkout, not here.


# --- Databases: native wire-proxies and/or browser SQL client -----------------
# native.enabled exposes the wire-protocol listener (connect with the normal
# client to native.listen); browser.enabled exposes it in the web SQL client (the
# browser SQL client auto-enables when any DB browser block is on). idle_timeout
# applies to both.
mysql:
  native:
    enabled: false
    listen: 3306                       # (default 3306)
  browser:
    enabled: false
  idle_timeout: "30m"                  # (default 30m)

postgres:
  native:
    enabled: false
    listen: 5432
  browser:
    enabled: false
  idle_timeout: "30m"

cockroachdb:                           # PostgreSQL-wire compatible
  native:
    enabled: false
    listen: 26257
  browser:
    enabled: false
  idle_timeout: "30m"

mssql:
  native:
    enabled: false
    listen: 1433
  browser:
    enabled: false
  idle_timeout: "30m"

redis:
  native:
    enabled: false
    listen: 6379
  browser:
    enabled: false
  idle_timeout: "30m"

mongodb:
  native:
    enabled: false
    listen: 27017
  browser:
    enabled: false
  idle_timeout: "30m"

cassandra:
  native:
    enabled: false
    listen: 9042
  browser:
    enabled: false
  idle_timeout: "30m"


# --- Network device protocols -------------------------------------------------
netconf:                               # NETCONF-over-SSH proxy
  native:
    enabled: false
    listen: 830
  browser:
    enabled: false
  max_auth_tries: 3                    # max SSH auth attempts (default 3)
  idle_timeout: "30m"

restconf:                              # RESTCONF (HTTPS) reverse proxy
  native:
    enabled: false
    listen: 8443
  browser:
    enabled: false
  idle_timeout: "30m"

winrm:                                 # WinRM (HTTPS) reverse proxy
  native:
    enabled: false
    listen: 5986
  browser:
    enabled: false
  idle_timeout: "30m"

k8s_exec:                              # Kubernetes exec/attach — browser only.
  browser:                            # (kubectl exec for end users goes through the HTTP proxy, not a native listener)
    enabled: false                     # browser k8s exec terminal (default false)
  idle_timeout: "30m"


# --- HTTP forward proxy (TLS-terminating, with HAR capture) -------------------
# There is no browser client and no native listener split — just a single
# TLS-terminating proxy. Capture scope is PER CHECKOUT (a request whose host
# matches no active checkout is always blocked), so it is not configured here.
http_proxy:
  enabled: false                 # explicit HTTP/HTTPS proxy listener (default false)
  listen: 8443                   # proxy listen port (TLS-terminating). (default 8443)
  allow_http2: true              # Allow HTTP/2 to capture-eligible backends. (default true)
  max_body_record: 65536         # Max bytes of a single request/response body to record. (default 65536 = 64KB)
  # Base redaction lists. A checkout may EXTEND (never shrink) each via its
  # sanitize_*_extend fields.
  sanitize_headers:        ["authorization","proxy-authorization","cookie","set-cookie","x-api-key","x-auth-token","x-csrf-token"]  # (default shown)
  sanitize_query_params:   ["token","access_token","refresh_token","key","secret","sig","signature","password"]                     # (default shown)
  sanitize_body_fields:    ["token","access_token","refresh_token","key","secret","password","client_secret","authorization"]       # (default shown)
  mitm:                          # the CA used to break SSL (sign per-host leaf certs). Clients must trust it.
    ca_cert_path: "/data/certs/ca.pem"      # (default shown)
    ca_key_path:  "/data/certs/ca-key.pem"  # (default shown)
    auto_generate_ca: true       # auto-create the CA if missing (default true)
    ca_common_name: "Britive Bridge CA"     # generated CA Common Name (default shown)
    ca_organization: "Britive"              # generated CA Organization (default shown)
    ca_validity: "87600h"        # generated CA validity (default 87600h = 10 years)
    leaf_validity: "24h"         # per-host leaf validity (default 24h)


# (Session recording is configured under server.recording — see the server block.)


# =============================================================================
# Cluster mode
# =============================================================================
# Single-container is the default (cluster.role: single) and uses NONE of the
# session/proxy/orchestrator blocks below — it runs every enabled protocol + the
# API in one process. Cluster mode splits that one image into roles (selected by
# cluster.role / BRIDGE_ROLE) so containers can be cycled without dropping
# sessions. The SAME config file is shared by all roles; each role reads the
# block(s) relevant to it. Durations use Go syntax ("30s", "1m", "36h"); 0 means
# off/unlimited as noted.
cluster:
  role: "single"                 # single (default) | session | proxy | orchestrator. Env: BRIDGE_ROLE.
                                 #   single       — all-in-one (default); ignores the blocks below.
                                 #   session      — terminates protocols end-to-end; ephemeral; reads `session`.
                                 #   proxy        — HAProxy edge + web tier; routes to session workers; long-lived.
                                 #   orchestrator — leader-elected controller; runs migrations, keeps the pools,
                                 #                  cycles proxies; reads `orchestrator`.

  # --- session role: ephemeral worker lifecycle ---
  session:
    max_concurrent_sessions: 1   # Concurrent sessions this worker serves before it stops accepting new ones
                                 # (capacity = CPU/mem). 0 = unlimited. (default 1)
    session_limit: 1             # Total real sessions before the worker drains + exits. 0 = unlimited. (default 1)
                                 # Defaults (1/1) = one-session-then-exit (the orchestrator keeps N warm).
    lifespan: "0s"               # Drain + exit after this long regardless of session count. 0 = off. (default 0)

  # --- proxy role: cycling (the orchestrator drives it) ---
  proxy:
    lifespan: "0s"               # Cycle (replace) a proxy once it's older than this. 0 = no cycling. (default 0)
                                 # e.g. 36h. Cycle = spawn replacement -> wait ready -> retire (readiness fails,
                                 # LB stops new conns) -> drain -> terminate.
    lifespan_jitter: "0s"        # +/- jitter on lifespan (deterministic per worker) so a fleet doesn't retire in
                                 # lockstep. 0 -> default of lifespan/6.
    drain_deadline: "0s"         # Max time a retiring proxy waits for in-flight sessions to finish before being
                                 # force-terminated. 0 = wait forever (default). The proxy accepts no new
                                 # connections while draining, so this only bounds already-established sessions.
    max_cycle_concurrency: 1     # Most proxies allowed to drain/cycle at once. 0 = unlimited. (default 1)

  # --- orchestrator role: the controller ---
  orchestrator:
    warm_session_workers: 1      # Warm session workers to keep ready (N). 0 = don't manage sessions. (default 1)
    proxy_workers: 1             # Proxy containers to keep running (M). 0 = don't manage proxies. The orchestrator
                                 # owns proxy lifecycle on every platform (no static Deployment). (default 1)
    reconcile: "10s"             # Control-loop tick: how often desired vs reality is reconciled (reap dead workers,
                                 # top up pools, evaluate cycling). (default 10s)
    lease: "15s"                 # Leader-election lease duration. (default 15s)
    provisioner:                 # how workers are spawned/terminated and LB targets managed
      platform: ""               # "k8s" | "ecs" — selects the sub-block below. (default "")
      path: ""                   # provisioner script invoked to spawn/terminate/list workers + manage LB targets.
                                 # "" = spawning disabled (leader + status only).
                                 # k8s: /opt/bridge/drivers/k8s/driver   ecs: /opt/bridge/drivers/aws/driver
      k8s:                       # workers are scoped to this namespace
        image: ""                # container image the orchestrator spawns for session/proxy workers (role via BRIDGE_ROLE). (default "")
        namespace: ""            # namespace workers are spawned in (also the provisioner's scope). (default "")
      ecs:                       # workers are scoped to this ECS cluster
        task_definition: ""      # task-definition ARN run for workers (the ECS analogue of k8s "image"). (default "")
        cluster: ""              # ECS cluster name/ARN the tasks run in (also the provisioner's scope). (default "")
