๐ŸŒฑ Infra/KeyCloak

[keycloak ๋ง›๋ณด๊ธฐ #6] Keycloak์˜ ์ธ๊ฐ€ ์ „๋žต

mini_world 2025. 2. 9. 14:47
๋ชฉ์ฐจ ์ ‘๊ธฐ

๊ฐœ์š”, ์ธ๊ฐ€๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

 

๋“ค์–ด๊ฐ€๊ธฐ ์ „์— ์ธ๊ฐ€(Authorization)์ด ๋ฌด์—‡์ธ์ง€ ํ•œ๋ฒˆ ๋” ๊ฐœ๋…์„ ์ •๋ฆฌํ•ด๋ณด์ž.
์ธ๊ฐ€๋Š” "์ด ์‚ฌ์šฉ์ž๊ฐ€ ํŠน์ • ๋ฆฌ์†Œ์Šค๋‚˜ ๊ธฐ๋Šฅ์— ์ ‘๊ทผํ•  ๊ถŒํ•œ์ด ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •"์ด๋‹ค.

์˜ˆ๋ฅผ๋“ค์ž๋ฉด ์–ด๋–ค ์‚ฌ์šฉ์ž๊ฐ€ ID/PW๋ฅผ ์ž…๋ ฅํ•˜๊ณ  ์‚ฌ์ง„์ฒฉ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋กœ๊ทธ์ธํ–ˆ๋‹ค๋ฉด, 
์‚ฌ์šฉ์ž ๋ณธ์ธ์˜ ์‚ฌ์ง„์ฒฉ์—๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•ด์•ผํ•˜๋ฉฐ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž์˜ ์‚ฌ์ง„์ฒฉ์—๋Š” ์ ‘๊ทผํ•ด์„œ๋Š” ์•ˆ๋œ๋‹ค.

๊ตฌ๋ถ„ ๊ฐœ๋… ์˜ˆ์‹œ
์ธ์ฆ
Authentication
๋ˆ„๊ตฌ์ธ์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ • ๋กœ๊ทธ์ธ
์ธ๊ฐ€
Authorization
๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ • ๋‚ด ์‚ฌ์ง„์ฒฉ์—๋งŒ ์ ‘๊ทผ 

์ฆ‰, ์ธ๊ฐ€๋ž€ ์‚ฌ์šฉ์ž๊ฐ€ ํ—ˆ์šฉ๋œ ๋ฆฌ์†Œ์Šค์—๋งŒ ์ ‘๊ทผํ•˜๋„๋ก ํ•˜๋Š”๊ฒƒ์ด ์ธ๊ฐ€์˜ ๊ฐœ๋…์ด๋‹ค.

์ธ๊ฐ€๋ฅผ ์œ„ํ•ด ๊ณ ๋ คํ•ด์•ผํ•˜๋Š” ์š”์†Œ๋Š” ์ •๋ง ๋งŽ๋‹ค.

  • ์‚ฌ์šฉ์ž ์ปจํ…์ŠคํŠธ (Who): ์‚ฌ์šฉ์ž ์‹ ์›, ์—ญํ• , ๊ทธ๋ฃน, ์†์„ฑ, ์กฐ์ง ๊ตฌ์กฐ ๋‚ด ์œ„์น˜
  • ๋ฆฌ์†Œ์Šค ์ปจํ…์ŠคํŠธ (What): ๋ฆฌ์†Œ์Šค ์œ ํ˜•, ์†Œ์œ ๊ถŒ, ๋ฏผ๊ฐ๋„ ์ˆ˜์ค€, ๊ณ„์ธต ๊ตฌ์กฐ, ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ
  • ์ ‘๊ทผ ์กฐ๊ฑด (When/How): ์‹œ๊ฐ„/์œ„์น˜ ๊ธฐ๋ฐ˜ ์ œ์•ฝ, ๋””๋ฐ”์ด์Šค/๋„คํŠธ์›Œํฌ ์กฐ๊ฑด, ๋‹ค์ค‘ ์ธ์ฆ, ์ ‘๊ทผ ๋นˆ๋„
  • ์šด์˜ ๊ด€์  (Operation): ๊ถŒํ•œ ์œ„์ž„/์ƒ์†, ๊ธด๊ธ‰ ์ ‘๊ทผ, ์ž„์‹œ ๊ถŒํ•œ, ๊ถŒํ•œ ์ทจ์†Œ
  • ๊ฐ์‚ฌ ๋ฐ ๋ชจ๋‹ˆํ„ฐ๋ง (Audit): ์ ‘๊ทผ ๋กœ๊ทธ, ๊ถŒํ•œ ๋ณ€๊ฒฝ ์ด๋ ฅ, ๋น„์ •์ƒ ํƒ์ง€, ์ปดํ”Œ๋ผ์ด์–ธ์Šค, ์‚ฌ์šฉ ํŒจํ„ด
  • ์ •์ฑ… ๊ด€๋ฆฌ (Policy): ๋ฒ„์ „ ๊ด€๋ฆฌ, ์ถฉ๋Œ ํ•ด๊ฒฐ, ํ…Œ์ŠคํŠธ, ๋ฐฐํฌ ์ „๋žต, ์˜ˆ์™ธ ์ฒ˜๋ฆฌ
  • ๋ณด์•ˆ ๊ณ ๋ ค์‚ฌํ•ญ: ์ตœ์†Œ ๊ถŒํ•œ ์›์น™, ์ง๋ฌด ๋ถ„๋ฆฌ, ๊ถŒํ•œ ์—์Šค์ปฌ๋ ˆ์ด์…˜ ๋ฐฉ์ง€, ์„ธ์…˜/ํ† ํฐ ๊ด€๋ฆฌ
  • ํ™•์žฅ์„ฑ ๋ฐ ์„ฑ๋Šฅ: ์บ์‹ฑ, ๋ถ„์‚ฐ ์‹œ์Šคํ…œ, ์ •์ฑ… ์ฒ˜๋ฆฌ, ์‘๋‹ต ์‹œ๊ฐ„, ์žฅ์•  ๋ณต๊ตฌ
  • ํ†ตํ•ฉ ๊ณ ๋ ค์‚ฌํ•ญ: ๋ ˆ๊ฑฐ์‹œ ํ†ตํ•ฉ, SSO, ์™ธ๋ถ€ ์‹œ์Šคํ…œ ์—ฐ๋™, API ๋ณด์•ˆ, ํ”„๋กœํ† ์ฝœ
  • ๊ทœ์ • ์ค€์ˆ˜: ์‚ฐ์—… ํ‘œ์ค€, ๋ฐ์ดํ„ฐ ๋ณดํ˜ธ, ๊ฐ์‚ฌ ์š”๊ตฌ์‚ฌํ•ญ, ๋ฒ•๊ทœ, ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ

๊ทธ๋ ‡๋‹ค๋ฉด, Keycloak์—์„œ๋Š” ์ธ๊ฐ€๋ฅผ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ๊ฒƒ์ธ๊ฐ€? 
๊ณต์‹๋ฌธ์„œ Authorization Services Guide ์—์„œ๋Š” ์ฃผ์š” ์ ‘๊ทผ์ œ์–ด๋ชจ๋ธ๊ณผ ์ •์ฑ… ์ง‘ํ–‰ ํฌ์ธํŠธ์— ๋Œ€ํ•ด ์ œ๊ณตํ•˜๊ณ ์žˆ๊ณ ,
์ด์ „ ์‹ค์Šต์—์„œ๋„ ์•„์ฃผ ์ž ๊น ๋‹ค๋ฃฌ์ ์ด ์žˆ๋‹ค. (๐Ÿ‘‰์‹ค์Šต)

์ ‘๊ทผ์ œ์–ด๋ชจ๋ธ ์„ค๋ช…
Attribute-based access control
(ABAC)
์‚ฌ์šฉ์ž, ๋ฆฌ์†Œ์Šค, ํ™˜๊ฒฝ์˜ ์†์„ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ด
์˜ˆ: ์‚ฌ์šฉ์ž์˜ ๋ถ€์„œ, ์ง๊ธ‰, ์œ„์น˜ ๋“ฑ์˜ ์†์„ฑ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ‘๊ทผ ๊ถŒํ•œ ํ—ˆ์šฉ
Role-based access control
(RBAC)
์‚ฌ์šฉ์ž์—๊ฒŒ ํ• ๋‹น๋œ ์—ญํ• ์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ด
์˜ˆ: Realm Role์— ๋งคํ•‘๋œ ์‚ฌ์šฉ์ž๋งŒ ์ ‘๊ทผ ๊ถŒํ•œ ํ—ˆ์šฉ
User-based access control
(UBAC)
ํŠน์ • ์‚ฌ์šฉ์ž๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ด (๊ฐœ๋ณ„ ์‚ฌ์šฉ์ž ๋‹จ์œ„์˜ ์„ธ๋ฐ€ํ•œ ๊ถŒํ•œ ์ œ์–ด ๊ฐ€๋Šฅ)
์˜ˆ, user01์—๊ฒŒ๋งŒ ์ ‘๊ทผ ๊ถŒํ•œ ํ—ˆ์šฉ
Context-based access control
(CBAC)
์š”์ฒญ์˜ ์ปจํ…์ŠคํŠธ(์‹œ๊ฐ„, ์œ„์น˜, ๋””๋ฐ”์ด์Šค ๋“ฑ)๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ด
์˜ˆ: ํŠน์ • IP ๋ฒ”์œ„์—์„œ๋งŒ ์ ‘๊ทผ ํ—ˆ์šฉ
Rule-based access control: JavaScript๋ฅผ ์‚ฌ์šฉํ•œ ์ปค์Šคํ…€ ๊ทœ์น™ ์ •์˜ (๋ณต์žกํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์Œ)
Time-based access control: ์‹œ๊ฐ„ ๊ธฐ๋ฐ˜์˜ ์ ‘๊ทผ ์ œ์–ด (ํŠน์ • ์‹œ๊ฐ„๋Œ€๋‚˜ ๊ธฐ๊ฐ„ ๋™์•ˆ๋งŒ ์ ‘๊ทผ ํ—ˆ์šฉ)
Custom ACMs through SPI: Service Provider Interface๋ฅผ ํ†ตํ•œ ์ปค์Šคํ…€ ์ ‘๊ทผ ์ œ์–ด ๋ฉ”์ปค๋‹ˆ์ฆ˜ ๊ตฌํ˜„ ๊ฐ€๋Šฅ
(ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์ž์ฒด ์ •์ฑ… ํƒ€์ž…์„ ๊ฐœ๋ฐœํ•˜์—ฌ ํ™•์žฅ ๊ฐ€๋Šฅ)
์ •์ฑ… ์ง‘ํ–‰ ํฌ์ธํŠธ ์„ค๋ช…
Policy Information Point
(PIP/์ •์ฑ… ์ •๋ณด)
์ •์ฑ… ํ‰๊ฐ€์— ํ•„์š”ํ•œ ์ •๋ณด ์ œ๊ณต
์‚ฌ์šฉ์ž ์†์„ฑ, ํ™˜๊ฒฝ ์ •๋ณด ๋“ฑ ์ˆ˜์ง‘
Policy Administration Point
(PAP/์ •์ฑ… ๊ด€๋ฆฌ)
์ •์ฑ…์„ ์ƒ์„ฑ, ๊ด€๋ฆฌ, ์ €์žฅํ•˜๋Š” ๊ณณ
Keycloak ๊ด€๋ฆฌ ์ฝ˜์†”์—์„œ ์ •์ฑ… ์„ค์ •
Policy Decision Point
(PDP/์ •์ฑ… ๊ฒฐ์ •)
์ ‘๊ทผ ํ—ˆ์šฉ/๊ฑฐ๋ถ€ ๊ฒฐ์ •
์ •์ฑ…๊ณผ ์†์„ฑ ์ •๋ณด๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํŒ๋‹จ
Policy Enforcement Point
(PEP/์ •์ฑ… ์ง‘ํ–‰)
์‹ค์ œ ์ ‘๊ทผ ์ œ์–ด ์‹คํ–‰
PDP์˜ ๊ฒฐ์ •์„ ๊ฐ•์ œ
๋”๋ณด๊ธฐ
1. PAP (์ •์ฑ… ๊ด€๋ฆฌ) ์—”๋“œํฌ์ธํŠธ
# ๊ธฐ๋ณธ URL
${keycloak_url}/admin/realms/${realm_name}/clients/${client_id}/authz/resource-server
# ์ •์ฑ… ๊ด€๋ฆฌ
GET    /policies                  # ์ •์ฑ… ๋ชฉ๋ก ์กฐํšŒ
POST   /policies                  # ์ •์ฑ… ์ƒ์„ฑ
GET    /policies/{id}            # ํŠน์ • ์ •์ฑ… ์กฐํšŒ
PUT    /policies/{id}            # ์ •์ฑ… ์—…๋ฐ์ดํŠธ
DELETE /policies/{id}            # ์ •์ฑ… ์‚ญ์ œ

2. PIP (์ •๋ณด ์ˆ˜์ง‘) ์—”๋“œํฌ์ธํŠธ
# ์‚ฌ์šฉ์ž ์ •๋ณด
GET /admin/realms/${realm_name}/users/{id}
GET /admin/realms/${realm_name}/users/{id}/groups
GET /admin/realms/${realm_name}/users/{id}/role-mappings
# ๋ฆฌ์†Œ์Šค ์ •๋ณด
GET /authz/protection/resource_set
GET /authz/protection/resource_set/{id}

3. PDP (๊ฒฐ์ •) ์—”๋“œํฌ์ธํŠธ
# ๊ถŒํ•œ ํ‰๊ฐ€
POST /realms/${realm_name}/protocol/openid-connect/token
{
    "grant_type": "urn:ietf:params:oauth:grant-type:uma-ticket",
    "audience": "${client_id}",
    "permission": "${resource}#${scope}"
}
# ์ •์ฑ… ํ‰๊ฐ€
POST /realms/${realm_name}/clients/${client_id}/authz/resource-server/policy/evaluate

4. PEP (์‹คํ–‰) ์—”๋“œํฌ์ธํŠธ
# ํ† ํฐ ๊ฒ€์ฆ
GET /realms/${realm_name}/protocol/openid-connect/userinfo
GET /realms/${realm_name}/protocol/openid-connect/token/introspect
# ๊ถŒํ•œ ํ™•์ธ
POST /realms/${realm_name}/clients/${client_id}/authz/resource-server/permission/ticket

์˜ค๋Š˜์€  KeyCloak์—์„œ์˜ ์ ‘๊ทผ์ œ์–ด ๋ฉ”์ปค๋‹ˆ์ฆ˜ ์ค‘ RBAC, ABAC์— ๋Œ€ํ•ด ํ™•์ธํ•ด๋ณด์ž.


 

RBAC  (Role-Based Access Control)

 

๊ฐœ๋… ์ดํ•ดํ•˜๊ธฐ 

Keycloak์—์„œ๋Š” Role์€ ์‚ฌ์šฉ์ž ํ˜น์€ ๊ทธ๋ฃน์— ๋งคํ•‘๋˜์–ด ์‚ฌ์šฉ๋œ๋‹ค. (๊ณต์‹๋ฌธ์„œ ๋งํฌ)
Role์ด๋ž€, ์ผ๋ฐ˜์ ์œผ๋กœ ์กฐ์ง ๋˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ปจํ…์ŠคํŠธ์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ๊ฐ€์ง€๋Š” ์—ญํ• ์„ ๋งํ•œ๋‹ค.
(e.g. administrator, system-manager, people-manager, audit-user, readonly-user ..)

Keycloak์˜ RBAC์„ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” user, group์˜ ๊ฐœ๋…๋„ ํ•จ๊ป˜ ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค.

๐Ÿ“Ž User

  • Keycloak์—์„œ ์ธ์ฆ๊ณผ ์ธ๊ฐ€์˜ ์ฃผ์ฒด์ด๋‹ค.
  • ์ง์ ‘์ ์œผ๋กœ Role์„ ํ• ๋‹น๋ฐ›์„ ์ˆ˜ ์žˆ์œผ๋ฉฐ(UBAC), Group์˜ ๋ฉค๋ฒ„๊ฐ€ ๋  ์ˆ˜ ์žˆ๋‹ค.
  • e.g. ์‚ฌ์šฉ์ž1(user01@test.com), ์‚ฌ์šฉ์ž2(user02@test.com)

๐Ÿ“Ž Group

  • ์—ฌ๋Ÿฌ User๋ฅผ ๋ฌถ์–ด์„œ ๊ด€๋ฆฌํ•˜๋Š” ๋‹จ์œ„์ด๋ฉฐ, Role์„ ํ• ๋‹น๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. (GBAC)
  • ๊ณ„์ธต์  ๊ตฌ์กฐ๊ฐ€ ๊ฐ€๋Šฅ(ํ•˜์œ„ ๊ทธ๋ฃน ์ƒ์„ฑ ๊ฐ€๋Šฅ)ํ•˜์—ฌ ์—ฌ๋Ÿฌ User๋ฅผ ํ•œ๋ฒˆ์— ๊ด€๋ฆฌ ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Role ๊ด€๋ฆฌ ํšจ์œจ์„ฑ ์ฆ๊ฐ€๋œ๋‹ค.

๐Ÿ“Ž Role

keycloak์—๋Š” ์„ธ ์ข…๋ฅ˜์˜ ์—ญํ• ์ด ์žˆ๋‹ค. 

๊ตฌ๋ถ„ ์„ค๋ช…
Realm Role
[๋งํฌ]
- ์ „์—ญ์ (Global) ๋ฒ”์œ„์˜ ์—ญํ• 
- Realm ๋‚ด์˜ ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ๊ณตํ†ต์œผ๋กœ ์‚ฌ์šฉ
- ์ผ๋ฐ˜์ ์œผ๋กœ ์กฐ์ง ์ „์ฒด์— ์ ์šฉ๋˜๋Š” ๊ด‘๋ฒ”์œ„ํ•œ ๊ถŒํ•œ์„ ์ •์˜
โš ๏ธ์ฃผ์˜โš ๏ธ  ์ „์—ญ์ ์œผ๋กœ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜์ง€๋งŒ, ์ž๋™์œผ๋กœ ๋ชจ๋“  ์‚ฌ์šฉ์ž์—๊ฒŒ ํ• ๋‹น๋˜์ง€๋Š” ์•Š์Œ
Client Role
[๋งํฌ]
- ํŠน์ • ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํ•œ์ •๋œ ์—ญํ• 
- ํ•ด๋‹น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ํŠนํ™”๋œ ์„ธ๋ถ€์ ์ธ ๊ถŒํ•œ์„ ์ •์˜
- ๋‹ค๋ฅธ ํด๋ผ์ด์–ธํŠธ์™€ ๋…๋ฆฝ์ ์œผ๋กœ ๊ด€๋ฆฌ
Default Role
[๋งํฌ]
- ์ƒˆ๋กœ์šด ์‚ฌ์šฉ์ž๊ฐ€ ์ƒ์„ฑ๋  ๋•Œ ์ž๋™์œผ๋กœ ํ• ๋‹น๋˜๋Š” ์—ญํ• 
- `default-roles-{realm-name}` Composite Role์„ ํ†ตํ•ด ๊ด€๋ฆฌ
- Realm Role์ด๋‚˜ Client Role์„ Default Role๋กœ ์„ค์ • ๊ฐ€๋Šฅ

Role๋“ค์€ ์ƒํ˜ธ ๋ฒ ํƒ€์ ์ธ ๊ฒƒ์ด ์•„๋‹ˆ๋ฉฐ, ์กฐํ•ฉํ•˜์—ฌ ๊ณ„์ธต์ ์ด๊ณ  ์„ธ๋ฐ€ํ•œ ์ ‘๊ทผ ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•ด์ง„๋‹ค.
์•„๋ž˜ ์‹œ๋‚˜๋ฆฌ์˜ค์—์„œ ๊ฐ Role๋“ค์„ ํ•จ๊ป˜ ์‚ฌ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ํ™•์ธํ•ด๋ณด์ž.

 


[Realm Role & Client Role ํ˜ผ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค]

Realm Role (USER)
- ์‹œ์Šคํ…œ ์ „๋ฐ˜์˜ ๊ธฐ๋ณธ ์ ‘๊ทผ ๊ถŒํ•œ
- ๋ชจ๋“  ํด๋ผ์ด์–ธํŠธ ์•ฑ์—์„œ ์œ ํšจ
- "์ด ์‚ฌ์šฉ์ž๊ฐ€ ์•จ๋ฒ” ์„œ๋น„์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ž๊ฒฉ์ด ์žˆ๋Š”๊ฐ€?"

Client Role ({์‚ฌ์šฉ์žID}:all_access)
- ์‚ฌ์šฉ์ž ๋ณธ์ธ์˜ ์•จ๋ฒ”์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ถŒํ•œ
- ์กฐํšŒ/์ˆ˜์ •/์‚ญ์ œ ๋“ฑ ๋ชจ๋“  ๊ธฐ๋Šฅ ์‚ฌ์šฉ ๊ฐ€๋Šฅ
- "์ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ณธ์ธ์˜ ์•จ๋ฒ”์— ๋Œ€ํ•œ ๋ชจ๋“  ๊ถŒํ•œ์„ ๊ฐ€์ง€๋Š”๊ฐ€?"


์ด๋Ÿฐ์‹์œผ๋กœ ์‚ฌ์šฉ์ž๊ฐ€ ์‚ฌ์ง„์•ฑ์„ ์‚ฌ์šฉํ• ์ˆ˜๋Š” ์žˆ์ง€๋งŒ, ๋ชจ๋“  ์‚ฌ์ง„์ฒฉ์ด ์•„๋‹Œ ๋ณธ์ธ์˜ ์‚ฌ์ง„์ฒฉ๋งŒ ์ ‘๊ทผํ•˜์—ฌ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ๋„๋ก
๋‘ ๊ถŒํ•œ์„ ์กฐํ•ฉํ•˜์—ฌ ๊ณ„์ธต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

 

๐Ÿ“Ž ์ •๋ฆฌ

  • Role์€ ๋‹จ๋…์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ณ , ๋ฐ˜๋“œ์‹œ Userํ˜น์€ Group์— ๋งคํ•‘๋˜์–ด์•ผ ํ•œ๋‹ค.
  • Keycloak์—์„œ๋Š” RBAC, UBAC, GBAC ๋ณ„๊ฐœ์˜ ๋‹ค๋ฅธ ๊ฐœ๋…์ด ์•„๋‹ˆ๋ผ ๊ฐ™์€ ์ ‘๊ทผ์ œ์–ด ๋ฉ”์ปค๋‹ˆ์ฆ˜์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋ชจ๋“  ์ข…๋ฅ˜์˜ Role์€ Group์ด๋‚˜ User์—๊ฒŒ ์ง์ ‘ ํ• ๋‹น ๊ฐ€๋Šฅํ•˜๋‹ค.
  • Group์— ํ• ๋‹น๋œ Role์€ ํ•ด๋‹น Group์˜ ๋ชจ๋“  ๋ฉค๋ฒ„๊ฐ€ ์ƒ์†๋ฐ›๋Š”๋‹ค.
  • ํ•œ ์‚ฌ์šฉ์ž๋Š” ์—ฌ๋Ÿฌ ๊ฒฝ๋กœ(Default, Group, ์ง์ ‘ ํ• ๋‹น)๋กœ Role์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋‹ค.

 

์‹ค์Šต) Role ์‚ฌ์šฉ ์‹ค์Šตํ•˜๊ธฐ 

