Keycloak Connector
The Keycloak connector reads the users in a realm so that Atolio can resolve each signed-in identity to an Atolio user. Every user is ingested under their Keycloak user ID, which is the same identifier Keycloak puts in the sub claim of an OIDC token. That match is what lets Atolio connect a login back to the right user.
Note: As part of Atolio Configuration, this connector should be selected as Identity Provider if it is used to resolve app-user mappings. Point it at the same realm your users authenticate against in Keycloak authentication.
Setting up the connector takes three steps:
- Create a read-only service account in Keycloak (done by your Keycloak admin).
- Deploy the connector pod into the Atolio cluster (done by your Deployment Engineer).
- Configure the source with
atolioctl(done by your Deployment Engineer).
Step 1: Create a Service Account in Keycloak
The connector talks to the Keycloak Admin REST API as a realm user, so we recommend creating a dedicated service account rather than using a personal admin account. The connector only reads users; it does not write to Keycloak or read any other resource.
- In the admin console, select your realm and create a user under “Users” (e.g.
atolio-connector). - On the new user’s “Credentials” tab, set a password and turn off “Temporary” so it does not expire on first use.
- On the “Role mapping” tab, click “Assign role”, filter by clients, and assign the
view-usersrole fromrealm-management. This is the lowest-privilege role that lets the connector list users in the realm.
The connector authenticates with this username and password against the realm’s built-in admin-cli client using the OAuth2 password grant, then refreshes the resulting token as needed. No additional client setup is required, since admin-cli exists in every realm by default.
Note:
view-usersis scoped to the realm you assign it in. If your users live in more than one realm, deploy a connector instance per realm, each with its own service account. If you rotate the service account’s password in Keycloak, update thepasswordsecret (Step 3) so the connector can keep authenticating.
Collect these values to use in the following steps:
| Value | Description | Example |
|---|---|---|
| Base URL | Root URL of your Keycloak instance. Include a context path such as /auth if your Keycloak uses one. | https://keycloak.example.com |
| Realm | The realm that holds your users and the service account. | employees |
| Username | The service account username created above. | atolio-connector |
| Password | The service account password. Provided as the password secret. |
Step 2: Deploy the Connector
Before the source can be configured, the connector pod must be running in the cluster. Connectors are deployed by enabling them in values-lumen.yaml. See Deploying Connectors for the full details, including how instances work.
connectors:
keycloak:
default:
enabled: true
default is the instance identifier. Treat it as immutable once set, because the instance is part of every resource identifier the connector ingests. Apply the change by upgrading the lumen Helm chart with create-infra.sh (recommended) or helm upgrade as described in the sources overview.
Step 3: Configure the Source
Source configuration is applied with atolioctl using a YAML file. If you have not already installed atolioctl, follow Configuring Sources first. The commands below also need an API token in JWT_TOKEN and the address the feeder server’s gRPC endpoint, both described next.
atolioctl prerequisites
JWT_TOKEN holds the API token atolioctl uses to authenticate to the feeder. Generate one from the deployment’s Helm values directory, which holds the values-lumen.yaml and values-lumen-templated.yaml files produced by create-infra.sh. The token is signed with the deployment’s jwtSecretKey, and the atolio:*:*:* match pattern grants access across all connectors, instances, and resources:
export JWT_TOKEN=$(atolioctl connector create-jwt --raw --config-dir . "atolio:*:*:*")
--feeder-address is the gRPC address of the feeder server that is used to read and write source configuration through. The standard path is to port-forward the in-cluster service/feeder and point atolioctl at it on localhost:
kubectl port-forward -n atolio-svc service/feeder 8889
With that port-forward running in another terminal, the examples below use --feeder-address :8889. The empty host means localhost, and because the port is not 443 the connection is made in plaintext, which is what the port-forward exposes. If the feeder is instead published on a load balancer, pass that address with port 443, for example --feeder-address feed.search.example.com:443, which connects over TLS.
Configuration schema
In the exported file, every source lives at connectors.<connector>.<instance>.<source>, so the Keycloak source sits at connectors.keycloak.default.keycloak. Its settings are grouped into common, secrets, and configuration sections:
| Field | Section | Required | Description |
|---|---|---|---|
enabled | common | yes | Set to true to run the source. |
identity-provider | common | yes | Set to true so Atolio uses this connector to resolve logins to users. |
cron-spec | common | no | Cron expression for periodic re-sync of users. Omit to sync only on demand. |
password | secrets | yes | Service account password from Step 1. |
base_url | configuration | yes | Root URL of your Keycloak instance. |
realm | configuration | yes | Realm holding your users and the service account. |
username | configuration | yes | Service account username from Step 1. |
Edit and apply the configuration
Source configuration is stored as a single document that covers every configured connector. The supported workflow is to export the current configuration, edit it, then import it back. Always start from a fresh export so you do not overwrite a change made elsewhere.
Export the current configuration to a local file:
atolioctl configure export --jwt-token-sdk ${JWT_TOKEN} --feeder-address :8889 lumen-connectors.yaml
Add a Keycloak entry alongside the connectors already in the file, substituting the values you collected in Step 1:
connectors:
# ...existing connectors left in place...
keycloak:
default:
keycloak:
connector: keycloak
instance: default
source: keycloak
common:
enabled: true
identity-provider: true # This connector is the identity provider
cron-spec: 0 7 * * * # Re-sync users on this schedule
secrets:
password:
value: "<SERVICE_ACCOUNT_PASSWORD>"
configuration:
base_url: https://keycloak.example.com
realm: employees
username: atolio-connector
Exported entries also carry a rendezvous-completed flag and a status block reporting each source’s current state and last validation result. Those fields are managed by Atolio. Leave them untouched on existing entries, and omit them when adding a new entry by hand as shown above.
Import the edited file to write the configuration back into the stack:
atolioctl configure import lumen-connectors.yaml --jwt-token-sdk ${JWT_TOKEN} --feeder-address :8889
Writing key: /lumen/connectors/keycloak/default/keycloak
Import writes the configuration into the stack after checking that the YAML is well formed. It does not contact Keycloak. The connector validates the credentials and connection itself when it starts and picks up the configuration, and it reads users after that. If something is wrong, the source reports as misconfigured and the connector pod logs the error. See Troubleshooting for the specific messages.
Troubleshooting
Almost all errors surface in the connector pod logs, not in the atolioctl output. The import command only checks that the YAML is well formed before writing it to the stack, so a malformed file is the one thing it catches directly. Everything else is reported by the connector as it runs through its lifecycle.
The connector validates first. When it starts and picks up the configuration, it logs in to Keycloak to check the credentials and connection. If that fails, the source moves to a misconfigured state and stops before reading any users. Once validation passes, the connector lists users during its first sync, which is where a missing role shows up. Use the lifecycle phase in the table below to tell the two apart.
| Message | Phase | Cause | Resolution |
|---|---|---|---|
YAML decode error from atolioctl configure import | Import | The configuration file is not valid YAML or does not match the expected structure. | Fix the YAML. Re-export with atolioctl configure export to get a known-good starting point. |
missing secret "password" | Validation | No password secret was provided. | Add the password secret with the service account password from Step 1. |
base_url reported as invalid | Validation | base_url is empty or not a valid HTTP or HTTPS URL. | Set base_url to a full URL, e.g. https://keycloak.example.com. |
credential validation: login failed: 401 ... invalid_grant | Validation | Wrong username or password, or the account is disabled. | Confirm the service account credentials and that the user is enabled in the realm. |
credential validation: login failed: 404 ... | Validation | The realm value does not match a realm that holds the service account. | Set realm to the realm where you created the account. |
credential validation: login failed: ... dial tcp / no such host | Validation | base_url is unreachable from the cluster, or a context path is missing. | Verify base_url is reachable from the cluster, including a context path such as /auth if your Keycloak uses one. |
export user: user page: get users: 403 ... | User sync | The service account logged in but lacks permission to list users. | Assign the view-users role from realm-management on the account’s “Role mapping” tab. |
| Logins fail to resolve to a user | At sign-in | The connector realm differs from the realm used for authentication. | Point the connector at the same realm configured in Keycloak authentication. |