Migration to LightHouse 0.22.X¶
This page covers the migration to the database-managed trust anchor repository and dynamically configured federation endpoints.
Info
You must be at least on version 0.20.0 to migrate to 0.22.X.
Breaking Changes
Endpoint paths, URLs, authentication trust anchors, and type-specific endpoint configuration (resolve settings, entity collection settings, enroll checker config, etc.) have been removed from the config file.
You MUST migrate these settings to the database.
After migration, all federation endpoint management is done via the Admin API.
Backup Before Migration
Before starting the migration process, create backups of:
- Your configuration file (
config.yaml) - Your database
What Changed¶
Trust Anchor Repository¶
Previously, trust anchors were configured independently at multiple locations in
the config file: endpoints.auth.trust_anchors, per-endpoint
auth_trust_anchors, entity checker trust_anchors, and
allowed_trust_anchors lists. This meant the same trust anchor could appear at
several places with duplicated JWKS, and updating a TA's keys required changing
every location.
LightHouse now has a common trust anchor repository stored in the database. All trust anchors and their JWKS are managed in a single place. Every usage (client auth, entity checks, allowed trust anchors) references a trust anchor by entity ID and resolves its JWKS live from the repository at request time.
See Trust Anchor Repository for details.
Automatic JWKS Refreshing¶
Trust anchors in the repository can optionally have their JWKS automatically
refreshed. When enable_jwks_update is set to true for a trust anchor,
LightHouse periodically polls the trust anchor's entity configuration and
updates the stored JWKS when keys change.
Dynamic Federation Endpoints¶
Federation endpoints (fetch, list, resolve, trust mark, etc.) are now managed in
the database. Their paths, URLs, authentication settings, and type-specific
configuration are stored in the federation_endpoints table and can be changed
at runtime via the Admin API without restarting LightHouse.
Endpoint paths are served via a single catch-all dispatcher that looks up the path in an in-memory registry. Changes via the Admin API trigger an immediate registry reload and entity configuration cache invalidation.
See Endpoints for details.
Config File Simplification¶
The endpoints section in the config file has been reduced to only JTI storage
settings (auth.jti_backend and auth.jti_cleanup_interval). All other
endpoint configuration is now database-managed.
Key Rotation¶
Key rotation has been managed in the database and configurable via the Admin
API (GET/PUT/PATCH /api/v1/admin/keys/rotation) since 0.20.0. The existing
options (enabled, interval, overlap) are unchanged.
Two new options have been added to control how far in advance a new key is published in the JWKS before it becomes the active signing key:
| Option | Description |
|---|---|
key_announcement_lead_time |
Fixed duration (in seconds) how far in advance a new key is published in the JWKS before it becomes the active signing key. |
key_announcement_lead_time_ec_multiplier |
Multiplier for the entity configuration lifetime to compute the announcement lead time. Takes precedence over key_announcement_lead_time if set. |
The key announcement lead time gives clients time to fetch the updated entity configuration and cache the new key before the old key is retired. The effective lead time is resolved as follows:
- If
key_announcement_lead_time_ec_multiplier > 0: multiplier × entity configuration lifetime. - If
key_announcement_lead_time > 0: the fixed duration. - Default:
max(5 × entity configuration lifetime, 24h).
The result is clamped to a minimum of the entity configuration lifetime; if the configured value is shorter, the EC lifetime is used instead and a warning is logged.
Info
In the past the key announcement lead time was set to one entity configuration lifetime. This is enough only if all client always fetch the entity configuration as soon as it expires. This is obvisouly a wrong assumption and the lead time should be set to a bigger value.
Prefork Mode Removed¶
The server.prefork config option and LH_SERVER_PREFORK environment variable
have been removed. LightHouse now always runs as a single process. If your
config file contains prefork: true, it will be silently ignored — remove it
from your config.
Prefork mode caused consistency issues with in-memory caches, the trust anchor repository, endpoint registry, and entity configuration metadata, since child processes could not receive updates made via the Admin API in the parent process.
Migration Steps¶
Step 1: Migrate trust anchors and endpoints to the database¶
The config2db command connects to whatever database LightHouse uses and
migrates the trust anchors and federation endpoints from the config file into
it. Use the driver-specific flags below for your database backend (SQLite,
MySQL, or PostgreSQL).
./lhmigrate config2db \
--config=/etc/lighthouse/config.yaml \
--db-type=sqlite \
--db-dir=/var/lib/lighthouse \
--only=trust_anchors,endpoints \
--update-config
./lhmigrate config2db \
--config=/etc/lighthouse/config.yaml \
--db-type=mysql \
--db-dsn='user:pass@tcp(127.0.0.1:3306)/lighthouse?charset=utf8mb4&parseTime=True' \
--only=trust_anchors,endpoints \
--update-config
./lhmigrate config2db \
--config=/etc/lighthouse/config.yaml \
--db-type=postgres \
--db-dsn='host=localhost user=lighthouse password=secret dbname=lighthouse port=5432' \
--only=trust_anchors,endpoints \
--update-config
For SQLite, --db-dir points at the directory (or database file). For MySQL
and PostgreSQL, --db-dsn is the connection string; --db-dir is not used.
Using Docker
The lhmigrate tool is included in the Docker image.
To run it, override the image entrypoint with --entrypoint /lhmigrate, and
mount your config file and data directory. For a containerized MySQL or
PostgreSQL, also attach to the database container's network so the DSN's
hostname resolves:
docker run --rm \
-v /etc/lighthouse:/config:ro \
-v /var/lib/lighthouse:/data \
--entrypoint /lhmigrate \
oidfed/lighthouse:0.22 \
config2db \
--config=/config/config.yaml \
--db-type=sqlite \
--db-dir=/data \
--only=trust_anchors,endpoints \
--update-config
docker run --rm \
-v /etc/lighthouse:/config:ro \
--network db-net \
--entrypoint /lhmigrate \
oidfed/lighthouse:0.22 \
config2db \
--config=/config/config.yaml \
--db-type=mysql \
--db-dsn='user:pass@tcp(mysql:3306)/lighthouse?charset=utf8mb4&parseTime=True' \
--only=trust_anchors,endpoints \
--update-config
docker run --rm \
-v /etc/lighthouse:/config:ro \
--network db-net \
--entrypoint /lhmigrate \
oidfed/lighthouse:0.22 \
config2db \
--config=/config/config.yaml \
--db-type=postgres \
--db-dsn='host=postgres user=lighthouse password=secret dbname=lighthouse port=5432' \
--only=trust_anchors,endpoints \
--update-config
This command:
- Collects all trust anchors from every config file location
(
federation_data.trust_anchors,endpoints.auth.trust_anchors, per-endpointauth_trust_anchors, entity checkertrust_anchors,allowed_trust_anchors) and stores them in thetrust_anchorstable, deduplicated by entity ID. - Creates
federation_endpointsrows for each configured endpoint, storing the path, URL, auth settings (linked to trust anchors via a join table), and type-specific configuration as a JSON blob. - Removes the migrated options from the config file (
--update-config).
Dry Run
Add --dry-run -v to preview what would be migrated without making changes.
The driver-specific flags work the same as in the examples above:
./lhmigrate config2db \
--config=/etc/lighthouse/config.yaml \
--db-type=sqlite \
--db-dir=/var/lib/lighthouse \
--only=trust_anchors,endpoints \
--dry-run -v
./lhmigrate config2db \
--config=/etc/lighthouse/config.yaml \
--db-type=mysql \
--db-dsn='user:pass@tcp(127.0.0.1:3306)/lighthouse?charset=utf8mb4&parseTime=True' \
--only=trust_anchors,endpoints \
--dry-run -v
./lhmigrate config2db \
--config=/etc/lighthouse/config.yaml \
--db-type=postgres \
--db-dsn='host=localhost user=lighthouse password=secret dbname=lighthouse port=5432' \
--only=trust_anchors,endpoints \
--dry-run -v
Interactive Alternative
lhsetup provides an interactive wizard that
covers all DB-managed configuration. It can prepopulate prompts from an
existing config file (--config) and is useful both as an alternative to
config2db and for configuring options that have no config-file equivalent.
Step 2: Verify the migration¶
Start LightHouse and verify via the Admin API:
# List all trust anchors
curl -u admin:password https://localhost:8081/api/v1/admin/trust-anchors
# List all federation endpoints
curl -u admin:password https://localhost:8081/api/v1/admin/federation-endpoints
# Check the entity configuration reflects the correct endpoint URLs
curl https://localhost:8080/.well-known/openid-federation
Step 3: (Optional) Enable JWKS refreshing¶
After migration, you can enable automatic JWKS refreshing for individual trust anchors via the Admin API:
curl -X PUT -u admin:password \
-H "Content-Type: application/json" \
-d '{"entity_id":"https://ta.example.com","enable_jwks_update":true,"key_poll_interval":3600}' \
https://localhost:8081/api/v1/admin/trust-anchors/https://ta.example.com
What Gets Migrated¶
Trust Anchors¶
| Config Location | DB Table | Notes |
|---|---|---|
federation_data.trust_anchors |
trust_anchors |
Full TA config with JWKS, enable_jwks_update, key_poll_interval |
endpoints.auth.trust_anchors |
trust_anchors |
Merged with the above, deduplicated by entity ID |
Per-endpoint auth_trust_anchors |
trust_anchors |
Entity IDs only (no JWKS in config); stored as TA rows if not already present |
Entity checker trust_anchors |
trust_anchors |
Entity IDs extracted from checker config, stored as TA rows |
resolve.allowed_trust_anchors |
trust_anchors |
Entity IDs only |
entity_collection.allowed_trust_anchors |
trust_anchors |
Entity IDs only |
Federation Endpoints¶
| Config Location | DB Table | Notes |
|---|---|---|
endpoints.fetch.path/url/auth_* |
federation_endpoints |
Type fetch |
endpoints.list.path/url/auth_* |
federation_endpoints |
Type list |
endpoints.resolve.* |
federation_endpoints |
Type resolve; config JSON includes allowed_trust_anchors, use_entity_collection_allowed_trust_anchors, grace_period, time_elapsed_grace_factor, proactive_resolver |
endpoints.trust_mark.path/url/auth_* |
federation_endpoints |
Type trust_mark |
endpoints.trust_mark_status.path/url/auth_* |
federation_endpoints |
Type trust_mark_status |
endpoints.trust_mark_list.path/url/auth_* |
federation_endpoints |
Type trust_mark_listing |
endpoints.historical_keys.path/url/auth_* |
federation_endpoints |
Type historical_keys |
endpoints.enroll.* |
federation_endpoints |
Type enroll; config JSON includes checker config with trust_anchors converted to entity-id references |
endpoints.enroll_request.path/url/auth_* |
federation_endpoints |
Type enroll_request |
endpoints.trust_mark_request.path/url/auth_* |
federation_endpoints |
Type trust_mark_request |
endpoints.entity_collection.* |
federation_endpoints |
Type entity_collection; config JSON includes allowed_trust_anchors, interval_seconds, concurrency_limit, pagination_limit |
endpoints.auth.all_require_auth |
(applied per-endpoint) | Each endpoint's auth_enabled is set to true if all_require_auth was true |
Auth Trust Anchor Mapping¶
Each endpoint's auth_trust_anchors are linked to trust anchor rows via the
federation_endpoint_auth_trust_anchors join table, which has foreign key
constraints with ON DELETE CASCADE.
Config File After Migration¶
After migration, the endpoints section is removed from the config file. JTI
storage settings are now under storage.endpoint_auth:
storage:
driver: sqlite
data_dir: /data
endpoint_auth:
jti_backend: cache
jti_cleanup_interval: 1h
All other configuration remains in the config file as before (entity_id,
server.*, storage.*, signing.*, api.*, stats.*, logging.*,
cache.*).
Environment Variable Change
The JTI environment variables have been renamed:
| Old | New |
|---|---|
LH_ENDPOINTS_AUTH_JTI_BACKEND |
LH_STORAGE_ENDPOINT_AUTH_JTI_BACKEND |
LH_ENDPOINTS_AUTH_JTI_CLEANUP_INTERVAL |
LH_STORAGE_ENDPOINT_AUTH_JTI_CLEANUP_INTERVAL |
The lhmigrate config step handles the YAML move automatically, but you
must update any environment variables manually.
Post-Migration Management¶
After migration, use the Admin API to manage trust anchors and endpoints:
| Resource | Admin API Endpoint |
|---|---|
| Trust Anchors | GET/POST/PUT/DELETE /api/v1/admin/trust-anchors |
| Federation Endpoints | GET/POST/PUT/DELETE /api/v1/admin/federation-endpoints |
| Endpoint Auth Trust Anchors | PUT /api/v1/admin/federation-endpoints/{type}/auth-trust-anchors |
See the Admin API documentation for details.
The interactive lhsetup wizard can also be used
to review and change any DB-managed configuration at runtime.
New Endpoint Types (Not Migrated)¶
Two new federation endpoint types were added in 0.22 and have no equivalent in
the old config file, so lhmigrate config2db does not create them. If you want
to use subordinate JWKS refreshing, create them manually via the Admin API after
migration:
| Endpoint Type | Purpose |
|---|---|
jwks_update_trigger |
A subordinate POSTs to request LightHouse re-fetches its JWKS. |
jwks_update |
A subordinate POSTs a signed JWK Set (application/jwk-set+jwt) with its new keys directly. |
# Create the JWKS Update Trigger endpoint
curl -X POST -u admin:password \
-H "Content-Type: application/json" \
-d '{"type":"jwks_update_trigger","path":"/jwks/update-trigger","auth_enabled":false}' \
https://localhost:8081/api/v1/admin/federation-endpoints
# Create the JWKS Update endpoint
curl -X POST -u admin:password \
-H "Content-Type: application/json" \
-d '{"type":"jwks_update","path":"/jwks/update"}' \
https://localhost:8081/api/v1/admin/federation-endpoints
See Subordinate JWKS Refreshing for full details on these endpoints and the periodic-refresh option.
Logging Changes¶
The logging library has been switched from logrus to zerolog. This affects
the logging configuration section:
Removed config keys¶
The "smart logger" (logging.internal.smart.*) was dead code (never called
from any handler) and has been removed.
Added config keys¶
logging.internal.stderr_format— output format for stderr:console(human-friendly, colored; default) orjson(structured JSON).logging.internal.dir_format— output format for log files:json(structured JSON; default) orconsole(human-friendly, no ANSI codes).
Each target (stderr and file) can use a different format independently. For
example, stderr_format: console with dir_format: json gives colored
console output on the terminal while writing structured JSON to the log file.
Backwards Compatibility
Existing configs with logging.internal.smart keys will simply ignore
those keys (YAML unmarshalling ignores unknown fields). No action is
required, but you may remove them for cleanliness.