RealmRole, User์— ํ• ๋‹น

Realm Role์€ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•˜๋ฉด ๋˜๋ฉฐ,
Client Role์€ [Clients > ์ƒ์„ฑํ•œ Client > Roles ํƒญ > Create role] ์—์„œ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค.
์ด ์‹ค์Šต์—์„œ๋Š” Realm Role๋งŒ ๊ฐ„๋žตํžˆ ์„ค๋ช…ํ•œ๋‹ค.

1. Realm Role์„ ์ƒ์„ฑํ•œ๋‹ค.

2. ์‚ฌ์šฉ์ž์—๊ฒŒ Realm Role์„ ํ• ๋‹นํ•œ๋‹ค.

3. ์‚ฌ์šฉ์ž์— ์—ฐ๊ฒฐ๋œ Realm Role ํ™•์ธ

๋จผ์ € Users์— Realm Role์ด ์ž˜ ์—ฐ๊ฒฐ๋˜์—ˆ๋Š”์ง€ ์ ๊ฒ€ํ•œ๋‹ค.

ํ„ฐ๋ฏธ๋„์—์„œ ํ˜ธ์ถœํ•  ์˜ˆ์ •์ด๋ฏ€๋กœ, Direct access grants๋ฅผ ํ—ˆ์šฉํ•ด์ค€๋‹ค. 

