Build1 distinct publisher3 min readUpdated
A dev.to walkthrough publishes the Keycloak stack behind an EKS gateway auth setup: one enabled grant, four redirect URLs, and a group membership Terraform does not fully own.
The Engineer · Build desk

Compiled by The EngineerSomething wrong?How this is made
The gateway checks a signature and looks for claims. It cannot add one. So the useful part of this stack is not the ALB policy but the client scope, which the author describes as the shared set of protocol mappers attached to the client [12]: whatever is not mapped there does not exist as far as the cluster is concerned.
The narrowing starts with the client flags. On the `kube-api` client, one flow toggle is on, `standard_flow_enabled`, which the author identifies as the authorization code grant [5]. Six are off: implicit, direct access grants, service accounts, standard token exchange, the OAuth2 JWT authorization grant and device authorization [6][1]. `full_scope_allowed = false` limits the token to roles scoped to this client [7]. With the direct access grant disabled, there is no password-grant shortcut for a test token; anything the gateway sees has to come back through one of the four registered redirect URLs [8][2], two loopback ports for kubelogin [9] and two Postman callbacks [10]. That constraint is exactly why runners need their own path, and the author's JWT-federated GitHub Actions client is deferred to a future article [3].
The membership side is looser than the client side. `keycloak_user_groups` is declared with `exhaustive = false` [13], and the `kube-admin` group carries the client role named `admin`, described in the code as the cluster-admin role for kube-api [14][11]. Non-exhaustive means Terraform owns the rows it declares and ignores the rest, so a hand-added member of that group is not drift anyone will be shown.
Two other lines are worth reading as policy rather than plumbing. `email_verified = true` is set from config for every user the stack creates [15], which is the realm asserting a fact about a person rather than the person proving it. And `lifecycle { ignore_changes = [first_name, last_name] }` [16] hands display names back to the directory while leaving `username` under Terraform control, which matters because `username` is the one attribute the article shows being copied into both the access token and the ID token [17][3]. Rename it in config and you rename the subject the cluster authorizes.
Which is where the walkthrough stops short of its own promise. The role resource is said to appear in the token's role claim once assigned to a user [11], but the mapper set published here contains only the username mapper, and the text breaks off mid-explanation of `add_to_id_token` [18][4]. Follow it literally and you get a token the gateway will accept carrying an identity and no authorization data.
One last asymmetry. The provider itself authenticates with a service-account client using the client credentials grant, driven by five environment variables and an otherwise empty `provider "keycloak" {}` block [2]. Service accounts are precisely what the `kube-api` client forbids [6][5]. The realm-management credential and the human credential are different clients with opposite capabilities, which is correct, and also means the secret that can rewrite every role mapping in this stack lives wherever the plan runs.
Follow any of these and your For You feed starts watching them — no settings page required.
Ranked by verification strength, evidence, and original report placement.
The author previously tested using ALB CRDs to offload JWT validation for OIDC-based authentication to the Amazon EKS Kubernetes API, and this article supplies the Terraform/OpenTofu stack that sets up Keycloak as the OIDC provider.
The official Keycloak Terraform provider is configured with a service-account client (OAuth 2.0 client credentials grant) and five environment variables (KEYCLOAK_URL, KEYCLOAK_REALM, KEYCLOAK_BASE_PATH, KEYCLOAK_CLIENT_ID, KEYCLOAK_CLIENT_SECRET), so an empty provider "keycloak" {} block is enough.
For GitHub Actions runners the author used a JWT-federated client and says it deserves a dedicated article.
The kube-api client sets access_type = CONFIDENTIAL and client_authenticator_type = client-secret, which the author explains creates a non-public client with a client secret.
standard_flow_enabled = true, which the author explains enables the Authorization Code Grant flow.
The kube-api client sets implicit_flow_enabled, direct_access_grants_enabled, service_accounts_enabled, standard_token_exchange_enabled, oauth2_jwt_authorization_grant_enabled and oauth2_device_authorization_grant_enabled all to false.
Evidence-backed comparisons of source perspectives and observed adoption signals. Read the methodology
Which Builder, Operator, and Investor concerns the observed source mix emphasized—not a truth score.
Evidence, demonstrated adoption, hype gap, incentives, and confidence are assessed independently, each on its own current evidence. How these are measured.
Primary configuration text, single unverified source
Nearly every claim is checkable against verbatim HCL pasted into the article, which is unusually direct evidence for configuration-level statements. It is weakened by being one self-published source with no independent verification, no decoded token or cluster RBAC output proving the end-to-end path, and a body that terminates mid-resource.
One self-reported test environment
The only adoption signal is the author's own demo-infra-project test setup wired to kubelogin, Postman and GitHub Actions runners. There are no third-party deployments, no usage counts, no downloads and no production evidence in the supplied material.
Claims sit at or slightly below the evidence
The article makes no performance, scale or market claims; its assertions are narrow configuration statements backed by the code itself, and it under-sells the operational implications it actually demonstrates (redirect-only token acquisition, non-exhaustive group ownership, a long-lived provider secret). The only misalignment runs the other way: a derived reading in the ledger overstates what is missing from the stack and is contradicted by the body.
Practitioner authorship with mild self-promotion
Incentives are limited to personal publishing dynamics on a developer platform: a series that references a prior article and teases a dedicated follow-up on the JWT-federated GitHub Actions client. No vendor sponsorship, commercial product, affiliation or paid relationship is disclosed anywhere in the supplied text, and no commercial alternative is disparaged.
Configuration facts firm, surrounding conclusions soft
Confidence is high for the literal HCL attributes and moderate overall: a single unreplicated source, a truncated body, no runtime proof that the resulting token satisfies ALB/EKS validation, and one derived ledger conclusion that the source itself contradicts.
build
A year without sprints: nine engineers, 36 services, and a WIP cap of eight graded B1 distinct publisher
build
Partition, not consolidation: what a 43-minute Jenkins queue actually cost1 distinct publisher
build
Send kills, not scores: the leaderboard fix that turns anti-cheat into a schema decision1 distinct publisher
build
A 30-to-45-second timeout change, four approvals, no merge: the cost of a two-person gate1 distinct publisher
Distinct publishers with included, body-backed reporting in this cluster.
dev.to
1 article · August 22, 2026