Automating Your Keycloak Audit with an AI Security Agent
Someone on the payments team registered a new Keycloak client at 4:50pm on a Friday. It shipped with Full Scope Allowed left on, which meant it could request offline_access for every user who authenticated through it — long-lived offline tokens, minted quietly, for a client nobody reviewed. You found it three weeks later, not because anything alerted, but because someone happened to scroll the client list. That is what a Keycloak audit gap looks like in practice: not a breach headline, just a realm that drifts a little further from its reviewed state every sprint.
This is part three of our Keycloak audit series. Part one mapped the misconfigurations that actually expose SSO — wildcard redirect URIs, weak client secrets, overprivileged service accounts, defaults left in place on brute-force protection and token lifetimes. Part two walked through auditing all of it with kcadm.sh, jq, and the Admin REST API, and ended on the honest problem: the audit is point-in-time, and the realm changes every time someone ships a client.
This article covers the automation step: how Olivier, CloudThinker's security agent, runs that same inspection continuously, what it watches for between audits, and — because this is your identity provider we're talking about — exactly what it will not do without your approval.
How Olivier connects: a read-only service account, about 5 minutes
Olivier connects to Keycloak the same way you'd want any third-party integration reviewed by your security team: a confidential client with a service account, granted only the view-side roles from the realm-management client — view-realm, view-clients, view-users, and view-events. No manage-* roles, no realm-admin, no stored admin passwords. It's the client-credentials pattern Keycloak documents for service accounts, scoped to read.
You create the client, assign the four roles, paste the client ID and secret into CloudThinker, and the first realm sweep starts. The whole flow takes about five minutes — the Keycloak connection guide lists the exact roles so your review can confirm precisely what is granted and what isn't.
One deliberate consequence of this design: if you never grant a manage-* role, Olivier is structurally incapable of changing your realm, regardless of what any autonomy setting says. The permission boundary is enforced by Keycloak itself, not by a policy inside CloudThinker.
What Olivier inspects continuously
Once connected, Olivier runs the part-two audit on a loop — every realm, every client, every role mapping:
- Client configuration — public clients with wildcard (
*) orhttp://entries in Valid Redirect URIs, permissive Web Origins, Direct Access Grants enabled on browser-facing clients, Full Scope Allowed left on. - Secret hygiene — confidential clients whose secrets haven't rotated within your policy window, and secrets reused across environments (the same value appearing in staging and production clients is a finding, not a coincidence).
- Role and scope creep — service accounts holding
realm-managementroles, composite roles that quietly include admin capabilities,offline_accessreachable through clients that don't need it. - Realm security settings — brute-force protection disabled, password policy at defaults, access-token and SSO-session lifetimes far beyond your stated policy.
- Event coverage — login events or admin events not being saved, which means the forensic trail you'd need after an incident doesn't exist.
The checks aren't novel — you ran most of them by hand in part two. What changes is the cadence and the diffing. Olivier keeps a baseline of the realm's reviewed state, so the interesting output isn't "here are 40 clients" — it's "this client is new since Tuesday, it's public, and its redirect URI ends in a wildcard."
Alerts on the changes that widen access
The Friday-afternoon client from the opening is the canonical case. Olivier flags, as they happen:
- A new client registered in any watched realm — with an immediate configuration review attached, not just a notification that it exists.
- A role grant that widens access: a user or service account picking up
realm-admin,manage-users,manage-clients, or any composite role that resolves to them. - An edit to an existing client that loosens it — a redirect URI broadened, Full Scope Allowed toggled on, a protocol mapper added that leaks group membership into tokens.
- Realm-setting changes: brute-force protection switched off, token lifespans extended, required actions removed.
Each alert carries the evidence: what changed, when, and — if you've enabled admin events with representation, as part two recommended — which admin account made the change.
Graduated autonomy: nothing changes in the realm without you
Every finding class has an autonomy level you set per realm:
- Notify — Olivier reports the finding and its evidence. Nothing else. This is the default for everything, and for an identity provider it's where most teams stay longest.
- Suggest — Olivier proposes the specific remediation: the exact redirect URI to replace the wildcard, the role to remove from a service account, the
kcadm.sh updatecommand your engineer would run. - Approve — Olivier prepares the change and executes it only after a named human approves. This requires you to have explicitly granted scoped
manage-*roles to the connection — remediation permissions are a separate, deliberate grant, never part of onboarding. - Autonomous — reserved for provably reversible actions in non-production realms, if you ever enable it at all. Sensible first candidates: rotating a stale client secret in a dev realm. Not sensible: anything touching production role mappings.
Every action at every level lands in an audit trail — finding, evidence, proposal, approver, execution, result. If your compliance program asks "who reviewed access to the identity provider and when," the answer is a queryable log rather than a quarterly spreadsheet.
What a first scan typically finds
Illustrative numbers — a composite of first scans against mid-market deployments in the range of three realms and 40–60 clients. Your realm will differ.
| Finding | Detail | Severity |
|---|---|---|
| Wildcard redirect URIs | 3 public clients with https://*.example.com/* patterns |
High |
| Service account with admin roles | 1 CI service account holding manage-users and manage-clients |
High |
| Brute-force protection disabled | Off in 2 of 3 realms, including production | High |
| Full Scope Allowed on new clients | 12 clients issuing every assignable role in tokens | Medium |
| Stale client secrets | 9 confidential clients, no rotation in 12+ months; 2 shared values | Medium |
| Admin events not saved | Login events on, admin events off — no change attribution | Medium |
| Session lifetimes beyond policy | SSO Session Max at 30 days against a stated 12-hour policy | Medium |
| Direct Access Grants on browser clients | 4 SPA clients accepting password grants | Low |
Notice the shape: nothing here is exotic. Every row is a part-one misconfiguration that accumulated because nobody re-ran the part-two audit after the realm changed. That's the entire argument for continuous inspection — the findings aren't clever, they're just current.
Prompts to try in your first session
Olivier is conversational — you ask in plain language and get answers backed by the same Admin API evidence you'd pull yourself:
"Review every client in the production realm and flag public clients with wildcard or http redirect URIs. Notify only — don't propose changes yet."
"List every service account that holds any realm-management role, and tell me which of those roles are actually used based on the event log."
"Which clients were created or modified in the last 14 days, and did any of them gain the ability to request offline_access?"
Each answer cites the underlying client and role representations, so you verify rather than trust — the same discipline part two built by hand.
What Olivier will not do
Worth stating plainly, because "AI agent connected to the identity provider" should trigger exactly the scrutiny it sounds like it should:
- It is read-only by default, enforced by Keycloak's own role model. Without
manage-*roles on the connection's service account, no write is possible — there's no permission to escalate. - It never modifies a realm, client, role mapping, or user without approval, unless you have deliberately set that specific action class to Autonomous for that specific realm.
- It does not handle credentials it doesn't need. The connection is a client-credentials grant; Olivier never sees user passwords, and client secrets it flags as stale are referenced, not exfiltrated into findings.
- It does not make identity-architecture decisions. It will tell you a service account holds
realm-admin; whether that CI pipeline genuinely needs realm administration is a judgment call, and it stays yours.
The right mental model, if you did the part-two audit manually: Olivier is that audit, running continuously, with a change-detection layer and an approval-gated remediation queue attached. It is not an autopilot for your identity provider, and it isn't designed to become one on day one.
From annual review to standing control
You know which Keycloak misconfigurations expose SSO, and you know how to find every one with native tools. The remaining gap is that a realm drifts faster than any team re-audits it — and closing that gap is an automation problem, not a diligence problem. Teams that move from periodic manual reviews to continuous, approval-gated inspection typically catch widening-access changes within hours instead of quarters, which is the difference between revoking a token and writing an incident report.
Try CloudThinker free — 100 premium credits, no card required — and follow the Keycloak connection guide to see your own realm's first findings table within the hour.