์ดํ›„ ์•„๋ž˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜ ๋ถ€๋ถ„์„ ๋‚ด ํ™˜๊ฒฝ์— ๋งž์ถฐ ๋ณ€๊ฒฝํ•˜๊ณ , ํ„ฐ๋ฏธ๋„์—์„œ ์‹คํ–‰ํ•ด๋ณด์ž.

# 1. keycloak ํ…Œ์ŠคํŠธ์„œ๋ฒ„ ์‹คํ–‰
docker run -p 8080:8080 \
          -e KEYCLOAK_ADMIN=admin \
          -e KEYCLOAK_ADMIN_PASSWORD=admin \
          quay.io/keycloak/keycloak \
          start-dev
          
# 2. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="admin"
export CLIENT_ID="admin-cli"
export REALM_NAME="my-realm"
export KEYCLOAK_URL="http://localhost:8080"
export KEYCLOAK_USERNAME=user01

# 3. ๊ด€๋ฆฌ์ž ํ† ํฐ ํš๋“
export ADMIN_TOKEN=$(curl -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=${CLIENT_ID}" \
-d "username=${ADMIN_USERNAME}" \
-d "password=${ADMIN_PASSWORD}" \
-d "grant_type=password" | jq -r '.access_token')

# 4. ์‚ฌ์šฉ์ž ID ์กฐํšŒ
export USER_ID=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users?username=${KEYCLOAK_USERNAME}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.[0].id')

# 5. Role ๋งคํ•‘ ํ™•์ธ (๊ด€๋ฆฌ์ž ํ† ํฐ ์‚ฌ์šฉ)
curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/realm" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq '.' --color-output

๊ฒฐ๊ณผ๋กœ ์•„๋ž˜์™€ ๊ฐ™์ด ์ƒˆ๋กœ ์ƒ์„ฑํ•œ my-realm-role์ด ๋งคํ•‘๋œ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.



ClientRole, Group์— ํ• ๋‹น

1. Client Role ์ƒ์„ฑ
[client > 'my-client' > Roles > create role] ์œผ๋กœ ์ƒˆ๋กœ์šด Role (my-client-role)์„ ์ƒ์„ฑํ•œ๋‹ค.

2. ๊ทธ๋ฃน์— ClientRole์„ ๋งคํ•‘ํ•œ๋‹ค.

3. ๊ทธ๋ฃน์— ClientRole ๋งคํ•‘๋œ๊ฒƒ ํ™•์ธ

# 1. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="admin"
export CLIENT_ID="my-client"
export REALM_NAME="my-realm"
export KEYCLOAK_URL="http://localhost:8080"
export KEYCLOAK_USERNAME="user01"
export KEYCLOAK_GROUPNAME="my-group"

# 2. ๊ด€๋ฆฌ์ž ํ† ํฐ ํš๋“
export ADMIN_TOKEN=$(curl -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=admin-cli" \
-d "username=${ADMIN_USERNAME}" \
-d "password=${ADMIN_PASSWORD}" \
-d "grant_type=password" | jq -r '.access_token')

# 3. ์‚ฌ์šฉ์ž ID ์กฐํšŒ
export USER_ID=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users?username=${KEYCLOAK_USERNAME}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.[0].id')

# 4. Client ID(UUID) ์กฐํšŒ
export MY_CLIENT_ID=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_ID}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.[0].id')

# 5. ์‚ฌ์šฉ์ž์˜ Client Role ๋งคํ•‘ ํ™•์ธ (์ง์ ‘ ํ• ๋‹น๋œ role)
echo "Direct Client Roles:"
curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${MY_CLIENT_ID}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq '.' --color-output

# 6. ์‚ฌ์šฉ์ž์˜ Effective Client Role ๋งคํ•‘ ํ™•์ธ (๊ทธ๋ฃน์—์„œ ์ƒ์†๋ฐ›์€ role ํฌํ•จ)
echo -e "\nEffective Client Roles (including inherited from groups):"
curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users/${USER_ID}/role-mappings/clients/${MY_CLIENT_ID}/composite" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq '.' --color-output

# 7. ๊ทธ๋ฃน ID ์กฐํšŒ ๋ฐ Client Role ๋งคํ•‘ ํ™•์ธ
export MY_GROUP_ID=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups?search=${KEYCLOAK_GROUPNAME}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.[0].id')

echo -e "\nGroup Client Roles:"
curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/groups/${MY_GROUP_ID}/role-mappings/clients/${MY_CLIENT_ID}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq '.' --color-output

๊ทธ๋ฃน์— ์—ฐ๊ฒฐ๋œ ClientRole, ๊ทธ๋ฆฌ๊ณ  ์‚ฌ์šฉ์ž์—๊ฒŒ ์ƒ์†๋œ ClientRole๋„ ์œ„ ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.


 

ABAC  (Attribute-Based Access Control)

 

๊ฐœ๋… ์ดํ•ดํ•˜๊ธฐ 

Keycloak์—์„œ ABAC(Attribute-Based Access Control)์€ ์‚ฌ์šฉ์ž, ๋ฆฌ์†Œ์Šค, ํ™˜๊ฒฝ์˜ ์†์„ฑ(Attribute)์„ ๊ธฐ๋ฐ˜์œผ๋กœ ์ ‘๊ทผ์„ ์ œ์–ดํ•˜๋Š” ๋ฐฉ์‹์ด๋ฉฐ, Role๊ธฐ๋ฐ˜์˜ ์ ‘๊ทผ์ œ์–ด๋ณด๋‹ค ๋” ์œ ์—ฐํ•˜๊ณ  ์„ธ๋ฐ€ํ•œ ์ ‘๊ทผ์ œ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

Attribute๋„ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๊ธฐ๋ณธ์ ์œผ๋กœ๋Š” User์™€ Group์— ํ• ๋‹นํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋ฉฐ, 
๊ทธ ์™ธ์—๋„ Organization, Client, Identity Provider ๋“ฑ ๋‹ค์–‘ํ•œ Keycloak ์ปดํฌ๋„ŒํŠธ์— Attribute๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋‹ค.
(core concepts and terms)

ABAC์„ ํ™•์ธํ•˜๊ธฐ ์ „์— ๋จผ์ € ์ฃผ์š” ๊ฐœ๋…๋ถ€ํ„ฐ ํ™•์ธํ•ด๋ณด์ž.

 

๐Ÿ“Ž  Attribute

  • Keycloak์—์„œ ์—”ํ‹ฐํ‹ฐ(User, Group ๋“ฑ)์˜ ์ถ”๊ฐ€ ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” Key-Value ํ˜•ํƒœ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๋งํ•œ๋‹ค.
  • ๋™์ ์œผ๋กœ ์ถ”๊ฐ€/์ˆ˜์ •์ด ๊ฐ€๋Šฅํ•˜๋ฉฐ, ํ•˜๋‚˜์˜ Key์— ์—ฌ๋Ÿฌ Value๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์œผ๋ฉฐ,
    ABAC(Attribute Based Access Control)์—์„œ ์ ‘๊ทผ ์ œ์–ด ๊ฒฐ์ •์— ์‚ฌ์šฉ๋œ๋‹ค.
  • Group์—์„œ User๋กœ ์ƒ์† ๊ฐ€๋Šฅ ํ•˜๋‹ค. (Group → User)
  • e.g. department: "HR", location: ["Seoul", "Busan"]

 

๐Ÿ“Ž  Protocol Mapper 

  • Attribute๋ฅผ Token Claim์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ์„ค์ •์ด๋‹ค.
  • Keycloak์˜ JavaDoc ์ธํ„ฐํŽ˜์ด์Šค ๊ตฌํ˜„์ฒด ๋งํฌ
  • Mapper ์ข…๋ฅ˜:
    • User Property Mapper: ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์†์„ฑ ๋งคํ•‘
    • User Attribute Mapper: ์ปค์Šคํ…€ ์‚ฌ์šฉ์ž ์†์„ฑ ๋งคํ•‘
    • Group Membership Mapper: ๊ทธ๋ฃน ์ •๋ณด ๋งคํ•‘
    • Role Mapper: ์—ญํ•  ์ •๋ณด ๋งคํ•‘
{
    "name": "department",     // Mapper์˜ ์ด๋ฆ„ (๊ด€๋ฆฌ์ž๊ฐ€ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ์šฉ๋„)
    "protocol": "openid-connect",     // ์‚ฌ์šฉํ•  ํ”„๋กœํ† ์ฝœ (๋ณดํ†ต OpenID Connect ์‚ฌ์šฉ)
    "protocolMapper": "oidc-usermodel-attribute-mapper",// Mapper์˜ ํƒ€์ž… (User Attribute๋ฅผ ๋งคํ•‘)
    "config": {                            // ์‹ค์ œ ๋งคํ•‘ ์„ค์ •
        "user.attribute": "department",         // Keycloak์— ์ €์žฅ๋œ ์†์„ฑ ์ด๋ฆ„
        "claim.name": "department",        // ํ† ํฐ์— ํฌํ•จ๋  ๋•Œ ์‚ฌ์šฉํ•  ์ด๋ฆ„
        "token.claim": "true"        // ํ† ํฐ์— ํฌํ•จํ• ์ง€ ์—ฌ๋ถ€
    }
}

 

๐Ÿ“Ž  Token Claim

  • ํ† ํฐ์— ํฌํ•จ๋˜๋Š” ์ •๋ณด์˜ ํ•œ ์กฐ๊ฐ์œผ๋กœ, ์‚ฌ์šฉ์ž๋‚˜ ํ† ํฐ ์ž์ฒด์— ๋Œ€ํ•œ statement๋ฅผ ๋งํ•œ๋‹ค.
  • Protocol Mapper๋ฅผ ํ†ตํ•ด Attribute๋ฅผ Claim์œผ๋กœ ๋ณ€ํ™˜ํ•˜์—ฌ ํ† ํฐ์— ํฌํ•จ์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์‚ฌ์šฉ์ž ์ •๋ณด๋‚˜ ๊ถŒํ•œ ํ™•์ธ์— ์‚ฌ์šฉํ•œ๋‹ค.
{
    // ๊ธฐ๋ณธ Claims
    "sub": "user123",
    "iss": "http://keycloak.example.com",
    "exp": 1516239022,
    
    // User Attributes -> Claims
    "user_attributes": {
        "department": "HR",
        "location": ["Seoul"]
    },
    
    // Group Attributes -> Claims
    "group_attributes": {
        "costCenter": "HR001"
    }
}

 

๐Ÿ“Ž  Attribute์™€ Token Claim ๊ด€๊ณ„

์‚ฌ์šฉ์ž๋‚˜ ๊ทธ๋ฃน์˜ ์†์„ฑ(attributes)์€ protocol mapper์„ค์ •์„ ํ†ตํ•ด Token์— Claims ํ˜•ํƒœ๋กœ ๋‹ด๊ฒจ ์ „๋‹ฌ๋œ๋‹ค. 
์ฆ‰,Attribute๋Š” Keycloak ๋‚ด๋ถ€ ๋ฐ์ดํ„ฐ์ด๊ณ , Claim์€ ์ด ๋ฐ์ดํ„ฐ๋ฅผ ํ† ํฐ์„ ํ†ตํ•ด ์™ธ๋ถ€๋กœ ์ „๋‹ฌํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค.

 

์‹ค์Šต) Attribute ์‚ฌ์šฉ๋ฐฉ๋ฒ• 

