Configuration Model

How deployment inputs are organized in the bsqai-platform CLI.

Agentic Friendly

This page explains how deployment configuration is structured in the bsqai-platform CLI.

Configuration is split into two layers: a global platform.toml file that defines platform-wide settings, and per-component variables.toml files that define each component's identity, resources, secrets, and SSO enrollment. Environment variables can override any value at any layer.

Configuration layers

1. Global platform defaults

platform.toml is located at src/manifests/source/platform.toml. It defines the shared foundation used across all platform applications.

SectionPurpose
[common]Base domain, registry, storage classes, image pull secret, realm name, affinity enforcement
[git]Manifests repository URL, branch, and path for ArgoCD reconciliation
[custom_tls]Optional TLS material (CA cert, certificate, key) when DNS-based issuance is not used
[proxy]HTTP/HTTPS proxy and no-proxy settings
[azure]Azure-specific: subscription, DNS, tenant, client credentials
[gcp]GCP-specific: service account namespaces
[apps]Sync wave ordering for parent ArgoCD Applications (common=1, coreai=2, proai=3)
[default]Default sizing values (CPU, memory, replicas) applied when a component does not specify its own

2. Environment files

Environment variables are loaded in three layers, from lowest to highest priority:

  1. platform.env — shared settings committed alongside the deployment (lowest priority)
  2. local.env — personal overrides, gitignored (overrides platform.env)
  3. OS environment — always wins (highest priority, used mainly in CI/CD)

Both .env files live at the repository root. They are loaded automatically when the CLI starts.

3. Per-component configuration

Each component has a variables.toml file inside its source directory under src/manifests/source/<group>/<component>/. The file is organized into TOML tables:

[component]
name          = "keycloak"
namespace     = "keycloak"
version       = "26.5.2"
format        = "helm"
chart_name    = "keycloak"
chart_version = "18.10.0"
release_name  = "keycloak"
url_prefix    = "iam"
parent_app    = "common"
sync_wave     = "7"
sync_options  = "- SkipDryRunOnMissingResource=true"
sync_annotations = ""

[database]
postgresql_name     = "keycloak"
postgresql_owner    = "keycloak"
postgresql_password = {value = "", secret = true}

The [component] table is required and defines identity, chart coordinates, namespace, and ArgoCD sync behavior. Additional tables ([database], [sso], [auth], [server], etc.) are component-specific and become template variables prefixed with the table name.

4. Variable resolution

When the CLI loads a component, it resolves each variable through this chain:

  1. Environment variable override — if an env var matching COMPONENTNAME_TABLENAME_KEY (uppercased, hyphens replaced with underscores) exists, it wins
  2. Explicit TOML value — a non-empty value in variables.toml is used as-is
  3. Generator — if the variable has a generate key (e.g., generate = "s3_access_key_id"), a value is generated automatically when the TOML value is empty
  4. Global default fallback — for flagged values (secret = true, token = true, cert = true), the CLI falls back to GLOBAL_SECRET_DEFAULT, GLOBAL_TOKEN_DEFAULT, or GLOBAL_CERT_DEFAULT environment variables
  5. Empty string — if none of the above produce a value

Type coercion is automatic. The CLI matches the type of the TOML reference value: booleans ("true"/"false"), integers, and floats are coerced from string env vars. Complex types (dicts and lists) must be provided as JSON-encoded strings when overriding from an environment variable or .env file.

Secrets management

Secrets in variables.toml use a metadata wrapper instead of a plain value:

postgresql_password = {value = "", secret = true}

The secret = true flag tells the CLI that the value is sensitive. When the rendered template produces a Kubernetes Secret manifest, the CLI automatically seals it with kubeseal before writing the output. The sealed secret can be safely stored in Git.

Three flag types exist:

FlagFallback env varTypical use
secret = trueGLOBAL_SECRET_DEFAULTPasswords, client secrets
token = trueGLOBAL_TOKEN_DEFAULTAPI tokens, registry tokens
cert = trueGLOBAL_CERT_DEFAULTCertificate material

