Back to Onyx

Terraform Provider for Onyx

terraform-provider-onyx/README.md

4.7.0-cloud.48.0 KB
Original Source

Terraform Provider for Onyx

Manages Onyx application configuration declaratively via the Onyx admin API: LLM providers, the deployment default model, API keys, workspace settings, and embedding providers.

Not to be confused with deployment/terraform/, which provisions the infrastructure Onyx runs on (EKS, RDS, ...). This provider configures what runs inside an Onyx deployment.

Resources & data sources

NameManagesImport id
onyx_api_keyAPI keys (/admin/api-key)numeric id
onyx_llm_providerLLM providers + their model list (/admin/llm/provider)numeric id
onyx_llm_provider_defaultThe deployment default (and vision) model — a singletondefault
onyx_settingsWorkspace settings — a singleton, partially managedsettings
onyx_embedding_providerCloud embedding provider credentialsprovider type (e.g. openai)
onyx_credentialConnector credentials (/manage/credential)numeric id
onyx_connectorConnector definitions (/manage/admin/connector)numeric id
data.onyx_llm_providersRead-only list of providers + defaults
data.onyx_embedding_providersRead-only list of embedding providers
data.onyx_settingsRead-only current settings (incl. license tier)
data.onyx_connectorsRead-only list of connectors

Generated per-resource docs live in docs/.

Authentication

The provider needs an API key in the seeded Admin group (or an unrestricted PAT created by an admin user). Create one in the Onyx admin panel (API Keys) or via the API — pass the Admin group id, since a key with no group has no admin permissions:

bash
curl -X POST https://your-onyx/api/admin/api-key \
  -H "Cookie: fastapiusersauth=<admin session>" \
  -H "Content-Type: application/json" \
  -d '{"name": "terraform", "group_ids": [<admin group id>]}'

This first key is inherently chicken-and-egg: it must exist before Terraform can run, so either leave it unmanaged, or terraform import it afterwards (its api_key attribute stays null — the material is only ever returned at creation).

hcl
provider "onyx" {
  endpoint = "https://your-onyx.example.com" # or ONYX_SERVER_URL
  api_key  = var.onyx_api_key                # or ONYX_API_KEY
  # api_prefix defaults to "/api" (the web proxy). Set to "" when pointing
  # directly at the backend (e.g. http://localhost:8080). Also: ONYX_API_PREFIX.
}

API keys work regardless of the deployment's human AUTH_TYPE (basic/OIDC/SAML/cloud), and on Onyx Cloud the tenant is embedded in the key itself.

Known limitations (by API design)

  • Secret drift is undetectable. The API masks api_key/custom_config on read, so rotating them out-of-band (e.g. in the admin UI) is invisible to terraform plan. The configured value is authoritative and is re-asserted on the next apply.
  • onyx_settings and onyx_llm_provider_default don't really delete. Onyx has no reset-settings API and no unset API for the text/vision defaults; destroy removes them from state with a warning and leaves the live values alone. The chat-naming default is the exception: it has an unset API and is cleared on destroy when managed.
  • onyx_embedding_provider updates replace all fields. Keep api_key in configuration — an update applied without it clears the stored key (the API has no keep-stored-key flag). The currently-active embedding provider also cannot be deleted.
  • model_configurations is the list of record. Models omitted from it are removed server-side, and removing the model currently set as deployment default fails — repoint onyx_llm_provider_default first (references order this correctly).
  • onyx_credential payloads are write-only. The API always returns credential_json masked, so it is never refreshed or diffed. admin_public, curator_public and groups have no update endpoint and force replacement instead.
  • onyx_connector does not own its access control. access_type and groups are validated on write but stored on the cc-pair, so Terraform cannot refresh them. Onyx also rewrites an unset prune_freq to 7 days on the first update, which the provider then keeps as the value of record.
  • onyx_connector does not set access control. Onyx applies it when a credential is associated, so it belongs to the connector-credential pair. The connector endpoints still require an access_type in the request body but ignore it, so the provider sends a fixed value rather than offering a knob that would do nothing.
  • A private credential can look deleted. The API hides a credential with admin_public = false from admins other than its creator, and that is indistinguishable from a deleted one, so Terraform would drop it from state and recreate it. Keep admin_public = true (the default) for credentials Terraform manages, or run Terraform with the key that created them.
  • The model list read is the API's display view. It hides obsolete models and dated duplicates, so writes (including the auto-mode pass-through, which is also not atomic with its read) cannot preserve rows the API hides. The admin UI round-trips the same filtered view; a keep-models flag on the upsert API is the planned structural fix.

Development

Requires Go (see go.mod) and the Terraform CLI.

bash
go build ./...        # build
go test ./...         # unit tests (no Onyx needed)

Running it against a local build

Point Terraform at your locally-built binary with a dev_overrides block in ~/.terraformrc:

hcl
provider_installation {
  dev_overrides {
    "onyx-dot-app/onyx" = "/path/to/onyx/terraform-provider-onyx"
  }
  direct {}
}

Then go build here and run terraform plan/apply (skip terraform init) in any config using the provider.

Acceptance tests

Acceptance tests run real CRUD cycles against a live Onyx deployment (they create and destroy providers/keys and briefly modify workspace settings — use a dev deployment):

bash
TF_ACC=1 ONYX_TF_ACC_SERVER_URL=http://localhost:8080 go test ./internal/provider/ -v
  • ONYX_TF_ACC_API_PREFIX defaults to "" (direct backend). Set /api when targeting the web server.
  • Auth: set ONYX_TF_ACC_API_KEY to an existing admin key, or let the harness bootstrap one by logging in as ONYX_TF_ACC_ADMIN_EMAIL/ONYX_TF_ACC_ADMIN_PASSWORD (defaults: [email protected] / TestPassword123!; on a fresh deployment the first registered user becomes admin automatically).

Without TF_ACC these tests skip, so plain go test ./... (and the repo's Go CI) stays green with no Onyx running.

To test against an API server that does not touch your dev database, give it a database of its own. This reuses the running Postgres, Redis, OpenSearch and MinIO containers (the container name follows your compose project, so adjust it if yours differs):

bash
docker exec onyx-relational_db-1 psql -U postgres -c "CREATE DATABASE onyx_tf_acc;"
cd backend && POSTGRES_DB=onyx_tf_acc uv run alembic upgrade head
POSTGRES_DB=onyx_tf_acc AUTH_TYPE=basic LICENSE_ENFORCEMENT_ENABLED=false \
  ENABLE_PAID_ENTERPRISE_EDITION_FEATURES=true \
  USER_AUTH_SECRET="$(openssl rand -hex 32)" \
  uv run uvicorn onyx.main:app --port 8081

Each variable earns its place. AUTH_TYPE=basic gives the harness a login to bootstrap its key with. License enforcement must be off or API key creation answers 402. The enterprise features flag registers the user-group routes, which the harness reads to find the Admin group its key needs.

Docs

docs/ is generated — edit schema MarkdownDescriptions and examples/, then:

bash
go generate .   # runs tfplugindocs; needs terraform on PATH

Publishing (future)

The public Terraform Registry requires a standalone GitHub repo named exactly terraform-provider-onyx with GPG-signed goreleaser artifacts. Until a release mirror is set up, install via dev_overrides (above) or a private registry/filesystem mirror.