User Attribute ์‚ฌ์šฉํ•˜๊ธฐ

๋จผ์ € ์‚ฌ์šฉ์ž ์†์„ฑ(Attributes)๋ฅผ ์„ค์ •ํ•ด๋ณด์ž.

1. [realm settings > User profile > create attribute]๋ฅผ ํด๋ฆญํ•˜๊ณ  department ์†์„ฑ์„ ๋งŒ๋“ ๋‹ค.

2. User Details์— ์ƒˆ๋กœ ์ƒ๊ธด Department์— ๊ฐ’์„ ์ž…๋ ฅํ•œ๋‹ค.

3. ์‚ฌ์šฉ์ž์— Attribute๊ฐ€ ์ œ๋Œ€๋กœ ์„ค์ • ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

# 1. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
export ADMIN_USERNAME="admin"
export ADMIN_PASSWORD="admin"
export CLIENT_ID="my-client"
export REALM_NAME="my-realm"
export KEYCLOAK_URL="http://localhost:8080"
export USER_NAME="user01"

# 2. ๊ด€๋ฆฌ์ž ํ† ํฐ ํš๋“
export ADMIN_TOKEN=$(curl -X POST "${KEYCLOAK_URL}/realms/master/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=admin-cli" \
-d "username=${ADMIN_USERNAME}" \
-d "password=${ADMIN_PASSWORD}" \
-d "grant_type=password" | jq -r '.access_token')