Auto-generated values are also supported. S3 access keys use built-in generators:

access_key_id     = {value = "", generate = "s3_access_key_id"}
secret_access_key = {value = "", generate = "s3_secret_access_key"}

When the value is empty and no environment override exists, the generator produces a cryptographically random credential.

SSO scope

All platform components with a user-facing endpoint are enrolled into Keycloak for single sign-on. This is controlled per component through an [sso] table in variables.toml.

How it works

When a component has [sso] enabled = true, the CLI generates:

  • an SSO configuration secret containing the OIDC client definition, groups, and roles
  • a setup job that registers the component with Keycloak before deployment (uses a negative sync wave to run before the component)
  • a PostDelete cleanup job that removes the Keycloak client when the component is deleted

When enabled is false or the [sso] table is absent, none of these resources are created.

SSO configuration structure

The [sso] table defines the full OIDC client registration:

[sso]
enabled       = true
client_id     = "grafana"
client_secret = {value = "", secret = true}
description   = "Grafana OAuth client"

default_scope                = ["openid", "profile", "email"]
standard_flow_enabled        = true
direct_access_grants_enabled = true
service_accounts_enabled     = false
redirect_uris                = ["*"]
groups                       = [{name = "Grafana-Viewer"}]
roles                        = []

Client secrets left empty are auto-generated. Keycloak-side client secrets are stored centrally in the Keycloak component's [clients] table and distributed via sealed secrets.

Components with SSO support

LayerComponents
RuntimeGrafana, PgAdmin, Rook Ceph RGW, ArgoCD
CoreAIPortal, LLM Backend (CoreAI API), MLflow, Temporal, Model Installer, LiteLLM
DataSuperset, Strimzi (Kafka), Airbyte (via OAuth2 Proxy), Attu (via OAuth2 Proxy)

Keycloak enroll credentials

The setup and cleanup jobs authenticate against Keycloak using a dedicated enroll user. The password for this user is controlled by [auth] enroll_password in the Keycloak component's variables.toml. When left empty, a random password is generated.

For a deeper explanation of how the enrollment mechanism works, see the Keycloak component page.

Environment-specific settings

Some settings only apply in specific deployment environments.

Azure

[azure]
enabled             = true
subscription_id     = ""
dns_resource_group  = ""
hosted_zone_name    = ""
tenant_id           = ""
client_id           = ""
client_secret_b64   = ""
dns_client_json     = ""

These control external-dns zone ownership and cert-manager DNS-01 challenge solving in Azure.

GCP

[gcp]
enabled                    = false
gcloud_svc_acct_namespaces = ""

Proxy

[proxy]
no_proxy_url = ""
http_url     = ""
https_url    = ""

Set these when the cluster requires an outbound proxy for internet access.

Custom TLS

[custom_tls]
enabled = false
ca_crt  = ""
crt     = ""
key     = ""

Used when certificates are provided directly instead of issued through DNS automation.

Safe review checklist

Before applying a deployment, validate:

  1. Does the target environment have the required storage classes (rwo_storageclass, rwx_storageclass)?
  2. Does base_domain match a DNS zone the platform can manage?
  3. Is the container registry reachable from the cluster?
  4. Is [git] pointing to the correct manifests repository and branch?
  5. Is the certificate model clear: custom TLS material or DNS-driven issuance?
  6. Are only the needed platform tiers enabled?

Minimal input shape

[common]
base_domain                  = "<platform-domain>"
rwo_storageclass             = "<rwo-storage-class>"
rwx_storageclass             = "<rwx-storage-class>"
registry_name                = "<registry-host>"
registry_platform_repository = "coreai/platform"
registry_backend_repository  = "coreai/backend"
registry_portal_repository   = "coreai/portal"
registry_helm_repository     = "coreai/helm"
realm_name                   = "dataplatform"

[git]
repo_url = "<manifests-repository-url>"
branch   = "<branch>"
path     = "platform"

[custom_tls]
enabled = false

Use that structure as the baseline, then add only the environment-specific and component-specific inputs required by the deployment target.

On this page