Skip to content

Commit d016796

Browse files
committed
Adding an initial realm setup
Signed-off-by: Matthias Wessendorf <[email protected]>
1 parent cbcbbf2 commit d016796

File tree

2 files changed

+284
-2
lines changed

2 files changed

+284
-2
lines changed

build/keycloak.mk

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,3 +54,287 @@ keycloak-status: ## Show Keycloak status and connection info
5454
.PHONY: keycloak-logs
5555
keycloak-logs: ## Tail Keycloak logs
5656
@kubectl logs -n $(KEYCLOAK_NAMESPACE) -l app=keycloak -f --tail=100
57+
58+
.PHONY: keycloak-setup-realm
59+
keycloak-setup-realm: ## Setup OpenShift realm with token exchange support
60+
@echo "========================================="
61+
@echo "Setting up OpenShift Realm for Token Exchange"
62+
@echo "========================================="
63+
@echo "Using Keycloak at http://localhost:8090"
64+
@echo "(Ensure 'make keycloak-forward' is running in another terminal)"
65+
@echo ""
66+
@echo "Getting admin access token..."
67+
@TOKEN=$$(curl -s -X POST "http://localhost:8090/realms/master/protocol/openid-connect/token" \
68+
-H "Content-Type: application/x-www-form-urlencoded" \
69+
-d "username=$(KEYCLOAK_ADMIN_USER)" \
70+
-d "password=$(KEYCLOAK_ADMIN_PASSWORD)" \
71+
-d "grant_type=password" \
72+
-d "client_id=admin-cli" \
73+
2>/dev/null | jq -r '.access_token // empty'); \
74+
if [ -z "$$TOKEN" ] || [ "$$TOKEN" = "null" ]; then \
75+
echo "❌ Failed to get access token. Check if:"; \
76+
echo " - Keycloak is running (make keycloak-install)"; \
77+
echo " - Port forwarding is active (make keycloak-forward)"; \
78+
echo " - Admin credentials are correct: $(KEYCLOAK_ADMIN_USER)/$(KEYCLOAK_ADMIN_PASSWORD)"; \
79+
exit 1; \
80+
fi; \
81+
echo "✅ Successfully obtained access token"; \
82+
echo ""; \
83+
echo "Creating OpenShift realm..."; \
84+
REALM_RESPONSE=$$(curl -s -w "%{http_code}" -X POST "http://localhost:8090/admin/realms" \
85+
-H "Authorization: Bearer $$TOKEN" \
86+
-H "Content-Type: application/json" \
87+
-d '{"realm":"openshift","enabled":true}'); \
88+
REALM_CODE=$$(echo "$$REALM_RESPONSE" | tail -c 4); \
89+
if [ "$$REALM_CODE" = "201" ] || [ "$$REALM_CODE" = "409" ]; then \
90+
if [ "$$REALM_CODE" = "201" ]; then echo "✅ OpenShift realm created"; \
91+
else echo "✅ OpenShift realm already exists"; fi; \
92+
else \
93+
echo "❌ Failed to create OpenShift realm (HTTP $$REALM_CODE)"; \
94+
exit 1; \
95+
fi; \
96+
echo ""; \
97+
echo "Configuring realm events..."; \
98+
EVENT_CONFIG_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X PUT "http://localhost:8090/admin/realms/openshift" \
99+
-H "Authorization: Bearer $$TOKEN" \
100+
-H "Content-Type: application/json" \
101+
-d '{"realm":"openshift","enabled":true,"eventsEnabled":true,"eventsListeners":["jboss-logging"],"adminEventsEnabled":true,"adminEventsDetailsEnabled":true}'); \
102+
EVENT_CONFIG_CODE=$$(echo "$$EVENT_CONFIG_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
103+
if [ "$$EVENT_CONFIG_CODE" = "204" ]; then \
104+
echo "✅ User and admin event logging enabled"; \
105+
else \
106+
echo "⚠️ Could not configure event logging (HTTP $$EVENT_CONFIG_CODE)"; \
107+
fi; \
108+
echo ""; \
109+
echo "Creating mcp:openshift client scope..."; \
110+
SCOPE_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/client-scopes" \
111+
-H "Authorization: Bearer $$TOKEN" \
112+
-H "Content-Type: application/json" \
113+
-d '{"name":"mcp:openshift","protocol":"openid-connect","attributes":{"display.on.consent.screen":"false","include.in.token.scope":"true"}}'); \
114+
SCOPE_CODE=$$(echo "$$SCOPE_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
115+
if [ "$$SCOPE_CODE" = "201" ] || [ "$$SCOPE_CODE" = "409" ]; then \
116+
if [ "$$SCOPE_CODE" = "201" ]; then echo "✅ mcp:openshift client scope created"; \
117+
else echo "✅ mcp:openshift client scope already exists"; fi; \
118+
else \
119+
echo "❌ Failed to create mcp:openshift scope (HTTP $$SCOPE_CODE)"; \
120+
exit 1; \
121+
fi; \
122+
echo ""; \
123+
echo "Adding audience mapper to mcp:openshift scope..."; \
124+
SCOPES_LIST=$$(curl -s -X GET "http://localhost:8090/admin/realms/openshift/client-scopes" \
125+
-H "Authorization: Bearer $$TOKEN" \
126+
-H "Accept: application/json"); \
127+
SCOPE_ID=$$(echo "$$SCOPES_LIST" | jq -r '.[] | select(.name == "mcp:openshift") | .id // empty' 2>/dev/null); \
128+
if [ -z "$$SCOPE_ID" ]; then \
129+
echo "❌ Failed to find mcp:openshift scope"; \
130+
exit 1; \
131+
fi; \
132+
MAPPER_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/client-scopes/$$SCOPE_ID/protocol-mappers/models" \
133+
-H "Authorization: Bearer $$TOKEN" \
134+
-H "Content-Type: application/json" \
135+
-d '{"name":"openshift-audience","protocol":"openid-connect","protocolMapper":"oidc-audience-mapper","config":{"included.client.audience":"openshift","id.token.claim":"true","access.token.claim":"true"}}'); \
136+
MAPPER_CODE=$$(echo "$$MAPPER_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
137+
if [ "$$MAPPER_CODE" = "201" ] || [ "$$MAPPER_CODE" = "409" ]; then \
138+
if [ "$$MAPPER_CODE" = "201" ]; then echo "✅ Audience mapper added"; \
139+
else echo "✅ Audience mapper already exists"; fi; \
140+
else \
141+
echo "❌ Failed to create audience mapper (HTTP $$MAPPER_CODE)"; \
142+
exit 1; \
143+
fi; \
144+
echo ""; \
145+
echo "Creating groups client scope..."; \
146+
GROUPS_SCOPE_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/client-scopes" \
147+
-H "Authorization: Bearer $$TOKEN" \
148+
-H "Content-Type: application/json" \
149+
-d '{"name":"groups","protocol":"openid-connect","attributes":{"display.on.consent.screen":"false","include.in.token.scope":"true"}}'); \
150+
GROUPS_SCOPE_CODE=$$(echo "$$GROUPS_SCOPE_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
151+
if [ "$$GROUPS_SCOPE_CODE" = "201" ] || [ "$$GROUPS_SCOPE_CODE" = "409" ]; then \
152+
if [ "$$GROUPS_SCOPE_CODE" = "201" ]; then echo "✅ groups client scope created"; \
153+
else echo "✅ groups client scope already exists"; fi; \
154+
else \
155+
echo "❌ Failed to create groups scope (HTTP $$GROUPS_SCOPE_CODE)"; \
156+
exit 1; \
157+
fi; \
158+
echo ""; \
159+
echo "Adding group membership mapper to groups scope..."; \
160+
SCOPES_LIST=$$(curl -s -X GET "http://localhost:8090/admin/realms/openshift/client-scopes" \
161+
-H "Authorization: Bearer $$TOKEN" \
162+
-H "Accept: application/json"); \
163+
GROUPS_SCOPE_ID=$$(echo "$$SCOPES_LIST" | jq -r '.[] | select(.name == "groups") | .id // empty' 2>/dev/null); \
164+
if [ -z "$$GROUPS_SCOPE_ID" ]; then \
165+
echo "❌ Failed to find groups scope"; \
166+
exit 1; \
167+
fi; \
168+
GROUPS_MAPPER_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/client-scopes/$$GROUPS_SCOPE_ID/protocol-mappers/models" \
169+
-H "Authorization: Bearer $$TOKEN" \
170+
-H "Content-Type: application/json" \
171+
-d '{"name":"groups","protocol":"openid-connect","protocolMapper":"oidc-group-membership-mapper","config":{"claim.name":"groups","full.path":"false","id.token.claim":"true","access.token.claim":"true","userinfo.token.claim":"true"}}'); \
172+
GROUPS_MAPPER_CODE=$$(echo "$$GROUPS_MAPPER_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
173+
if [ "$$GROUPS_MAPPER_CODE" = "201" ] || [ "$$GROUPS_MAPPER_CODE" = "409" ]; then \
174+
if [ "$$GROUPS_MAPPER_CODE" = "201" ]; then echo "✅ Group membership mapper added"; \
175+
else echo "✅ Group membership mapper already exists"; fi; \
176+
else \
177+
echo "❌ Failed to create group mapper (HTTP $$GROUPS_MAPPER_CODE)"; \
178+
exit 1; \
179+
fi; \
180+
echo ""; \
181+
echo "Creating mcp-server client scope..."; \
182+
MCP_SERVER_SCOPE_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/client-scopes" \
183+
-H "Authorization: Bearer $$TOKEN" \
184+
-H "Content-Type: application/json" \
185+
-d '{"name":"mcp-server","protocol":"openid-connect","attributes":{"display.on.consent.screen":"false","include.in.token.scope":"true"}}'); \
186+
MCP_SERVER_SCOPE_CODE=$$(echo "$$MCP_SERVER_SCOPE_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
187+
if [ "$$MCP_SERVER_SCOPE_CODE" = "201" ] || [ "$$MCP_SERVER_SCOPE_CODE" = "409" ]; then \
188+
if [ "$$MCP_SERVER_SCOPE_CODE" = "201" ]; then echo "✅ mcp-server client scope created"; \
189+
else echo "✅ mcp-server client scope already exists"; fi; \
190+
else \
191+
echo "❌ Failed to create mcp-server scope (HTTP $$MCP_SERVER_SCOPE_CODE)"; \
192+
exit 1; \
193+
fi; \
194+
echo ""; \
195+
echo "Adding audience mapper to mcp-server scope..."; \
196+
SCOPES_LIST=$$(curl -s -X GET "http://localhost:8090/admin/realms/openshift/client-scopes" \
197+
-H "Authorization: Bearer $$TOKEN" \
198+
-H "Accept: application/json"); \
199+
MCP_SERVER_SCOPE_ID=$$(echo "$$SCOPES_LIST" | jq -r '.[] | select(.name == "mcp-server") | .id // empty' 2>/dev/null); \
200+
if [ -z "$$MCP_SERVER_SCOPE_ID" ]; then \
201+
echo "❌ Failed to find mcp-server scope"; \
202+
exit 1; \
203+
fi; \
204+
MCP_SERVER_MAPPER_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/client-scopes/$$MCP_SERVER_SCOPE_ID/protocol-mappers/models" \
205+
-H "Authorization: Bearer $$TOKEN" \
206+
-H "Content-Type: application/json" \
207+
-d '{"name":"mcp-server-audience","protocol":"openid-connect","protocolMapper":"oidc-audience-mapper","config":{"included.client.audience":"mcp-server","id.token.claim":"true","access.token.claim":"true"}}'); \
208+
MCP_SERVER_MAPPER_CODE=$$(echo "$$MCP_SERVER_MAPPER_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
209+
if [ "$$MCP_SERVER_MAPPER_CODE" = "201" ] || [ "$$MCP_SERVER_MAPPER_CODE" = "409" ]; then \
210+
if [ "$$MCP_SERVER_MAPPER_CODE" = "201" ]; then echo "✅ mcp-server audience mapper added"; \
211+
else echo "✅ mcp-server audience mapper already exists"; fi; \
212+
else \
213+
echo "❌ Failed to create mcp-server audience mapper (HTTP $$MCP_SERVER_MAPPER_CODE)"; \
214+
exit 1; \
215+
fi; \
216+
echo ""; \
217+
echo "Creating openshift service client..."; \
218+
OPENSHIFT_CLIENT_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/clients" \
219+
-H "Authorization: Bearer $$TOKEN" \
220+
-H "Content-Type: application/json" \
221+
-d '{"clientId":"openshift","enabled":true,"publicClient":false,"standardFlowEnabled":true,"directAccessGrantsEnabled":true,"serviceAccountsEnabled":true,"authorizationServicesEnabled":false,"redirectUris":["*"],"defaultClientScopes":["groups"],"optionalClientScopes":[]}'); \
222+
OPENSHIFT_CLIENT_CODE=$$(echo "$$OPENSHIFT_CLIENT_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
223+
if [ "$$OPENSHIFT_CLIENT_CODE" = "201" ] || [ "$$OPENSHIFT_CLIENT_CODE" = "409" ]; then \
224+
if [ "$$OPENSHIFT_CLIENT_CODE" = "201" ]; then echo "✅ openshift client created"; \
225+
else echo "✅ openshift client already exists"; fi; \
226+
else \
227+
echo "❌ Failed to create openshift client (HTTP $$OPENSHIFT_CLIENT_CODE)"; \
228+
exit 1; \
229+
fi; \
230+
echo ""; \
231+
echo "Creating mcp-client public client..."; \
232+
MCP_PUBLIC_CLIENT_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/clients" \
233+
-H "Authorization: Bearer $$TOKEN" \
234+
-H "Content-Type: application/json" \
235+
-d '{"clientId":"mcp-client","enabled":true,"publicClient":true,"standardFlowEnabled":true,"directAccessGrantsEnabled":true,"serviceAccountsEnabled":false,"authorizationServicesEnabled":false,"redirectUris":["*"],"defaultClientScopes":[],"optionalClientScopes":["mcp-server"]}'); \
236+
MCP_PUBLIC_CLIENT_CODE=$$(echo "$$MCP_PUBLIC_CLIENT_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
237+
if [ "$$MCP_PUBLIC_CLIENT_CODE" = "201" ] || [ "$$MCP_PUBLIC_CLIENT_CODE" = "409" ]; then \
238+
if [ "$$MCP_PUBLIC_CLIENT_CODE" = "201" ]; then echo "✅ mcp-client public client created"; \
239+
else echo "✅ mcp-client public client already exists"; fi; \
240+
else \
241+
echo "❌ Failed to create mcp-client public client (HTTP $$MCP_PUBLIC_CLIENT_CODE)"; \
242+
exit 1; \
243+
fi; \
244+
echo ""; \
245+
echo "Creating mcp-server client with token exchange..."; \
246+
MCP_CLIENT_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/clients" \
247+
-H "Authorization: Bearer $$TOKEN" \
248+
-H "Content-Type: application/json" \
249+
-d '{"clientId":"mcp-server","enabled":true,"publicClient":false,"standardFlowEnabled":true,"directAccessGrantsEnabled":true,"serviceAccountsEnabled":true,"authorizationServicesEnabled":false,"redirectUris":["*"],"defaultClientScopes":["groups","mcp-server"],"optionalClientScopes":["mcp:openshift"],"attributes":{"oauth2.device.authorization.grant.enabled":"false","oidc.ciba.grant.enabled":"false","backchannel.logout.session.required":"true","backchannel.logout.revoke.offline.tokens":"false"}}'); \
250+
MCP_CLIENT_CODE=$$(echo "$$MCP_CLIENT_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
251+
if [ "$$MCP_CLIENT_CODE" = "201" ] || [ "$$MCP_CLIENT_CODE" = "409" ]; then \
252+
if [ "$$MCP_CLIENT_CODE" = "201" ]; then echo "✅ mcp-server client created"; \
253+
else echo "✅ mcp-server client already exists"; fi; \
254+
else \
255+
echo "❌ Failed to create mcp-server client (HTTP $$MCP_CLIENT_CODE)"; \
256+
exit 1; \
257+
fi; \
258+
echo ""; \
259+
echo "Enabling standard token exchange for mcp-server..."; \
260+
CLIENTS_LIST=$$(curl -s -X GET "http://localhost:8090/admin/realms/openshift/clients" \
261+
-H "Authorization: Bearer $$TOKEN" \
262+
-H "Accept: application/json"); \
263+
MCP_CLIENT_ID=$$(echo "$$CLIENTS_LIST" | jq -r '.[] | select(.clientId == "mcp-server") | .id // empty' 2>/dev/null); \
264+
if [ -z "$$MCP_CLIENT_ID" ]; then \
265+
echo "❌ Failed to find mcp-server client"; \
266+
exit 1; \
267+
fi; \
268+
UPDATE_CLIENT_RESPONSE=$$(curl -s -w "HTTPCODE:%{http_code}" -X PUT "http://localhost:8090/admin/realms/openshift/clients/$$MCP_CLIENT_ID" \
269+
-H "Authorization: Bearer $$TOKEN" \
270+
-H "Content-Type: application/json" \
271+
-d '{"clientId":"mcp-server","enabled":true,"publicClient":false,"standardFlowEnabled":true,"directAccessGrantsEnabled":true,"serviceAccountsEnabled":true,"authorizationServicesEnabled":false,"redirectUris":["*"],"defaultClientScopes":["groups","mcp-server"],"optionalClientScopes":["mcp:openshift"],"attributes":{"oauth2.device.authorization.grant.enabled":"false","oidc.ciba.grant.enabled":"false","backchannel.logout.session.required":"true","backchannel.logout.revoke.offline.tokens":"false","standard.token.exchange.enabled":"true"}}'); \
272+
UPDATE_CLIENT_CODE=$$(echo "$$UPDATE_CLIENT_RESPONSE" | grep -o "HTTPCODE:[0-9]*" | cut -d: -f2); \
273+
if [ "$$UPDATE_CLIENT_CODE" = "204" ]; then \
274+
echo "✅ Standard token exchange enabled for mcp-server client"; \
275+
else \
276+
echo "⚠️ Could not enable token exchange (HTTP $$UPDATE_CLIENT_CODE)"; \
277+
fi; \
278+
echo ""; \
279+
echo "Getting mcp-server client secret..."; \
280+
SECRET_RESPONSE=$$(curl -s -X GET "http://localhost:8090/admin/realms/openshift/clients/$$MCP_CLIENT_ID/client-secret" \
281+
-H "Authorization: Bearer $$TOKEN" \
282+
-H "Accept: application/json"); \
283+
CLIENT_SECRET=$$(echo "$$SECRET_RESPONSE" | jq -r '.value // empty' 2>/dev/null); \
284+
if [ -z "$$CLIENT_SECRET" ]; then \
285+
echo "❌ Failed to get client secret"; \
286+
else \
287+
echo "✅ Client secret retrieved"; \
288+
fi; \
289+
echo ""; \
290+
echo "Creating test user developer/developer..."; \
291+
USER_RESPONSE=$$(curl -s -w "%{http_code}" -X POST "http://localhost:8090/admin/realms/openshift/users" \
292+
-H "Authorization: Bearer $$TOKEN" \
293+
-H "Content-Type: application/json" \
294+
-d '{"username":"developer","email":"[email protected]","firstName":"Developer","lastName":"User","enabled":true,"emailVerified":true,"credentials":[{"type":"password","value":"developer","temporary":false}]}'); \
295+
USER_CODE=$$(echo "$$USER_RESPONSE" | tail -c 4); \
296+
if [ "$$USER_CODE" = "201" ] || [ "$$USER_CODE" = "409" ]; then \
297+
if [ "$$USER_CODE" = "201" ]; then echo "✅ developer user created"; \
298+
else echo "✅ developer user already exists"; fi; \
299+
else \
300+
echo "❌ Failed to create developer user (HTTP $$USER_CODE)"; \
301+
exit 1; \
302+
fi; \
303+
echo ""; \
304+
echo "🎉 OpenShift realm setup complete!"; \
305+
echo ""; \
306+
echo "========================================"; \
307+
echo "Configuration Summary"; \
308+
echo "========================================"; \
309+
echo "Realm: openshift"; \
310+
echo "Authorization URL: http://localhost:8090/realms/openshift"; \
311+
echo ""; \
312+
echo "Test User:"; \
313+
echo " Username: developer"; \
314+
echo " Password: developer"; \
315+
echo " Email: [email protected]"; \
316+
echo ""; \
317+
echo "Clients:"; \
318+
echo " mcp-client (public, for browser-based auth)"; \
319+
echo " Client ID: mcp-client"; \
320+
echo " Optional Scopes: mcp-server"; \
321+
echo " mcp-server (confidential, token exchange enabled)"; \
322+
echo " Client ID: mcp-server"; \
323+
echo " Client Secret: $$CLIENT_SECRET"; \
324+
echo " openshift (service account)"; \
325+
echo " Client ID: openshift"; \
326+
echo ""; \
327+
echo "Client Scopes:"; \
328+
echo " mcp-server (default) - Audience: mcp-server"; \
329+
echo " mcp:openshift (optional) - Audience: openshift"; \
330+
echo " groups (default) - Group membership mapper"; \
331+
echo ""; \
332+
echo "TOML Configuration:"; \
333+
echo " require_oauth = true"; \
334+
echo " oauth_audience = \"mcp-server\""; \
335+
echo " authorization_url = \"http://localhost:8090/realms/openshift\""; \
336+
echo " sts_client_id = \"mcp-server\""; \
337+
echo " sts_client_secret = \"$$CLIENT_SECRET\""; \
338+
echo " sts_audience = \"openshift\""; \
339+
echo " sts_scopes = [\"mcp:openshift\"]"; \
340+
echo "========================================"

config/keycloak/deployment.yaml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ spec:
3030
value: "admin"
3131
- name: KEYCLOAK_ADMIN_PASSWORD
3232
value: "admin"
33-
- name: KC_PROXY
34-
value: "edge"
3533
- name: KC_HOSTNAME_STRICT
3634
value: "false"
3735
- name: KC_HTTP_ENABLED

0 commit comments

Comments
 (0)