# 3. ์‚ฌ์šฉ์ž ID ์กฐํšŒ
export USER_ID=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users?username=${USER_NAME}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.[0].id')
echo $USER_ID

# 4. Client ID(UUID) ์กฐํšŒ
export CLIENT_UUID=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/clients?clientId=${CLIENT_ID}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json" | jq -r '.[0].id')
echo $CLIENT_UUID

# 5. ํ˜„์žฌ ์‚ฌ์šฉ์ž ์ •๋ณด ์กฐํšŒ
export USER_INFO=$(curl -X GET "${KEYCLOAK_URL}/admin/realms/${REALM_NAME}/users/${USER_ID}" \
-H "Authorization: Bearer ${ADMIN_TOKEN}" \
-H "Content-Type: application/json")
echo $USER_INFO | jq

# 6. User Attribute ์กฐํšŒ
echo "Current User Attributes:"
echo ${USER_INFO} | jq '.attributes' --color-output

user attribute์— department๊ฐ€ ์ถ”๊ฐ€๋œ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

4. Protocol Mapper๋ฅผ ์„ค์ •ํ•œ๋‹ค.

5. ์ด์ œ AccessToken์„ ๋ฐœ๊ธ‰๋ฐ›๊ณ  Attribute๊ฐ€ ํฌํ•จ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

