Skip to main content

Configuration

Baleia (the API and the worker) is configured with environment variables. The defaults work for local development with the provided docker-compose.yaml. In Kubernetes, the Helm chart sets them from config and its Secret (deploy/helm/baleia/values.yaml).

VariableDefaultDescription
PORT8080HTTP listen port
DATABASE_URLpostgresql://baleia:baleia@localhost:5432/baleia?sslmode=disablePostgreSQL connection string
JWT_SECRETchange-me-in-productionKey for signing JWTs
BALEIA_ENCRYPTION_KEY(unset)Key that encrypts stored connection credentials (≥ 32 characters, must differ from JWT_SECRET). Required once any credential is stored; the API refuses to start without it. Derived with HKDF-SHA256; each value is bound to its connection row
BALEIA_ENCRYPTION_KEY_PREVIOUS(unset)Previous encryption key, set only during rotation: values are read with the current or previous key and always written with the current one
BALEIA_ACCESS_TOKEN_TTL15mLifetime of an access token
BALEIA_REFRESH_TOKEN_TTL720h (30 days)Lifetime of a refresh token; a password change or reset, a role change, a suspension or a removal revokes them earlier
BALEIA_RESET_TOKEN_TTL30mLifetime of a password-reset link
BALEIA_BCRYPT_COST12Password hashing cost, between 10 and 31; higher is slower to sign in and to brute-force
BALEIA_ALLOW_AMBIENT_AWS_CREDENTIALSfalseLets an AWS Glue connection with no keys or role of its own use the host's default AWS credential chain. Off by default: otherwise any connection owner could use the platform's IAM role
BALEIA_AUDIT_EXPORT_URL, BALEIA_AUDIT_EXPORT_INDEX, BALEIA_AUDIT_EXPORT_AUTH, BALEIA_AUDIT_EXPORT_USER, BALEIA_AUDIT_EXPORT_PASSWORD, BALEIA_AUDIT_EXPORT_TOKEN, BALEIA_AUDIT_EXPORT_BATCH, BALEIA_AUDIT_EXPORT_INTERVAL, BALEIA_AUDIT_EXPORT_CA_FILEexport offShipping the audit trail to OpenSearch/Elasticsearch: defaults, authentication modes and behavior in Audit export
TEMPORAL_HOSTlocalhost:7233Temporal server address
TRINO_URLhttp://localhost:8088Trino coordinator REST endpoint. At API boot it also seeds the default Trino engine (with the service and admin identities below) and keeps it in step while that engine's connection is system-owned; engine endpoints live in the database (engines, ADR 0002). Trino is dialed through the connections dialer like every engine, so a loopback TRINO_URL needs BALEIA_CONNECTIONS_ALLOW_LOOPBACK=true (set by make dev)
POLARIS_URLhttp://localhost:8181Polaris REST API endpoint
POLARIS_CLIENT_ID / POLARIS_CLIENT_SECRET(unset)Credentials stored for a polaris connection created without any; both must be set
PUBLIC_URLhttp://localhost:8080Externally reachable URL (used for presigned links)
S3_ENDPOINTlocalhost:9000Endpoint of any S3-compatible store (AWS S3, RustFS, MinIO, Ceph RGW, Google Cloud Storage, Oracle Object Storage), as host[:port]
S3_ACCESS_KEYrustfsadminS3 access key
S3_SECRET_KEYrustfsadminS3 secret key
S3_BUCKETbaleiaS3 bucket for query results
S3_REGION(empty)SigV4 signing region. Empty discovers it (AWS, RustFS, MinIO); set it for stores that require it, e.g. sa-saopaulo-1 on Oracle Object Storage
S3_USE_SSLfalseEnable TLS for S3 connections
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASSWORD / SMTP_FROM—Outbound email (password reset, invites)
BALEIA_DEFAULT_LOCALEenFallback language for transactional e-mails when the recipient has no users.locale (en or pt-BR)
RATE_LIMIT_RPS60Max requests per second (rate limiter)
RATE_LIMIT_BURST10Rate limiter burst size
BALEIA_STATEMENT_TIMEOUT30mPer-statement execution timeout; enforced by the worker and by the engine (Trino: query_max_execution_time)
BALEIA_RECONCILE_INTERVALunsetApply binding reconciliation on a schedule (at least 5m); unset: no schedule, only POST /engines/{id}/reconcile
BALEIA_RECONCILE_MAX_ACTIONS20Changes one reconcile run may apply; the rest are reported
BALEIA_METADATA_SYNC_INTERVAL15mHow often every catalog's metadata snapshot is refreshed (at least 5m)
BALEIA_MAINTENANCE_MAX_CONCURRENT_RUNS4Automatic Iceberg maintenance runs in progress at once, across tables (#500)
BALEIA_ICEBERG_MAINTENANCE_MIN_RETENTION1hMinimum retention projected into managed Iceberg catalogs for expire_snapshots and remove_orphan_files; table parameters below the floor a catalog has loaded are refused (at least 1m). Changing it, including the first deploy that introduces it, changes the catalog version: every managed Iceberg catalog is re-created on its engine once, and until that reconcile the old floor (Trino's 7d) still applies
BALEIA_EXECUTION_TIMEOUT2hCap for a whole execution: all statements run in one engine session, so a script may take statements × statement timeout, capped by this
BALEIA_RESULT_MAX_ROWS1000000Max rows buffered per statement result before truncation
BALEIA_LOB_MAX_BYTES1048576Max bytes an Oracle engine reads from one CLOB/NCLOB/BLOB value into a result (1 MiB)
BALEIA_RESULT_MAX_BYTES536870912Max Arrow bytes per statement result before truncation
BALEIA_SCHEDULES_ENABLEDtrueEnsure recurring Temporal Schedules (Lens pollers, table health, retriever) at worker boot
BALEIA_CONNECTIONS_DENY_CIDRS(unset)Comma-separated CIDRs that connections may never reach, added to the built-in deny list (loopback, link-local incl. cloud metadata 169.254.169.254, 0.0.0.0/8) — see ADR 0011
BALEIA_CONNECTIONS_ALLOW_CIDRS(unset)If set, connections may only reach these comma-separated CIDRs (the deny list still wins)
BALEIA_CONNECTIONS_CREATEeveryoneWho may create and edit connections: everyone, or admins. The CIDR lists bind admins too, so on a deployment with self-service or shared accounts use admins to keep other users from aiming connections at internal services
BALEIA_LOG_LEVELinfoLowest level the API, the worker and cmd/migrate log: debug, info, warn or error. They log JSON lines to stdout; a line logged during a traced request or activity carries its trace_id and span_id (#379)
BALEIA_TRINO_EVENTS_TOKEN(unset)Bearer token Trino's HTTP event listener sends to POST /internal/trino/query-events (at least 32 characters). Set, the API records each completed query as it ends; unset, the endpoint does not exist. The chart wires both sides with trino.queryEvents.enabled (#406)
BALEIA_PPROF_ADDR(unset)Where the API and the worker serve the Go runtime profiles (/debug/pprof/), e.g. 127.0.0.1:6060; unset serves none. The listener has no authentication: bind it to loopback or a port only reachable from the pod (kubectl port-forward), never to a public interface (#380)
BALEIA_METRICS_ENABLEDtrueServe Prometheus metrics at the API's /metrics (the catalog is internal/metrics, #87)
BALEIA_METRICS_TOKEN(unset)When set, /metrics (API and worker) needs Authorization: Bearer <token>; it is never behind the user JWT. A credential: in the chart it is the optional Secret key BALEIA_METRICS_TOKEN (secrets.values or existingSecret), never config
WORKER_HEALTH_PORT8081The worker's liveness listener (/healthz)
BALEIA_WORKER_METRICS_ADDR:9090The worker's listener for /metrics (Temporal SDK, pool, build) and /healthz; empty disables it
BALEIA_DB_MAX_CONNSapi 20, worker 10Size of Baleia's own database pool (observable as baleia_db_pool_*)
BALEIA_DB_MIN_CONNS2Connections the pool keeps open
BALEIA_DB_MAX_CONN_LIFETIME1hRecycle pool connections after this long
BALEIA_DB_MAX_CONN_IDLE_TIME30mClose pool connections idle for this long
BALEIA_DB_HEALTH_CHECK_PERIOD1mHow often the pool checks idle connections
BALEIA_DB_STATEMENT_TIMEOUT1mstatement_timeout on Baleia's own sessions (not user queries, which use BALEIA_STATEMENT_TIMEOUT); 0 disables it
BALEIA_DB_IDLE_IN_TX_TIMEOUT1midle_in_transaction_session_timeout: a leaked transaction is ended and its locks released; 0 disables it
BALEIA_DB_LOCK_TIMEOUT30slock_timeout on Baleia's own sessions; 0 disables it
BALEIA_HTTP_READ_HEADER_TIMEOUT10sTime a client has to send the request headers to the API
BALEIA_HTTP_IDLE_TIMEOUT2mHow long an idle keep-alive connection to the API stays open
BALEIA_HTTP_SHUTDOWN_TIMEOUT20sHow long the API drains in-flight requests on shutdown (keep it below the pod's termination grace period); 0 waits without a deadline
BALEIA_SECRET_FILE_BASE_DIR(unset)Directory @baleia-secret[file:name] references resolve under (secrets.md); unset refuses file: references. Read once at startup
BALEIA_SQLITE_ROOT(unset)Directory SQLite connections are confined to (symlinks resolved); unset disables the SQLite provider. The API and the worker must see the same files (shared volume)
BALEIA_SQLITE_ALLOW_WRITEfalseLet a SQLite connection that sets read_write open its file read-write; otherwise files open read-only
BALEIA_CONNECTIONS_ALLOW_LOOPBACKfalseLet connections reach loopback addresses. For local development only (make dev / make worker set it); never in a shared deployment
BALEIA_TRINO_ADMIN_USERbaleia_adminTrino identity for catalog DDL/reconcile/maintenance (never user SQL)
BALEIA_TRINO_SERVICE_USERbaleiaWorker fallback identity for executions
BALEIA_TRINO_USER_IDENTITYuuidMap Baleia users to Trino users: uuid→u_<uuid> or email
BALEIA_AGENTS_ENABLEDfalseMount the agent management API and /mcp (mcp.md). Off by default
BALEIA_AGENT_TOKEN_DEFAULT_TTL720hDefault lifetime of an agent token when expires_in_days is omitted
BALEIA_AGENT_TOKEN_MAX_TTL2160hMaximum accepted agent-token lifetime (90 days)
BALEIA_AGENT_MAX_ROWS5000Ceiling for an agent policy's max_rows_returned
BALEIA_AGENT_MAX_RESULT_BYTES1048576Ceiling for max_result_bytes (1 MiB)
BALEIA_AGENT_MAX_QUERY_RUNTIME_SECONDS900Ceiling for max_query_runtime_seconds
BALEIA_AGENT_MAX_CONCURRENT_QUERIES10Ceiling for max_concurrent_queries
BALEIA_AGENT_MAX_QUERIES_PER_HOUR2000Ceiling for max_queries_per_hour
BALEIA_AGENT_MAX_TOOL_CALLS_PER_MINUTE600Ceiling for max_tool_calls_per_minute
BALEIA_MCP_ALLOWED_ORIGINS(unset)Comma-separated Origin allow-list for /mcp; empty rejects any request that carries one

Credential encryption​

Connection credentials are stored as v1:<key-id>:<base64> envelopes: AES-256-GCM under a key derived (HKDF-SHA256) from BALEIA_ENCRYPTION_KEY, with the connection id as additional authenticated data, so a ciphertext copied to another connection does not open. A value that cannot be opened is reported as credentials_unreadable; it is never used as if it were the secret.

  • Fresh install: set BALEIA_ENCRYPTION_KEY before saving the first credential. Without it the API starts with a warning and refuses to store credentials.
  • Upgrading from JWT_SECRET-encrypted credentials: set BALEIA_ENCRYPTION_KEY, keep the existing JWT_SECRET, then run the one-shot, idempotent migration (make migrate-credentials, or /migrate -cmd=credentials in the image). It requires a valid JWT_SECRET to open the legacy values. Rows that cannot be decrypted are listed by id and left untouched; re-enter those credentials.
  • Rotating the key: move the old value to BALEIA_ENCRYPTION_KEY_PREVIOUS and set the new BALEIA_ENCRYPTION_KEY. Values are read with either key, but reading never re-seals them. Run make migrate-credentials (or /migrate -cmd=credentials) to move every envelope to the new key; only after it reports no failures is it safe to drop BALEIA_ENCRYPTION_KEY_PREVIOUS. Envelopes left on the old key become credentials_unreadable once it is removed.

See also secrets.md for external secret references and the catalog registry at rest.