realm

Manage realms, the isolated tenants that hold clients, users, roles, and credentials.

ferris-ctl realm <subcommand>

Read operations target the realm resolved from your context (or --realm). See Authentication.

realm list

List all realms.

ferris-ctl realm list

Table columns: NAME, ID.

realm get

Show a single realm’s details.

ferris-ctl realm get <name>
ArgumentRequiredDescription
<name>yesRealm name

realm create

Create a new realm.

ferris-ctl realm create <name>
ArgumentRequiredDescription
<name>yesName of the realm to create

realm delete

Delete a realm. This prompts for confirmation, since it also removes the realm’s clients, users, and roles.

ferris-ctl realm delete <name> [--force]
ArgumentRequiredDescription
<name>yesName of the realm to delete
--force / -fnoSkip the confirmation prompt

Confirmation in scripts

Without --force, the command refuses to run in a non-interactive shell rather than deleting silently. Pass --force (or -f) in CI and automation.

realm role

Manage the roles of a realm, or the roles scoped to one of its clients. Every subcommand takes --realm to target a realm other than the context default, and --client <client_id> to work on that client’s roles instead of the realm’s.

realm role create

ferris-ctl realm role create <name> [--description <text>] [--permission <name>]... [--realm <realm>] [--client <client_id>]
ArgumentRequiredDescription
<name>yesRole name
--descriptionnoFree-text description
--permissionnoA permission granted by the role. Repeat the flag for several
--realmnoRealm (defaults to the context realm)
--clientnoCreate a client role scoped to this client id, instead of a realm role

Permissions are passed by their snake_case name, for example manage_users. See the permissions reference for the full list.

ferris-ctl realm role create user-admin \
  --description "Create and update users" \
  --permission manage_users \
  --permission query_users \
  --permission view_users
ferris-ctl realm role create service-reader --client backend

Unknown permission names are dropped

A permission name FerrisKey does not recognize is ignored rather than rejected, so a typo produces a role that grants nothing. Check the created role with realm role get after creating it.

realm role list

ferris-ctl realm role list [--realm <realm>] [--client <client_id>]

Lists realm roles, or the roles of --client when given. Table columns: NAME, ID.

realm role get

ferris-ctl realm role get <name> [--realm <realm>] [--client <client_id>]

realm role delete

ferris-ctl realm role delete <name> [--realm <realm>] [--client <client_id>] [--force]
ArgumentRequiredDescription
<name>yesRole name
--realmnoRealm (defaults to the context realm)
--clientnoDelete a client role instead of a realm role
--force / -fnoSkip the confirmation prompt (required in non-interactive shells)

realm import

Import a realm (its settings, roles, clients, and users) from a description file, a live Keycloak, or a live Zitadel instance.

ferris-ctl realm import --from <kind> [source flags] [--target-realm <name>] [--dry-run]
FlagDescription
--fromSource kind: config, keycloak, or zitadel (optional if --source-ref is given)
--source-refName of a stored source; inline flags below override its values
--filePath to a realm description file (required for --from config); .yaml, .yml, or .toml
--source-urlBase URL of the source instance (Keycloak / Zitadel)
--source-realmSource realm name (Keycloak)
--source-orgSource organization id (Zitadel); sent as the x-zitadel-orgid header
--source-client-idClient id for source authentication (Keycloak client credentials)
--source-client-secretClient secret for source authentication (Keycloak)
--source-tokenBearer token / personal access token (Zitadel PAT, or a ready Keycloak token)
--target-realmOverride the name of the realm created in FerrisKey (defaults to the source realm name)
--dry-runResolve and print the planned realm without calling the FerrisKey API
ferris-ctl realm import --from config --file examples/realm.yaml --dry-run -o yaml
ferris-ctl realm import --from keycloak \
  --source-url https://keycloak.example.com \
  --source-realm acme \
  --source-client-id admin-cli \
  --source-client-secret "$KC_SECRET" \
  --target-realm acme

The Import section covers each source in full, including what is and isn’t migrated.

Re-running imports is safe

Imports are idempotent: entities that already exist are skipped with a warning, so you can re-run an import after fixing the source.