# 1. ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ •
export USER_NAME="user01"
export USER_PASSWORD="user01"
export CLIENT_ID="my-client"
export REALM_NAME="my-realm"
export KEYCLOAK_URL="http://localhost:8080"


# 1. ์‚ฌ์šฉ์ž ํ† ํฐ ๋ฐœ๊ธ‰
export USER_TOKEN=$(curl -X POST "${KEYCLOAK_URL}/realms/${REALM_NAME}/protocol/openid-connect/token" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "client_id=${CLIENT_ID}" \
-d "username=${USER_NAME}" \
-d "password=${USER_PASSWORD}" \
-d "grant_type=password")

# 2. Access Token ์ถ”์ถœ
export ACCESS_TOKEN=$(echo $USER_TOKEN | jq -r '.access_token')

# 3. Access Token ๋””์ฝ”๋”ฉ (JWT)
echo $ACCESS_TOKEN | cut -d"." -f2 | tr -d '-' | tr '_' '/' | sed -e 's/$/\=/' | base64 -d | jq '.' --color-output

protocol mapper๊นŒ์ง€ ์„ค์ •ํ•˜๊ณ  ๋‚˜๋ฉด AccessToken์— Department๊ฐ€ ์ถ”๊ฐ€๋˜์–ด ์ „๋‹ฌ๋œ๋‹ค.


