CCSN Crossplane provider generated with Upjet v2 from a checked-in source snapshot of the
terraform-provider-logto fork (based on Lenstra v0.0.15, MIT).
The controller embeds the Terraform Plugin Framework provider through protocol
v6; Terraform/OpenTofu is required only to regenerate the schema.
Each resource has a namespaced API and a legacy cluster-scoped API, version
v1alpha1. Prefer namespaced resources on Crossplane v2.
| Terraform resource | Namespaced API group | Kind |
|---|---|---|
logto_application |
application.logto.m.crossplane.io |
Application |
logto_application_secret |
application.logto.m.crossplane.io |
Secret |
logto_application_user_consent_scopes |
application.logto.m.crossplane.io |
UserConsentScopes |
logto_api_resource |
api.logto.m.crossplane.io |
Resource |
logto_api_resource_scope |
api.logto.m.crossplane.io |
Scope |
logto_connector |
connector.logto.m.crossplane.io |
Connector |
logto_sign_in_experience |
configuration.logto.m.crossplane.io |
SignInExperience |
logto_account_center |
configuration.logto.m.crossplane.io |
AccountCenter |
logto_id_token_config |
configuration.logto.m.crossplane.io |
IDTokenConfiguration |
logto_oidc_session_config |
configuration.logto.m.crossplane.io |
OIDCSessionConfiguration |
logto_role |
role.logto.m.crossplane.io |
Role |
logto_user |
user.logto.m.crossplane.io |
User |
References connect secrets to applications, scopes to APIs, roles to scopes,
and users to roles. Configure credentials with a logto.m.crossplane.io/v1beta1
ProviderConfig in the managed resource's namespace, or a ClusterProviderConfig.
The referenced Secret's credentials key contains JSON with hostname
(hostname only, no scheme), resource (Management API audience), application_id,
and application_secret. Use a machine-to-machine application authorized for
Management API all; for the default OSS tenant the audience is commonly
https://default.logto.app/api (verify it in your console).
Application exports clientId and existing named secrets as internal state
connection details. Secret exports clientId, clientSecret, and
attribute.value (reserved by Upjet for state reconstruction). Credential
values are absent from CRD spec/status. writeConnectionSecretToRef writes a
Secret in the resource's namespace. The Secret kind in this API group is a
Logto managed resource, distinct from a core Kubernetes Secret.
The repository builds independently. go.mod points to the reviewed source
snapshot in third_party/terraform-provider-logto; its manifest records the
upstream base and SHA-256 of every included file. To update it from the adjacent
fork, run make sync-provider, review the diff, then regenerate and verify.
make snapshot detects accidental modifications to the embedded source.
nix develop path:.
make generate
make verifymake generate builds the fork, extracts its schema using a local development
override (no registry installation/init), scrapes local resource docs, and runs
Upjet, controller-gen and angryjet. Schema exports use a canonical registry address
so Terraform and OpenTofu produce identical generated files. make verify checks
the snapshot, runs offline race tests and vet in both modules, and builds a static
controller under .work/bin/provider.
Caches stay in ../.local; override GOMODCACHE, GOCACHE, or GOPATH if needed.
When the default Go proxy is unavailable, set GOPROXY to your preferred mirror.
Generated CRDs are in package/crds; runtime image definition is in
cluster/images/provider-upjet-logto/Dockerfile. The runtime image uses a
digest-pinned nonroot base. make image builds it
without accessing credentials. Distribution still requires an approved package
registry, signed release process, and a tested Crossplane package.
Start with examples/namespaced/application/import.yaml and managementPolicies: [Observe]; fill verified application IDs and named-secret IDs. New application
and named-secret examples are in application.yaml; they intentionally omit
Delete. Keep the existing consumer Secret distribution until the connection
Secret has been checked. No production Flux kustomization includes these files.
Named secrets and legacy application secrets are separate Logto APIs. This
provider does not rotate or import legacy secrets. Replacing a named-secret
resource explicitly replaces the owned credential; expiry and rotation policies
are not implemented yet. Application client_secrets is read-only and never
creates or rotates secrets. Terraform sensitive fields are still present in
Terraform state; use an encrypted and access-controlled backend.
UserConsentScopes references an Application with applicationIdRef and
authoritatively manages its userScopes, for example [profile, email].
Use one consent resource per application. Omit openid, which is implicit.
The controller detects drift, revokes obsolete user scopes, and assigns missing
scopes in place; an explicit userScopes: [] revokes all user profile scopes.
A missing userScopes value never requests revocation.
Explicit forProvider.userScopes values, including [], override
initProvider.userScopes. Initialization grants remain retryable until they
converge. Valid partial creations retain their external application ID even when
a mutation fails, so restarts and deletion can recover without losing ownership.
After convergence, changes to initialization values and external grants
are observed without modifying grants. Use forProvider.userScopes for continuous
management. The controller persists initialization completion in the
logto.crossplane.io/user-consent-scopes-initialized annotation across restarts.
A new resource becomes Ready after its initial grants converge and completion
is persisted. Concurrent GitOps changes cause metadata writes to retry with a
fresh resource snapshot.
Grant mutations use the synchronous Framework connector, so initialization is
confirmed by a fresh read after the write finishes. A parent supplied only in
initProvider.applicationId is never promoted into forProvider, including when
late initialization is enabled or initial grants must retry. Removing the initial
parent configuration preserves this behavior. After initialization, that parent
remains fixed until a missing resource is recreated.
Recreating a missing resource uses the current initialization defaults and
resolves their references again. Completed initial references cannot block
ongoing observation or explicit permission changes. Adopting an existing
application by external name also ignores its initial references before the
initialization marker is persisted.
Recreation preparation preserves completion until a fresh read confirms absence;
a parent that reappears retains its previous initialization state.
API resource and organization consent scopes are preserved. Import uses the
application ID. Deletion revokes user profile scopes without deleting the app;
omit Delete from managementPolicies to retain grants when removing the CR.
Users still approve requested permissions on Logto's consent screen.
See examples/namespaced/application/consent-scopes.yaml. This CR requires a
provider package built from this revision or newer. Publish that package and
update the GitOps provider digest before reconciling manifests using the new
kind; the previously released v0.1.0 package does not include this controller.
Offline tests cover all twelve resource lifecycles and Framework protocol v6
create/plan/update/read/delete, partial creation, pagination, bounded retries and cancellation,
token reuse/refresh/concurrency, sensitive schemas, idempotent deletion,
metadata preservation, credentials isolation, and status redaction. All 29
CRDs pass the Kubernetes API server structural/CEL validation functions.
Real acceptance tests use the integration build tag and temporary loopback-only
LOGTO_TEST_CREDENTIALS. make test-integration starts an isolated API Server
and executes the shipped controller. It validates the seven-resource reference
graph, drift repair, restart recovery, Observe adoption, connection Secrets,
legacy cluster APIs and explicit empty role/scope revocation against Logto 1.40.1.
Consent scope acceptance includes Terraform protocol CRUD/import, preservation
of API consent grants, recovery when an initial write configured through
initProvider fails, and explicit empty-list revocation with initialization
defaults still present. These tests run through the existing
make test-integration release gate.
KUBEBUILDER_ASSETS must point to local etcd, kube-apiserver and kubectl binaries.
Connector configuration uses a SecretRef, and its sensitive JSON stays out of
status. Required sensitive selectors in initProvider are omitted when unset so
they cannot mask a valid forProvider selector. Singleton resources manage explicit
JSON contracts, adopt external ID default, and never reset tenant configuration
on deletion. Organizations, JWT customizer scripts, and SAML-specific settings
are not managed yet. The validated Logto version is 1.40.1. CI includes real Logto/controller acceptance
and amd64/arm64 package builds. Actual Crossplane Core installation and upgrade,
production RBAC, load/soak testing and signed distribution remain release gates.
Automatic credential rotation is not implemented.
Keep LateInitialize when creating resources whose IDs are assigned by Logto:
the current Upjet async controller uses that policy to persist a generated
external-name. Observe-only adoption supplies the existing external-name and
does not need LateInitialize. Supply a connection Secret for sensitive state.
Upstream references: Terraform provider, Upjet template, Upjet, Logto application-secret API.
See quality assessment for executed checks, findings and production readiness gates.
Embedded dependency updates belong to the Terraform fork. Dependabot does not modify the snapshot directly: sync and review it after source dependency updates.
See operations and release gates for real acceptance, package verification, monitoring and recovery.
nix develop --command make package
GOARCH=arm64 nix develop --command make packageEach build creates .work/provider-upjet-logto.xpkg, runtime.spdx.json and
SHA256SUMS. Packaging embeds the compiled controller, checks the non-root
runtime, CA certificates and all 29 CRDs, and inventories dependencies with
Syft. The local package builder does not need a container daemon.
This repository derives from the Apache-2.0 Upjet provider template; see LICENSE. The embedded Terraform fork retains its MIT license. Source ownership and upstream references are recorded in NOTICE.