Getting Started
Prerequisites
- Python 3.12+
- uv package manager
- Task runner (optional, for convenience commands)
- Docker + Docker Compose (for the full stack)
Install Dependencies
uv sync
Keycloak Bootstrap and Sync
The CLI provisions Keycloak with the scopes and clients defined in clients.yaml.
Step 1: Start Keycloak
Either start just Keycloak from the compose stack:
docker compose up keycloak -d
Or use an existing Keycloak instance and set CELINE_KEYCLOAK_BASE_URL.
Step 2: Bootstrap the Platform and the Admin Client
ENV=dev celine-policies keycloak bootstrap --admin-user admin --admin-password admin
This does two things, in order:
- Converges the realm's platform level from
platform.yaml: Organizations, fine-grained admin permissions, sign-in settings, languages, themes, lifespans and the realm role groups. Only the keys the file names are written. Brute-force protection comes fromCELINE_KEYCLOAK_BRUTE_FORCE_ENABLED(on by default, off underENV=dev), andsmtpServerfromCELINE_KEYCLOAK_SMTP_*whenCELINE_KEYCLOAK_SMTP_HOSTis set.--dry-runshows what would change. - Creates a
celine-admin-cliservice account with realm-management roles, and writes its secret to.client.secrets.yaml. Subsequent commands auto-load credentials from this file. The secret is printed only under a developmentENV.
The emails and login pages need the rec theme, so bootstrap refuses a Keycloak that
does not list it: use this repository's keycloak image, not the stock one.
The file is the store of the credentials the CLI authenticates with, not a log of the last run: bootstrap and sync both merge into it, so neither deletes what the other wrote. It holds one realm's credentials — pointing a command at a different realm replaces its contents, and says so.
Step 3: Sync Scopes and Clients
celine-policies keycloak sync
This reads clients.yaml and ensures Keycloak matches the desired state:
- Creates missing client scopes
- Creates missing service clients with generated secrets
- Assigns default scopes to clients
- Adds audience mappers for cross-service JWT validation
Use --dry-run to preview changes without applying them.
Step 4: Sync Users (optional)
Import users from a rec-registry REC definition YAML:
celine-policies keycloak sync-users ../rec-registry/recs/rec-example.yaml \
--password "demo" --mock
The --mock flag fills placeholder email/name fields for development.
sync-users and sync-orgs write no realm setting: they refuse a realm that bootstrap
and sync have not prepared, and say which to run.
Participants are also added to any group clients.yaml declares under
admin_permissions, so the service account granted over that group can see them — run
keycloak sync first, which is what creates the group. --no-admin-groups turns that off.
See Realm administration.
Development users (optional)
A realm created from the dev import already has them. Any other development realm gets them from:
ENV=dev celine-policies keycloak seed-dev-users
admin, manager, editor and viewer, each with its username as password, in the role group
of the same rank (config/keycloak/dev-users.yaml). It refuses outside a development ENV.
Step 5: Sync Organizations (optional)
Import organizations from an owners.yaml file:
celine-policies keycloak sync-orgs ../dataset-api/owners.yaml
Running the Full Stack
docker compose up -d
This starts:
| Service | Port | Description |
|---|---|---|
keycloak |
8080 | Identity provider |
keycloak-sync |
— | Runs bootstrap + sync on startup, then exits |
sync-users |
— | Imports example users, then exits |
mqtt_auth |
8009 | MQTT auth HTTP backend |
mosquitto |
1883 (MQTT), 1884 (WebSocket) | MQTT broker |
redis |
— | Cache backend for mosquitto-go-auth |
oauth2-proxy |
4180 | OAuth2 reverse proxy |
mailpit |
1025 (SMTP), 8025 (UI) | Keeps Keycloak's outgoing mail; delivers none unless a relay is configured |
Verify the MQTT auth service is running:
curl http://localhost:8009/health
Using Task Commands
task run # Start MQTT auth dev server (with hot reload)
task debug # Start with debugger attached
task test # Run pytest suite
task keycloak:bootstrap # Bootstrap admin client
task keycloak:sync # Sync clients.yaml to Keycloak
task keycloak:sync-users # Sync example REC users
task keycloak:sync-orgs # Sync organizations from owners.yaml
CLI Reference
All celine-policies commands accept --help for detailed usage:
celine-policies --help
celine-policies keycloak --help
celine-policies keycloak sync --help
Common Options
Most keycloak commands share these connection options:
| Option | Env Variable | Default |
|---|---|---|
--base-url |
CELINE_KEYCLOAK_BASE_URL |
http://keycloak.celine.localhost |
--realm |
CELINE_KEYCLOAK_REALM |
celine |
--admin-user |
CELINE_KEYCLOAK_ADMIN_USER |
— |
--admin-password |
CELINE_KEYCLOAK_ADMIN_PASSWORD |
— |
--admin-client-id |
CELINE_KEYCLOAK_ADMIN_CLIENT_ID |
celine-admin-cli |
--admin-client-secret |
CELINE_KEYCLOAK_ADMIN_CLIENT_SECRET |
(auto-loaded from .client.secrets.yaml) |
--secrets-file |
CELINE_KEYCLOAK_SECRETS_FILE |
.client.secrets.yaml |
sync has a third input for the realm — realm: in the declaration it is applying — and it is the lowest-ranked one:
--realm > CELINE_KEYCLOAK_REALM > realm: in clients.yaml > celine
The declaration aims a run nobody aimed, and nothing more. sync prints which input won, because the value alone does not say:
Syncing to Keycloak: http://keycloak.celine.localhost realm=e2e-throwaway (from CELINE_KEYCLOAK_REALM)
Testing
# Run the full test suite
uv run pytest
# Or via task
task test
Next Steps
- Review Scopes & Permissions to understand the platform's OAuth model
- See MQTT Integration for topic patterns and broker configuration
- Check Deployment for the Docker Compose stack details