RBAC vs ABAC

์‹ค์ œ๋กœ๋Š” ํ•˜๋‚˜๋งŒ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์ด ์•„๋‹ˆ๋ผ 
๊ธฐ๋ณธ์ ์ธ ๊ถŒํ•œ์€ RBAC์œผ๋กœ ๊ด€๋ฆฌํ•˜๊ณ , ํŠน์ˆ˜ํ•œ ์ƒํ™ฉ์€ ABAC์œผ๋กœ ๋ณด์™„ํ•˜๋Š” ํ˜•ํƒœ๋กœ ๋‘ ๋ฐฉ์‹์„ ํ˜ผํ•ฉํ•˜์—ฌ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ๋งŽ๋‹ค.

๊ตฌ๋ถ„ RBAC ABAC
์„ค๋ช… Role๊ธฐ๋ฐ˜์˜ ์ ‘๊ทผ์ œ์–ด
{
"user": "user01",
"roles": ["admin"],
"groups": ["/hr/manager"],
"permissions": ["read", "write"]
}
์†์„ฑ ๊ธฐ๋ฐ˜์˜ ์ ‘๊ทผ์ œ์–ด
{
"user": {
"department": "HR",
"level": "senior",
"location": "Seoul",
"clearance": "top-secret"
},
"resource": {
"type": "document",
"classification": "confidential",
"department": "HR"
},
"action": "read",
"environment": {
"time": "09:00-18:00",
"ip_range": "10.0.0.0/24"
}
}
ํŠน์ง• ๋ฏธ๋ฆฌ ์ •์˜๋œ ์—ญํ• /๊ทธ๋ฃน์— ๊ธฐ๋ฐ˜
๊ด€๋ฆฌ๊ฐ€ ๋‹จ์ˆœ
๋ณ€๊ฒฝ์ด ์ ์€ ํ™˜๊ฒฝ์— ์ ํ•ฉ
ํ™•์žฅ์„ฑ ์ œํ•œ์ 
๋‹ค์–‘ํ•œ ์†์„ฑ ๊ธฐ๋ฐ˜ ๊ฒฐ์ •
์œ ์—ฐํ•œ ์ •์ฑ… ์„ค์ • ๊ฐ€๋Šฅ
์ƒํ™ฉ์— ๋”ฐ๋ฅธ ๋™์  ์ ‘๊ทผ ์ œ์–ด
๋ณต์žกํ•œ ๊ทœ์น™ ์ง€์›
์˜ˆ์‹œ @RolesAllowed("admin")
public void adminMethod() {
    // ๊ด€๋ฆฌ์ž๋งŒ ์ ‘๊ทผ ๊ฐ€๋Šฅ
}
@Attribute("department == 'HR' && time.between('09:00', '18:00')")
public void hrDocumentAccess() {
    // HR๋ถ€์„œ ์ง์›์ด ์—…๋ฌด์‹œ๊ฐ„ ๋‚ด ์ ‘๊ทผ
}
์‹œ๋‚˜๋ฆฌ์˜ค ์กฐ์ง ๊ตฌ์กฐ๊ฐ€ ๋ช…ํ™•ํ•œ ๊ธฐ์—… ์‹œ์Šคํ…œ
๊ถŒํ•œ ์ฒด๊ณ„๊ฐ€ ๋‹จ์ˆœํ•œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
์‚ฌ์šฉ์ž ๊ทธ๋ฃน์ด ๋ช…ํ™•ํ•œ ์‹œ์Šคํ…œ
๋ณต์žกํ•œ ๋ณด์•ˆ ์š”๊ตฌ์‚ฌํ•ญ์ด ์žˆ๋Š” ์‹œ์Šคํ…œ
์‹œ๊ฐ„/์œ„์น˜ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด ํ•„์š”
๋‹ค์–‘ํ•œ ์กฐ๊ฑด์— ๋”ฐ๋ฅธ ๋™์  ๊ถŒํ•œ ํ•„์š”

 

