116 lines
9.5 KiB
Markdown
116 lines
9.5 KiB
Markdown
---
|
|
title: Keycloak Authorization Services — Realm vs Client Roles, Permission Model, JWT Claims
|
|
source_type: official-doc
|
|
url: https://www.keycloak.org/docs/latest/authorization_services/index.html
|
|
archive_url:
|
|
related_branches: [feature-authentication-authorization-contract]
|
|
related_projects: [ca-skeleton]
|
|
tags: [authorization, keycloak, realm-roles, client-roles, JWT, permission-model, RBAC, ABAC, official-doc]
|
|
created: 2026-06-08
|
|
last_reviewed: 2026-06-08
|
|
---
|
|
|
|
# Keycloak Authorization Services — Realm vs Client Roles, Permission Model, JWT Claims
|
|
|
|
> Layer: `raw/official-docs/` — Keycloak 공식 Authorization Services 문서 + JWT claim 구조 (realm_access / resource_access). feature-authentication-authorization-contract 의 IdP side permission model 결정의 근거.
|
|
|
|
## Parent / 활용 branch (필수)
|
|
|
|
| Branch | 이 자료가 정당화하는 결정 |
|
|
|---|---|
|
|
| [[raw/branch-notes/feature-authentication-authorization-contract]] | Keycloak realm/client roles 을 JWT 로 전달받아 Spring Security `ROLE_*` authority 로 매핑하고, application-level permission check 는 별도 port 로 처리하는 설계 결정 근거 |
|
|
|
|
## 출처 / Source
|
|
|
|
**Keycloak Authorization Services:**
|
|
- 원본 URL: https://www.keycloak.org/docs/latest/authorization_services/index.html
|
|
- 저자 / 조직: Keycloak (Red Hat / CNCF)
|
|
- 발행일: rolling docs (Keycloak 25+)
|
|
- 마지막 확인일: 2026-06-08
|
|
|
|
**JWT claim mapping (community technical article, betweendata.io):**
|
|
- URL: https://betweendata.io/posts/secure-spring-rest-api-using-keycloak/
|
|
- 주의: official-doc 이 아닌 engineering article — claims 에 `source_type` 별도 표시
|
|
|
|
## 왜 저장했는지 / Why archived
|
|
|
|
Keycloak 이 JWT 에 `realm_access.roles` 와 `resource_access[client].roles` 두 가지 형태로 role 을 전달하고, Spring Security 는 이를 기본 지원하지 않아 custom `JwtGrantedAuthoritiesConverter` 가 필요함. 또한 Keycloak Authorization Services 의 fine-grained permission model 이 존재하지만, application-level authorization 과의 책임 분리를 결정하는 근거로 필요.
|
|
|
|
## 핵심 인용 / Key quotes (verbatim)
|
|
|
|
### Keycloak Authorization Services
|
|
|
|
> [§Authorization services overview] "A permission associates the object being protected with the policies that must be evaluated to determine whether access is granted."
|
|
|
|
> [§Permission model — expression] "X CAN DO Y ON RESOURCE Z" — where X represents users/roles/groups, Y represents actions, Z represents protected resources.
|
|
|
|
> [§Terminology — Resource] "A resource is part of the assets of an application and the organization. It can be a set of one or more endpoints, a classic web resource such as an HTML page, and so on."
|
|
|
|
> [§Terminology — Scope] "A resource's scope is a bounded extent of access that is possible to perform on a resource...scope can also be related to specific information provided by a resource."
|
|
|
|
> [§Fine-grained capabilities] "Policies are strongly related to the different access control mechanisms (ACMs) that you can use to protect your resources. With policies, you can implement strategies for attribute-based access control (ABAC), role-based access control (RBAC), context-based access control, or any combination of these."
|
|
|
|
### Keycloak JWT Claim Structure (from community technical article)
|
|
|
|
> [betweendata.io — JWT structure] "In the access token, realm roles appear under the realm_access claim containing a roles array" and "Resource roles are nested under resource_access, organized by client name, with each resource potentially containing its own roles collection."
|
|
|
|
```json
|
|
{
|
|
"realm_access": {
|
|
"roles": ["admin", "user"]
|
|
},
|
|
"resource_access": {
|
|
"my-app": {
|
|
"roles": ["app-user"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
> [betweendata.io — Spring Security gap] "Keycloak stores roles in custom claims like realm_access and resource_access, while Spring Security expects them in claims like roles or authorities."
|
|
|
|
> [betweendata.io — custom converter] "implements a custom converter that extracts the roles from where they are by default," using a Converter<Jwt, Collection<GrantedAuthority>> that parses both claim levels.
|
|
|
|
> [betweendata.io — prefix convention] Realm roles: "ROLE_realm_" prefix. Client roles: "ROLE_[CLIENT_NAME]_" prefix.
|
|
|
|
### Spring Security Resource Server JWT (official)
|
|
|
|
> [Spring Security JWT docs] "A JWT that is issued from an OAuth 2.0 Authorization Server will typically either have a scope or scp attribute, indicating the scopes (or authorities) it's been granted. When this is the case, Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string 'SCOPE_'."
|
|
|
|
> [Spring Security JWT docs — custom claim] "As part of configuring a JwtAuthenticationConverter, you can supply a subsidiary converter to go from Jwt to a Collection of granted authorities." (via setAuthoritiesClaimName / setAuthorityPrefix)
|
|
|
|
## Claims Extracted / 추출된 주장
|
|
|
|
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|
|
|---|---|---|---|---|---|
|
|
| KC-AUTHZ-C1 | Keycloak Authorization Services 는 `X CAN DO Y ON RESOURCE Z` 로 표현되는 **permission model** 을 제공하며, ABAC / RBAC / context-based 를 모두 지원 | [§permission expression] "X CAN DO Y ON RESOURCE Z" + [§fine-grained] "implement strategies for attribute-based access control (ABAC), role-based access control (RBAC)..." | `official-vendor-doc` | Keycloak 의 IdP-side fine-grained authorization 이 필요한 경우 | application-level authorization 을 Keycloak 에 완전 위임하는 것이 항상 바람직하다는 것은 아님 |
|
|
| KC-AUTHZ-C2 | Keycloak JWT 에서 realm roles 은 `realm_access.roles`, client roles 은 `resource_access[clientId].roles` claim 에 위치 — Spring Security 기본 매핑과 불일치 | [betweendata.io] "realm roles appear under the realm_access claim" + "Resource roles are nested under resource_access" | `engineering-blog` (community article, NOT official-vendor-doc) | Keycloak + Spring Security OAuth2 Resource Server 통합 | 모든 Keycloak 버전에서 이 claim 위치가 동일하게 유지된다는 것은 아님 — Keycloak 설정에 따라 다를 수 있음 |
|
|
| KC-AUTHZ-C3 | Spring Security 기본 JWT 파싱은 `scope`/`scp` claim 을 `SCOPE_` prefix 로, role claim 은 자동 추출하지 않음 → Keycloak role 을 `ROLE_*` authority 로 쓰려면 **custom JwtGrantedAuthoritiesConverter** 필요 | [Spring Security JWT docs] "Resource Server will attempt to coerce these scopes into a list of granted authorities, prefixing each scope with the string 'SCOPE_'" + custom converter needed | `official-vendor-doc` | Keycloak realm/client role → Spring `ROLE_*` authority 매핑 설계 | 이 매핑이 application-level permission check 의 완전한 대체가 된다는 것은 아님 |
|
|
| KC-AUTHZ-C4 | Keycloak Authorization Services (fine-grained) 는 resource + scope 기반으로 IdP 에서 permission 결정을 내리지만, application-level authorization logic 과의 **책임 경계 분리** 에 대한 공식 권고는 문서에 없음 | [§Terminology — Scope] "A resource's scope is a bounded extent of access that is possible to perform on a resource" | `official-vendor-doc` | Keycloak Authorization Services 를 application authorization 대리로 쓰는 아키텍처 평가 | 이것이 실제 production 에서 권장/비권장인지 — 문서는 capabilities 만 기술 |
|
|
|
|
## Usage Boundaries / 적용 경계
|
|
|
|
- 이 자료가 직접 증명하는 것:
|
|
- `KC-AUTHZ-C1`: Keycloak Authorization Services 는 ABAC/RBAC/context-based 지원
|
|
- `KC-AUTHZ-C2`: JWT claim 위치 (`realm_access.roles` / `resource_access[client].roles`) — 단 community article 수준
|
|
- `KC-AUTHZ-C3`: Spring Security 기본은 `scope` → `SCOPE_*`, Keycloak role 자동 추출 없음 (official)
|
|
- 이 자료가 증명하지 않는 것:
|
|
- Keycloak Authorization Services 를 쓰지 말아야 한다는 것
|
|
- application-level `AuthorizationPort` 가 Keycloak Authorization Services 보다 낫다는 것
|
|
- `KC-AUTHZ-C2` 는 community article 기반 — official Keycloak token 구조 문서로 확인 필요
|
|
- 내 프로젝트에 적용하려면 추가 확인이 필요한 것:
|
|
- ca-skeleton 에서 사용하는 Keycloak 버전의 realm_access / resource_access claim 위치가 변경되지 않았는지
|
|
- application-level permission 만으로 충분한지 vs Keycloak Authorization Services UMA flow 까지 도입할지의 복잡도 trade-off
|
|
|
|
## 메모 / Notes
|
|
|
|
- **Keycloak Authorization Services vs. application-level**: Keycloak Authorization Services 는 강력하지만 복잡함 (UMA 2.0, policy evaluation endpoint, resource server registration). 단순 permission check 에는 application-level `AuthorizationPort` 가 훨씬 간단하고 테스트하기 쉬움
|
|
- **realm roles vs client roles**: realm roles = organization-wide (예: `ADMIN`, `USER`). client roles = app-specific (예: `portfolio:write`). 이 프로젝트에서 `ROLE_*` authority 로 매핑하는 것은 realm roles 대상이 일반적
|
|
- **주의**: `KC-AUTHZ-C2` 는 engineering blog (betweendata.io) 기반 — official Keycloak 문서 (https://www.keycloak.org/docs/latest/server_admin/index.html#assigning-permissions-using-roles-and-groups) 로 별도 확인 권장
|
|
|
|
## Related / 관련
|
|
|
|
- [[raw/official-docs/spring-security-resource-server-jwt]] — JWT authority mapping 상세
|
|
- [[raw/official-docs/spring-security-authorization-architecture]] — enforcement mechanism
|
|
- [[raw/branch-notes/feature-authentication-authorization-contract]]
|