๐Ÿ“Ž ์ฃผ์˜์‚ฌํ•ญ

Role Explosion (์—ญํ•  ํญ๋ฐœ) ๋ฌธ์ œ๋ฅผ ์ฃผ์˜ํ•ด์•ผํ•œ๋‹ค. ์—ญํ• ์€ ์„ธ๋ถ„ํ™”๋œ ์ธ๊ฐ€๋ฅผ ์œ„ํ•œ ์—ญํ•  ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์„ ์ง€์–‘ํ•˜๊ณ , ์กฐ์ง ๊ตฌ์กฐ/์ง๋ฌด๋ฅผ ๋ฐ˜์˜ํ•˜๋„๋ก ํ•˜๋Š”๊ฒƒ์ด ์ข‹๋‹ค. (ADMIN, READ_USER ๋“ฑ)

  • ์—ญํ• (Role)์€ ํฐ ๋ฒ”์ฃผ๋กœ ์ •์˜ํ•œ๋‹ค. (admin, superuser, readonlyuser ํ˜น์€ department ๋“ฑ)
  • ์„ธ๋ถ€ ์ ‘๊ทผ์ œ์–ด๋Š” ์†์„ฑ(attributes)๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
{
    "accessPolicy": {
        "role": "MANAGER",
        "requiredAttributes": {
            "department": ["HR", "IT"],
            "location": "Seoul",
            "timeWindow": "businessHours"
        }
    }
}

 

Role Explosion (์—ญํ•  ํญ๋ฐœ) ๋ฌธ์ œ๋ž€,
์„ธ๋ถ€์ ์ธ ๋ถ€๋ถ„๊นŒ์ง€ ์ „๋ถ€ Role๋กœ ์ •์˜ํ•˜์—ฌ Role์ด ์—„์ฒญ ๋งŽ์•„์ง€๋Š”๊ฒƒ

728x90