๐ŸŒฑ Infra/KeyCloak

์ธ์ฆ ๋ฐ ๊ถŒํ•œ ํ”„๋กœํ† ์ฝœ OAuth 2.0, OpenID Connect, SAML ๊ทธ๋ฆฌ๊ณ  Zero Trust์— ๋Œ€ํ•˜์—ฌ

mini_world 2024. 11. 12. 22:03
๋ชฉ์ฐจ ์ ‘๊ธฐ

์ด ํฌ์ŠคํŒ…์—์„œ๋Š” ์ž์„ธํ•œ ๋‚ด์šฉ ๋ณด๋‹ค๋Š” ๊ฐœ๋…๋ง›๋ณด๊ธฐ๐Ÿ‘… ์ˆ˜์ค€์˜ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.

 

 

๐Ÿ“Œ OAuth 2.0, OpenID Connect, SAML ๊ฐ„๋‹จ ๊ฐœ๋… ์ •๋ฆฌ

 

  • OAuth 2.0: ๊ถŒํ•œ ๋ถ€์—ฌ์— ์ค‘์ ์„ ๋‘” ํ”„๋กœํ† ์ฝœ
  • OpenID Connect: OAuth 2.0์„ ํ™•์žฅํ•˜์—ฌ ์ธ์ฆ ๋ ˆ์ด์–ด ์ถ”๊ฐ€
  • SAML: ์—”ํ„ฐํ”„๋ผ์ด์ฆˆ ํ™˜๊ฒฝ์— ์ ํ•ฉํ•œ XML ๊ธฐ๋ฐ˜ ์ธ์ฆ ํ”„๋กœํ† ์ฝœ

 

๊ตฌ๋ถ„ OAuth 2.0 OpenID Connect SAML
๋ชฉ์  ๊ถŒํ•œ ๋ถ€์—ฌ(Authorization) ์‚ฌ์šฉ์ž ์ธ์ฆ(Authentication) ์‚ฌ์šฉ์ž ์ธ์ฆ(Authentication)
๋ฐ์ดํ„ฐ ํ˜•์‹ JSON JSON XML
์‚ฌ์šฉ ์‚ฌ๋ก€ API ์ธ์ฆ, ๋ชจ๋ฐ”์ผ ์•ฑ ์†Œ์…œ ๋กœ๊ทธ์ธ, API ์ธ์ฆ
๋ชจ๋ฐ”์ผ ์•ฑ, SPA, API ๊ธฐ๋ฐ˜ ์„œ๋น„์Šค์— ์ ํ•ฉ
๊ธฐ์—… SSO, ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์ฆ
์ „ํ†ต์ ์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉ
๋ณต์žก์„ฑ ์ค‘๊ฐ„ ์ค‘๊ฐ„
REST API ํ˜ธ์ถœ, JWT ์ฒ˜๋ฆฌ๋กœ ๋น„๊ต์  ๋‹จ์ˆœ
๋†’์Œ
XML ์ฒ˜๋ฆฌ, ๋ณต์žกํ•œ ๋ฆฌ๋‹ค์ด๋ ‰์…˜ ๋กœ์ง ํ•„์š”
๋ณด์•ˆํŠน์ง• Access Token, 
Refresh Token ์‚ฌ์šฉ
ID Token(JWT) ์ถ”๊ฐ€ ์‚ฌ์šฉ ๋””์ง€ํ„ธ ์„œ๋ช…, ์•”ํ˜ธํ™” ์ง€์›
ํ†ต์‹ ๋ฐฉ์‹ Authorization Code, 
Access Token ๊ตํ™˜
[์„œ๋ฒ„ ๊ฐ„ ์ง์ ‘ ํ†ต์‹  ๊ฐ€๋Šฅ, API ๊ธฐ๋ฐ˜ ํ†ต์‹ ]
Client ←→ Authorization Server
- ์„œ๋ฒ„ ๊ฐ„ ์ง์ ‘ ํ†ต์‹ 
- REST/JSON ๊ธฐ๋ฐ˜ ํ†ต์‹ 
- Token ๊ธฐ๋ฐ˜ ์ธ์ฆ
[๋ธŒ๋ผ์šฐ์ € ์ค‘์‹ฌ์˜ ๋ฆฌ๋””๋ ‰์…˜ ๊ธฐ๋ฐ˜ ํ†ต์‹ ]
SP ↔ Browser ↔ IdP
- ๋ชจ๋“  ํ†ต์‹ ์ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง
- XML ๊ธฐ๋ฐ˜์˜ ๋ฉ”์‹œ์ง€
- ๋ฆฌ๋‹ค์ด๋ ‰์…˜์„ ํ†ตํ•œ ํ†ต์‹ 
ํ‘œ์ค€ํ™” ๊ธฐ๊ตฌ IETF OpenID Foundation OASIS

 


 

๐Ÿ“Œ OAuth 2.0

OAuth 2.0 ์€ ์•ก์„ธ์Šคํ† ํฐ(AccessToken)์„ ํ†ตํ•ด API๋‚˜ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” "๊ถŒํ•œ๋ถ€์—ฌ(Authorization)"๋ฅผ ์œ„ํ•œ ํ”„๋กœํ† ์ฝœ์ด๋‹ค.  (The OAuth 2.0 Authorization Framework

The OAuth 2.0 Authorization Framework.txt
0.16MB

- ์ฃผ์š”๊ฐœ๋…

๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž
(Resource Owner)
์ž์›์— ๋Œ€ํ•œ ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž
ํด๋ผ์ด์–ธํŠธ
(Client)
์‚ฌ์šฉ์ž์˜ ์Šน์ธ์„ ๋ฐ›์•„ ๋ณดํ˜ธ๋œ ์ž์›์— ์ ‘๊ทผํ•˜๋ ค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ์„ ๋Œ€์‹  ๋ฐ›์•„์˜ค๊ณ , ์•ก์„ธ์Šค ํ† ํฐ์„ ๊ด€๋ฆฌํ•จ
๋ฆฌ์†Œ์Šค ์„œ๋ฒ„
(Resource Server)
๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ œ๊ณตํ•˜๋Š” ์„œ๋ฒ„
์ธ์ฆ์„œ๋ฒ„
(Authorization Server)
ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€์‹ ํ•ด ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ์•ก์„ธ์Šค ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ์„œ๋ฒ„
์•ก์„ธ์Šค ํ† ํฐ
(Access Token)
๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๋‚˜ํƒ€๋‚ด๋Š” ํ† ํฐ (ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์— ์š”์ฒญํ•  ๋•Œ ์‚ฌ์šฉํ•จ)

 

- ์ฃผ์š” ๊ถŒํ•œ ๋ถ€์—ฌ ์œ ํ˜•(Grant Types)

* ์ฐธ๊ณ :
- https://alexbilbie.github.io/guide-to-oauth-2-grants/
- https://oauth.net/2/grant-types/
- https://www.2e.co.kr/news/articleView.html?idxno=208594

Authorization Code
Grant
์Šน์ธ ์ฝ”๋“œ ์œ ํ˜•
์ฃผ๋กœ ์„œ๋ฒ„๊ฐ„ ํ†ต์‹ ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค. 
์‚ฌ์šฉ์ž๊ฐ€ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋กœ๊ทธ์ธํ•œ ํ›„ ์ธ์ฆ ์„œ๋ฒ„๋Š” Authorization Code๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ์ „์†กํ•œ๋‹ค.
ํด๋ผ์ด์–ธํŠธ๋Š” ์ด ์ฝ”๋“œ๋ฅผ ์‚ฌ์šฉํ•ด ์ธ์ฆ ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ Access Token์„ ์š”์ฒญํ•œ๋‹ค.
๋ณด์•ˆ์„ฑ์ด ๋†’์Œ (Access Token์ด ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ๋…ธ์ถœ๋˜์ง€ ์•Š์Œ).
OpenID Connect๋Š” ์ด ์ค‘ ์ฃผ๋กœ Authorization Code Grant๋ฅผ ํ™•์žฅํ•˜์—ฌ ์‚ฌ์šฉํ•œ๋‹ค.
Client Credentials
Grant
์•ฑ์ธ์ฆ ์œ ํ˜•
์‚ฌ์šฉ์ž์—†์ด ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ž์ฒด์˜ ์ธ์ฆ๋งŒ ํ•„์š”ํ•œ ๊ฒฝ์šฐ (e.g. ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋ฆฌ์†Œ์Šค ์˜ค๋„ˆ์ธ ๊ฒฝ์šฐ)์‚ฌ์šฉํ•˜๋ฉฐ,
์ฃผ๋กœ ๋ฐฑ์—”๋“œ ์‹œ์Šคํ…œ ๊ฐ„์˜ API ํ˜ธ์ถœ๊ณผ ๊ฐ™์€ ์„œ๋ฒ„ ๊ฐ„ ํ†ต์‹ ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค.
ํด๋ผ์ด์–ธํŠธ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์ž์ฒด ์ž๊ฒฉ ์ฆ๋ช…์„ ์‚ฌ์šฉํ•˜์—ฌ ์ธ์ฆ ์„œ๋ฒ„์—์„œ Access Token์„ ์š”์ฒญํ•œ๋‹ค.
Device Authorization 
Grant
๋””๋ฐ”์ด์Šค ์ธ์ฆ ์œ ํ˜•
๋””์Šคํ”Œ๋ ˆ์ด๋‚˜ ํ‚ค๋ณด๋“œ๊ฐ€ ์—†๋Š” ๋””๋ฐ”์ด์Šค(์˜ˆ: ์Šค๋งˆํŠธ TV, IoT ๊ธฐ๊ธฐ ๋“ฑ)๊ฐ€ ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•  ๋•Œ ์‚ฌ์šฉํ•œ๋‹ค.
๋””๋ฐ”์ด์Šค๋Š” ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณ„๋„์˜ ์ธ์ฆ ํŽ˜์ด์ง€(URL)์™€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ์ œ๊ณตํ•˜๊ณ , ์‚ฌ์šฉ์ž๋Š” ์ด ์ •๋ณด๋ฅผ ๋ธŒ๋ผ์šฐ์ €๋‚˜ ์Šค๋งˆํŠธํฐ์—์„œ ์ž…๋ ฅํ•˜์—ฌ ์ธ์ฆ์„ ์™„๋ฃŒํ•œ๋‹ค.
์˜ˆ) ์Šค๋งˆํŠธ TV์—์„œ ์œ ํŠœ๋ธŒ ์•ฑ์— ๋กœ๊ทธ์ธํ•˜๊ณ  ์‹ถ์„ ๋•Œ, TV ํ™”๋ฉด์— "https://example.com/device"์™€ ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ํ‘œ์‹œํ•จ
Implicit Grant
์•”๋ฌต์  ์œ ํ˜• 
(์‚ฌ์šฉ โŒโŒโŒ)
์ฃผ๋กœ SPA(Single Page Application) ์—์„œ ์‚ฌ์šฉ๋œ๋‹ค. 
ํด๋ผ์ด์–ธํŠธ๋Š” Authorization Code๋ฅผ ์š”์ฒญํ•˜๋Š” ๋Œ€์‹ , ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธํ•˜๋ฉด ๋ฐ”๋กœ Access Token์„ ๋ฐ›๋Š”๋‹ค.
์ธ์ฆ ๊ณผ์ •์ด ๊ฐ„๋‹จํ•˜์ง€๋งŒ Access Token์ด URL๋กœ ๋…ธ์ถœ๋˜์–ด ๋ณด์•ˆ์„ฑ์ด ๋‚ฎ์•„ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š”๋‹ค.
Resource Owner Password Credentials Grant
์‚ฌ์šฉ์ž ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ์œ ํ˜•
(์‚ฌ์šฉ โŒโŒโŒ)
์‚ฌ์šฉ์ž๊ฐ€ ์•ฑ ์ƒ์œผ๋กœ ID/๋น„๋ฐ€๋ฒˆํ˜ธ๋กœ ๋กœ๊ทธ์ธํ•˜์—ฌ ์ธ์ฆํ•˜๊ณ  ๊ถŒํ•œ ๋ถ€์—ฌ์— ๋™์˜ํ•˜๋ฉด ์ ‘๊ทผ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ์œ ํ˜•์ด๋‹ค.
์‚ฌ์šฉ์ž ์ž๊ฒฉ ์ฆ๋ช…์ด ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋…ธ์ถœ๋˜๊ธฐ ๋•Œ๋ฌธ์— ๋ณด์•ˆ ์œ„ํ—˜์ด ๋†’์•„ ์ž์‚ฌ ์„œ๋น„์Šค๋‚˜ ๋งค์šฐ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ๋งŒ ์ œํ•œ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.


- OAuth  2.0 ๊ธฐ๋ณธ ํ๋ฆ„

 

  • (A): ํด๋ผ์ด์–ธํŠธ(Client)๊ฐ€ ๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž(Resource Owner)์—๊ฒŒ ์ธ์ฆ ์š”์ฒญ์„ ๋ณด๋ƒ„
  • (B): ๋ฆฌ์†Œ์Šค ์†Œ์œ ์ž(Resource Owner)๊ฐ€ ํด๋ผ์ด์–ธํŠธ(Client)์—๊ฒŒ ์ธ์ฆ ์Šน์ธ ๋ถ€์—ฌ (Authorization Grant).
  • (C): ํด๋ผ์ด์–ธํŠธ(Client)๋Š” ์ด ์ธ์ฆ ์Šน์ธ์„ ๊ถŒํ•œ ์„œ๋ฒ„(Authorization Server)์— ์ „๋‹ฌํ•˜์—ฌ ์•ก์„ธ์Šค ํ† ํฐ ์š”์ฒญ
  • (D): ๊ถŒํ•œ ์„œ๋ฒ„๋Š”(Authorization Server) ํด๋ผ์ด์–ธํŠธ(Client)์—๊ฒŒ ์•ก์„ธ์Šค ํ† ํฐ ๋ฐ˜ํ™˜
  • (E): ํด๋ผ์ด์–ธํŠธ(Client)๋Š” ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„(Resource Server)์— ์•ก์„ธ์Šค ํ† ํฐ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผ
  • (F): ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„๊ฐ€ ์š”์ฒญ๋œ ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜

 

 


- OAuth  2.0 ์ธ์ฆ ์˜ˆ์‹œ (์ฒ ์ˆ˜์˜ ๊ตฌ๊ธ€๋“œ๋ผ์ด๋ธŒ)

+-----------+                                                                        
|  Client   |                                     +------------------+
| (ํฌํ† ๋ถ ์•ฑ) |  ----(A) Authorization Request----> |  Resource Owner  |
|           |  <----(B) Authorization Grant-----  |    (์ฒ ์ˆ˜)         |
|           |                                     +------------------+
|           |                                      
|           |                                     +------------------+
|           |  ----(C) Authorization Grant----->  | Authorization    |
|           |  <----(D) Access Token-----------   |     Server       |
|           |                                     |  (๊ตฌ๊ธ€ OAuth)     |
|           |                                     +------------------+
|           |                                     
|           |                                     +------------------+
|           |  ----(E) Access Token------------>  | Resource Server  |
|           |  <----(F) Protected Resource------  |  (๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ)    |
+-----------+                                     +------------------+

 

  • (A) Authorization Request
    • ํฌํ† ๋ถ ์•ฑ์€ ์ฒ ์ˆ˜์—๊ฒŒ "๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ์˜ ์‚ฌ์ง„์„ ๊ฐ€์ ธ์™€๋„ ๋˜๊ฒ ์Šต๋‹ˆ๊นŒ?"๋ผ๋Š” ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.
    • ์ฒ ์ˆ˜๋Š” "ํ—ˆ์šฉ" ๋ฒ„ํŠผ์„ ํด๋ฆญํ•œ๋‹ค.
  • (B) Authorization Grant
    • ์ฒ ์ˆ˜๊ฐ€ "ํ—ˆ์šฉ"์„ ํด๋ฆญํ•˜๋ฉด, ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„๋Š” ํฌํ† ๋ถ ์•ฑ์— ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
    • ์ธ์ฆ ์ฝ”๋“œ๋Š” ์ฒ ์ˆ˜๊ฐ€ ์ ‘๊ทผ์„ ํ—ˆ์šฉํ–ˆ๋‹ค๋Š” ์ฆ๋ช…์ด๋‹ค.
  • (C) Authorization Grant
    • ํฌํ† ๋ถ ์•ฑ์€ ์ด ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„์— ๋ณด๋‚ด๋ฉฐ, "์•ก์„ธ์Šค ํ† ํฐ์„ ์ฃผ์„ธ์š”!"๋ผ๊ณ  ์š”์ฒญํ•œ๋‹ค.
  • (D) Access Token
    • ๊ตฌ๊ธ€ OAuth ์„œ๋ฒ„๋Š” ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ๊ฒ€์ฆํ•œ ํ›„, ํฌํ† ๋ถ ์•ฑ์— "์•ก์„ธ์Šค ํ† ํฐ"์„ ๋ฐœ๊ธ‰ํ•œ๋‹ค.
    • ์ด ํ† ํฐ์€ ํฌํ† ๋ถ ์•ฑ์ด ๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•œ๋‹ค.
  • (E) Access Token
    • ํฌํ† ๋ถ ์•ฑ์€ ๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ ์„œ๋ฒ„์— ์•ก์„ธ์Šค ํ† ํฐ์„ ํฌํ•จํ•œ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.
    • "์ด ํ† ํฐ์œผ๋กœ ์ฒ ์ˆ˜์˜ ์‚ฌ์ง„์„ ๊ฐ€์ ธ์˜ค๊ฒ ์Šต๋‹ˆ๋‹ค!"๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.
  • (F) Protected Resource
    • ๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ ์„œ๋ฒ„๋Š” ์•ก์„ธ์Šค ํ† ํฐ์˜ ์œ ํšจ์„ฑ์„ ํ™•์ธํ•œ ํ›„, ์ฒ ์ˆ˜์˜ ์‚ฌ์ง„ ํŒŒ์ผ์„ ํฌํ† ๋ถ ์•ฑ์— ๋ฐ˜ํ™˜ํ•œ๋‹ค.

 

 

- OAuth  2.0 Confidential Client / Public Client ๊ฐœ๋… ์ดํ•ด

[์ฐธ๊ณ ] What's the difference between Confidential and Public clients? - OAuth in Five Minutes

OAuth 2.0์—์„œ ํด๋ผ์ด์–ธํŠธ๋ฅผ "๊ธฐ๋ฐ€ ํด๋ผ์ด์–ธํŠธ"์™€ "๊ณต์šฉ ํด๋ผ์ด์–ธํŠธ"๋กœ ๋‚˜๋ˆ„๋Š” ์ด์œ ๋Š” ๋ณด์•ˆ ์ˆ˜์ค€์ด ๊ฐ๊ธฐ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์ด๋ฉฐ,
๋ณด์•ˆ์ด ์ทจ์•ฝํ•œ ํ™˜๊ฒฝ์—์„œ๋Š” ๊ณต์šฉ ํด๋ผ์ด์–ธํŠธ์˜ ํ† ํฐ์ด ์‰ฝ๊ฒŒ ๋…ธ์ถœ๋  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ณ„๋„์˜ ๋ณด์•ˆ ๊ฐ•ํ™” ์žฅ์น˜๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

  • ๊ธฐ๋ฐ€ ํด๋ผ์ด์–ธํŠธ(Confidential Client)
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด์•ˆ๋œ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ, ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•  ์ˆ˜ ์žˆ๋Š” ํด๋ผ์ด์–ธํŠธ
    • ์˜ˆ์‹œ. ์‡ผํ•‘ ์•ฑ์˜ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„ (.env, $key=)
    • ๋ณดํ†ต ์™ธ๋ถ€์™€๋Š” ์—ฐ๊ฒฐ๋˜์ง€ ์•Š๊ณ , ์ž์‹ ์˜ ์„œ๋ฒ„ ๋‚ด๋ถ€์—์„œ ๋ฏผ๊ฐํ•œ ์ •๋ณด(ํด๋ผ์ด์–ธํŠธ ๋น„๋ฐ€, ํ† ํฐ ๋“ฑ)๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๋ฅผ ๋งํ•œ๋‹ค.
  • ๊ณต์šฉ ํด๋ผ์ด์–ธํŠธ(Public Client)
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด์•ˆ๋˜์ง€ ์•Š์€ ํ™˜๊ฒฝ์—์„œ ์‹คํ–‰๋˜๋ฏ€๋กœ, ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•  ์ˆ˜ ์—†๋Š” ํด๋ผ์ด์–ธํŠธ
    • ์˜ˆ์‹œ. ๋ชจ๋ฐ”์ผ ์•ฑ ๋˜๋Š” ์›น ๋ธŒ๋ผ์šฐ์ € SPA
    • ๊ฐœ์ธ์˜ ์Šค๋งˆํŠธํฐ์ด๋‚˜ PC์—์„œ ์‹คํ–‰๋˜๋Š”๋ฐ, ๋””์ปดํŒŒ์ผ๋˜๊ฑฐ๋‚˜ ๋„คํŠธ์›Œํฌ์—์„œ ๋ฐ์ดํ„ฐ๊ฐ€ ํƒˆ์ทจ๋  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค.

์ฆ‰, ๊ณต์šฉ ํด๋ผ์ด์–ธํŠธ์˜ ๊ฒฝ์šฐ PKCE(Proof Key for Code Exchange) ๊ฐ™์€ ๋ณด์•ˆ ๋ฐฉ์‹์„ ํ†ตํ•ด ์ธ์ฆ ์ฝ”๋“œ๊ฐ€ ํƒˆ์ทจ๋˜๋”๋ผ๋„ ๊ณต๊ฒฉ์ž๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋„๋ก ๋ณดํ˜ธํ•ด์•ผํ•œ๋‹ค.

 

- PKCE (Proof Key for Code Exchange) ๋ž€? ( ํ”ฝ์‹œ(Pixy)- ๋ผ๊ณ  ์ฝ๋Š”๋‹ค ๐Ÿ˜Ž)

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

  • ์ž‘๋™ ์›๋ฆฌ:
    PKCE๋Š” ์ธ์ฆ ์š”์ฒญ๊ณผ ์ธ์ฆ ์ฝ”๋“œ ๊ตํ™˜ ์‹œ, ์ฝ”๋“œ ๊ฒ€์ฆ ๊ฐ’ (code_challenge/code_verifier) ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ธ์ฆ ์ฝ”๋“œ์˜ ์•ˆ์ „์„ฑ์„ ๋ณด์žฅํ•œ๋‹ค.
    • code_verifier (์›๋ณธ ๊ฐ’)
    • code_challenge (verifier์˜ ํ•ด์‹œ๊ฐ’/๋‹จ๋ฐฉํ–ฅ ํ•ด์‹œ๋กœ, ์—ญ์‚ฐ์ด ๋ถˆ๊ฐ€๋Šฅ)
  • PKCE๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค
    1. ์ •์ƒ ์•ฑ: ์ธ์ฆ ์š”์ฒญ (client_id + redirect_uri)
    2. ์•…์„ฑ ์•ฑ: ์ด ์š”์ฒญ์„ ๊ฐ€๋กœ์ฑ”
    3. ์•…์„ฑ ์•ฑ: ๊ฐ€๋กœ์ฑˆ ์ •๋ณด๋กœ ์ธ์ฆ ์„œ๋ฒ„์— ์ ‘๊ทผ
    4. ์ธ์ฆ ์„œ๋ฒ„: ์ฝ”๋“œ ๋ฐœ๊ธ‰
    5. ์•…์„ฑ ์•ฑ: ๋ฐœ๊ธ‰๋ฐ›์€ ์ฝ”๋“œ๋กœ ์•ก์„ธ์Šค ํ† ํฐ ํš๋“ ๐Ÿ˜ˆ
  • PKCE๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค
    1. ์ •์ƒ ์•ฑ: ๋žœ๋คํ•œ code_verifier ์ƒ์„ฑ (์˜ˆ: "abc123xyz789")
    2. ์ •์ƒ ์•ฑ: code_verifier๋ฅผ ํ•ด์‹œํ•˜์—ฌ code_challenge ์ƒ์„ฑ
    3. ์ •์ƒ ์•ฑ: ์ธ์ฆ ์š”์ฒญ ์‹œ code_challenge ํฌํ•จํ•ด์„œ ์ „์†ก
    4. ์ธ์ฆ ์„œ๋ฒ„: code_challenge ์ €์žฅ
    5. ์ •์ƒ ์•ฑ: ์•ก์„ธ์Šค ํ† ํฐ ์š”์ฒญ ์‹œ ์›๋ณธ code_verifier ์ „์†ก
    6. ์ธ์ฆ ์„œ๋ฒ„: code_verifier๋ฅผ ํ•ด์‹œํ•ด์„œ ์ €์žฅ๋œ challenge์™€ ๋น„๊ต
  • PKCE๊ฐ€ ํฌํ•จ๋œ ๋‹ค์ด์–ด๊ทธ๋žจ
    • ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋žœ๋คํ•œ code_verifier ์ƒ์„ฑ
    • code_verifier๋ฅผ SHA256์œผ๋กœ ํ•ด์‹œํ•˜์—ฌ code_challenge ์ƒ์„ฑ
    • ์ธ์ฆ ์š”์ฒญ ์‹œ code_challenge ํฌํ•จํ•˜์—ฌ ์ „์†ก
    • ์ธ์ฆ ์„œ๋ฒ„๋Š” code_challenge ์ €์žฅ
    • ์ธ์ฆ ์ฝ”๋“œ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜
    • ํด๋ผ์ด์–ธํŠธ๋Š” ํ† ํฐ ์š”์ฒญ ์‹œ ์›๋ณธ code_verifier ์ „์†ก
    • ์„œ๋ฒ„๋Š” ๋ฐ›์€ verifier๋กœ challenge๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ์ €์žฅ๋œ ๊ฐ’๊ณผ ๋น„๊ต
    • ๊ฒ€์ฆ ์„ฑ๊ณต ์‹œ ์•ก์„ธ์Šค ํ† ํฐ ๋ฐœ๊ธ‰
    • ํด๋ผ์ด์–ธํŠธ๋Š” ์•ก์„ธ์Šค ํ† ํฐ์œผ๋กœ API ์š”์ฒญ
    • ๋ณดํ˜ธ๋œ ๋ฆฌ์†Œ์Šค ์‘๋‹ต
+--------+                  +-----------+              +-----------+
|        |                  |           |              |           |
| Client |                  | Auth      |              | Resource  |
|        |                  | Server    |              | Server    |
+--------+                  +-----------+              +-----------+
    |                            |                           |
    | 1. Generate verifier       |                           |
    | code_verifier="abc123"     |                           |
    |                            |                           |
    | 2. Generate challenge      |                           |
    | challenge=hash(verifier)    |                           |
    |                            |                           |
    | 3. Auth Request            |                           |
    |--------------------------->|                           |
    | client_id, challenge       |                           |
    |                            |                           |
    |                            | 4. Store challenge        |
    |                            | Show auth screen          |
    |                            |                           |
    | 5. Auth Response           |                           |
    |<---------------------------|                           |
    | auth_code                  |                           |
    |                            |                           |
    | 6. Token Request           |                           |
    |--------------------------->|                           |
    | auth_code, verifier        |                           |
    |                            |                           |
    |                            | 7. Verify:                |
    |                            | hash(verifier) == challenge|
    |                            |                           |
    | 8. Token Response          |                           |
    |<---------------------------|                           |
    | access_token               |                           |
    |                            |                           |
    | 9. API Request             |                           |
    |------------------------------------------------->|    |
    | Bearer access_token        |                           |
    |                            |                           |
    | 10. Resource Response      |                           |
    |<-------------------------------------------------|    |
    | Data                       |                           |
    |                            |                           |
  1.  

 

- Bearer Tokens ๐ŸŽซ  (์ „๋‹ฌ ๋ฐฉ์‹)

OAuth2.0์€ ์ ‘๊ทผํ† ํฐ ์œ ํ˜•์ด๋‚˜ ์‚ฌ์šฉ๋ฐฉ๋ฒ•์— ๋Œ€ํ•ด ์ •์˜๋˜์–ด์žˆ์ง€ ์•Š์œผ๋ฉฐ,
Bearer Token์€ ํ˜„์žฌ ๊ฐ€์žฅ ์ผ๋ฐ˜์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” ์ ‘๊ทผํ† ๊ทผ์œ ํ˜•์ด๋‹ค.

Bearer Token์€ "์†Œ์ง€์ž ํ† ํฐ"์ด๋ผ๊ณ ๋„ ํ•œ๋‹ค.  (ํ˜„๊ธˆ์ฒ˜๋Ÿผ, ๋ˆ„๊ตฌ๋“  ์ด ํ† ํฐ์„ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค)

// Bearer Token ์‚ฌ์šฉ ์˜ˆ์‹œ
fetch('https://api.example.com/data', {
    headers: {
        'Authorization': 'Bearer eyJhbGciOiJIUzI1NiIs...'
    }
});
  • ํŠน์ง•
    • ๋‹จ์ˆœํžˆ ํ† ํฐ์„ ์ œ์‹œํ•˜๋Š” ๊ฒƒ๋งŒ์œผ๋กœ ์ธ์ฆ๋œ๋‹ค. ํƒˆ์ทจ๋˜๋ฉด ๋ˆ„๊ตฌ๋‚˜ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๋‹ค. (์œ„ํ—˜!)
    •  ์ผ๋ฐ˜์ ์œผ๋กœ JWT ํ˜•ํƒœ๋กœ ๊ตฌํ˜„
    • Authorization Header๋ฅผ ํ†ตํ•ด ์ „์†ก๋˜๋ฉฐ, ์ธ์ฝ”๋”ฉ์ฒ˜๋ฆฌ๋œ ํŽ˜์ด๋กœ๋“œ(body) ๋˜๋Š” ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „๋‹ฌ๋œ๋‹ค.
      ์ฃผ์˜ํ• ์ ์€, Bearerํ† ํฐ์„ ์ฟผ๋ฆฌ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ „์†กํ•˜๋Š”๊ฒƒ์€ ๊ทธ ์ž์ฒด๋กœ ๋ณด์•ˆ์ทจ์•ฝ์ ์ด๊ธฐ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์•„์•ผํ•œ๋‹ค.
       

 

- Token Introspection ๐Ÿ”

ํ† ํฐ์˜ ํ˜„์žฌ ์ƒํƒœ์™€ ์œ ํšจ์„ฑ์„ ํ™•์ธํ•˜๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ๋งํ•œ๋‹ค.

// Token Introspection ์š”์ฒญ ์˜ˆ์‹œ
const response = await fetch('https://auth-server.com/introspect', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: 'token=eyJhbGciOiJIUzI1NiIs...'
});

// ์‘๋‹ต ์˜ˆ์‹œ
{
    "active": true,
    "client_id": "123456",
    "username": "jsmith",
    "scope": "read write",
    "exp": 1589391341
}
  • ํŠน์ง•
    • ํ† ํฐ์ด ์œ ํšจํ•œ์ง€ ์‹ค์‹œ๊ฐ„ ํ™•์ธ ๊ฐ€๋Šฅํ•˜๋‹ค,
    • ํ† ํฐ์˜ ์ƒ์„ธ ์ •๋ณด ์กฐํšŒ ๊ฐ€๋Šฅํ•˜๋‹ค.
    • ์ค‘์•™ ์ง‘์ค‘์‹ ํ† ํฐ ๊ด€๋ฆฌ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

- Token Revocation ๐Ÿšซ

๋ฐœ๊ธ‰๋œ ํ† ํฐ์„ ๋ฌดํšจํ™”ํ•˜๋Š” ํ”„๋กœ์„ธ์Šค๋ฅผ ๋งํ•œ๋‹ค.
์‚ฌ์šฉ์ž ๋กœ๊ทธ์•„์›ƒ, ๋ณด์•ˆ ์นจํ•ด ๋ฐœ์ƒ, ๊ถŒํ•œ ๋ณ€๊ฒฝ, ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ ๋“ฑ์˜ ์ƒํ™ฉ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

// Token Revocation ์š”์ฒญ ์˜ˆ์‹œ
fetch('https://auth-server.com/revoke', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
    },
    body: 'token=eyJhbGciOiJIUzI1NiIs...'
});

 

- Bearer Tokens / Token Introspection/  Token Revocation ๊ฐœ๋… ๊ด€๊ณ„ ๋ฐ ์ฝ”๋“œ์ƒ˜ํ”Œ

[Bearer Token]
      โ”‚
      โ”œโ”€โ”€> [Token Introspection]
      โ”‚     - ํ† ํฐ ์œ ํšจ์„ฑ ํ™•์ธ
      โ”‚     - ํ† ํฐ ์ •๋ณด ์กฐํšŒ
      โ”‚
      โ””โ”€โ”€> [Token Revocation]
            - ํ† ํฐ ๋ฌดํšจํ™”
            - ์ ‘๊ทผ ๊ถŒํ•œ ํšŒ์ˆ˜
class TokenService {
    // Bearer ํ† ํฐ ์ƒ์„ฑ
    async createBearerToken(user) {
        return jwt.sign({ userId: user.id }, 'secret', { expiresIn: '1h' });
    }

    // ํ† ํฐ ๊ฒ€์‚ฌ (Introspection)
    async introspectToken(token) {
        try {
            const decoded = jwt.verify(token, 'secret');
            const isRevoked = await this.checkIfTokenRevoked(token);
            
            return {
                active: !isRevoked,
                ...decoded
            };
        } catch (error) {
            return { active: false };
        }
    }

    // ํ† ํฐ ํ๊ธฐ (Revocation)
    async revokeToken(token) {
        await redis.set(`revoked:${token}`, 'true');
        await redis.expire(`revoked:${token}`, 24 * 60 * 60); // 24์‹œ๊ฐ„ ์œ ์ง€
    }
}

 


๐Ÿ“Œ OpenID Connect

์‚ฌ์šฉ์ž ์ธ์ฆ(Authentication)์„ ์œ„ํ•œ ํ”„๋กœํ† ์ฝœ๋กœ ์‹œ์ž‘๋˜์—ˆ์œผ๋‚˜ ํ˜„์žฌ๋Š” OAuth 2.0์„ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•œ ์‚ฌ์šฉ์ž ์ธ์ฆ ํ”„๋กœํ† ์ฝœ์ด๋‹ค. 

OpenID Connect๋Š”, OAuth 2.0 ํ”„๋กœํ† ์ฝœ ์œ„์— ๊ตฌ์ถ•๋œ Identity Layer์ด๋‹ค.
OAuth 2.0์ด ๊ถŒํ•œ ๋ถ€์—ฌ(Authorization)์— ์ค‘์ ์„ ๋‘”๋‹ค๋ฉด, OpenID Connect๋Š” ์ธ์ฆ(Authentication)์„ ์ถ”๊ฐ€ํ•œ ํ”„๋กœํ† ์ฝœ์ด๋‹ค.

OpenID Connect๋Š” OAuth2.0์˜ Authorization Code Grant (์Šน์ธ์ฝ”๋“œ์œ ํ˜•)์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

 

๋งŽ์€ ๋Œ€ํ˜• ์„œ๋น„์Šค ์ œ๊ณต์—…์ฒด๋“ค์ด OIDC Provider(IdP)๋กœ ํ™œ์šฉ๋˜๊ณ ์žˆ๋‹ค.

- ์ฃผ์š” OIDC Provider

  • Google
  • Microsoft Azure AD
  • Okta
  • AWS Cognito
  • GitHub
  • Facebook

 

- ์ฃผ์š”๊ฐœ๋…
์ตœ์ข… ์‚ฌ์šฉ์ž
(End User) 
์‹ค์ œ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‚ฌ์šฉ์ž
Relying Party
(RP)
OpenID Provider๋ฅผ ์‹ ๋ขฐํ•˜๊ณ  ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์š”์ฒญํ•˜๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ (์˜ˆ, ๋กœ๊ทธ์ธํŽ˜์ด์ง€)
OpenID Provider
(OP)  
์‚ฌ์šฉ์ž์˜ ์‹ ์›์„ ์ฆ๋ช…ํ•˜๊ณ  ID Token์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ์„œ๋ฒ„ (์˜ˆ: Google, Keycloak)
ID Token ์‚ฌ์šฉ์ž์˜ ์‹ ์› ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” JWT(JSON Web Token) ํ˜•์‹์˜ ํ† ํฐ
UserInfo
Endpoint 
์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ์ œ๊ณตํ•˜๋Š” ํ‘œ์ค€ํ™”๋œ REST API

 

- ์ธ์ฆ ํ๋ฆ„ ์œ ํ˜•

* ์ฐธ๊ณ : https://backstage.forgerock.com/docs/am/6/oidc1-guide/

Authorization Code Flow
๊ธฐ๋ณธ ์ธ์ฆ ํ๋ฆ„
๊ฐ€์žฅ ์ผ๋ฐ˜์ ์ด๊ณ  ์•ˆ์ „ํ•œ ๋ฐฉ์‹ 
์„œ๋ฒ„ ์‚ฌ์ด๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉ
ID Token๊ณผ Access Token ๋ชจ๋‘ ๋ฐฑ์—”๋“œ์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ์ฒ˜๋ฆฌ
Implicit Flow
์•”๋ฌต์  ํ๋ฆ„ 
(์‚ฌ์šฉ โŒโŒโŒ)
SPA์™€ ๊ฐ™์€ ํด๋ผ์ด์–ธํŠธ ์‚ฌ์ด๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ์ ํ•ฉ
๋ณด์•ˆ์„ฑ์ด ๋‹ค์†Œ ๋‚ฎ์Œ
๋ฆฌ๋‹ค์ด๋ ‰ํŠธ๋ฅผ ํ†ตํ•ด ์ง์ ‘ ID Token์„ ๋ฐ›์Œ
Hybrid Flow
ํ•˜์ด๋ธŒ๋ฆฌ๋“œ ํ๋ฆ„ 
Authorization Code Flow์™€ Implicit Flow์˜ ์กฐํ•ฉ
ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ๋ชจ๋‘์—์„œ ํ† ํฐ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ์‚ฌ์šฉ
์ผ๋ถ€ ํ† ํฐ์€ ํ”„๋ก ํŠธ์—”๋“œ๋กœ, ์ผ๋ถ€๋Š” ๋ฐฑ์—”๋“œ๋กœ ์ „๋‹ฌ

 

- OpenID Connect์˜ Authorization Code Flow ๋‹ค์ด์–ด๊ทธ๋žจ

+---------+            +--------+            +-----------+
|         |            |        |            |           |
| EndUser |            |   RP   |            |    OP     |
|         |            |        |            |(KeyCloak) |
+---------+            +--------+            +-----------+
    |                      |                      |
    | 1. ์„œ๋น„์Šค ์ ‘๊ทผ          |                      |
    |--------------------->|                      |
    |                      |                      |
    |                      | 2. Auth Request      |
    |                      |--------------------->|
    |                      | scope=openid profile |
    |                      | response_type=code   |
    |                      | client_id, state     |
    |                      |                      |
    | 3. ์ธ์ฆ ํ™”๋ฉด           |                      |
    |<--------------------------------------------|
    |                      |                      |
    | 4. ์ธ์ฆ์ •๋ณด ์ œ๊ณต        |                      |
    |-------------------------------------------->|
    | (id/password)        |                      |
    |                      |                      |
    |                      | 5. Auth Code         |
    |                      |<---------------------|
    |                      | code=xyz789          |
    |                      |                      |
    |                      | 6. Token Request     |
    |                      |--------------------->|
    |                      | code, client_creds   |
    |                      |                      |
    |                      | 7. Token Response    |
    |                      |<---------------------|
    |                      | id_token             |
    |                      | access_token         |
    |                      |                      |
    |                      | 8. UserInfo Request  |
    |                      |--------------------->|
    |                      | Bearer token         |
    |                      |                      |
    |                      | 9. UserInfo Response |
    |                      |<---------------------|
    |                      | {sub,name,email,...} |
    |                      |                      |
  1. EndUser -> RP
    • ์‚ฌ์šฉ์ž๊ฐ€ ์„œ๋น„์Šค(RP) ์ ‘๊ทผ
    • ๋กœ๊ทธ์ธ ํ•„์š”
  2. RP -> OP
    • ์ธ์ฆ ์š”์ฒญ ์‹œ์ž‘
    • OpenID scope ์ง€์ •
  3. OP -> EndUser : ๋กœ๊ทธ์ธ ํ™”๋ฉด ํ‘œ์‹œ
  4. EndUser -> OP
    • ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด ์ œ๊ณต
    • ๊ถŒํ•œ ๋™์˜
  5. OP -> RP : ์ธ์ฆ ์ฝ”๋“œ ์ „๋‹ฌ
  6. RP -> OP : ์ฝ”๋“œ๋กœ ํ† ํฐ ์š”์ฒญ
  7. OP -> RP
    • ID Token
    • Access Token
  8. RP -> OP : UserInfo ์š”์ฒญ
  9. OP -> RP : ์‚ฌ์šฉ์ž ์ •๋ณด ์ „๋‹ฌ

 

- OAuth 2.0๊ณผ OIDC์˜ ์ฃผ์š” ์ฐจ์ด์  (scope ๐Ÿ“‹)

ํด๋ผ์ด์–ธํŠธ ์ดˆ๊ธฐ ์š”์ฒญ์— scope ๊ฐ€ ์ถ”๊ฐ€๋œ๋‹ค.

OIDC์˜ Scope๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด์˜ ๋ฒ”์œ„๋ฅผ ์ •์˜ํ•˜๊ณ ,
๊ฐ Scope๋Š” ํŠน์ • ์‚ฌ์šฉ์ž ์ •๋ณด ์ง‘ํ•ฉ์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๋‚˜ํƒ€๋‚ธ๋‹ค.

Scope๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด์— ๋Œ€ํ•œ ํ‘œ์ค€ํ™”๋œ ์ ‘๊ทผ ๋ฐฉ์‹์„ ์ œ๊ณตํ•˜๋ฉฐ, ํด๋ผ์ด์–ธํŠธ๋Š” ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ์š”์ฒญํ•˜๊ณ  ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

// OAuth 2.0 ์‘๋‹ต
{
    "access_token": "eyJ0eXAi...",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "8xLOxBtZp8..."
}

// OIDC ์‘๋‹ต (OAuth 2.0 + α)
{
    "access_token": "eyJ0eXAi...",
    "token_type": "Bearer",
    "expires_in": 3600,
    "refresh_token": "8xLOxBtZp8...",
    "id_token": "eyJ0eXAiOi...",  // ์ถ”๊ฐ€๋จ!
    "scope": "openid profile email" // ํŠน๋ณ„ํ•œ scope
}

 

Scope ์‚ฌ์šฉ์˜ˆ์‹œ 1.

// Google ๋กœ๊ทธ์ธ ์š”์ฒญ ์˜ˆ์‹œ
const googleAuth = {
    scope: 'openid profile email',  // ๊ธฐ๋ณธ ์‚ฌ์šฉ์ž ์ •๋ณด๋งŒ ์š”์ฒญ
    // ...
};

// ๋ฐ›์€ ์ •๋ณด๋กœ ํšŒ์›๊ฐ€์ž…/๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ
async function handleGoogleLogin(idToken) {
    const decoded = jwt.decode(idToken);
    await createOrUpdateUser({
        email: decoded.email,
        name: decoded.name,
        picture: decoded.picture
    });
}

Scope ์‚ฌ์šฉ์˜ˆ์‹œ 2.

// ๋ฐฐ์†ก ์„œ๋น„์Šค์˜ ๊ฒฝ์šฐ
const shippingAuth = {
    scope: 'openid profile email address phone',  // ๋ฐฐ์†ก์— ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด ์š”์ฒญ
    // ...
};

// ๋ฐ›์€ ์ •๋ณด๋กœ ๋ฐฐ์†ก ์ฒ˜๋ฆฌ
async function handleShippingInfo(userInfo) {
    await createShippingOrder({
        recipient: userInfo.name,
        address: userInfo.address,
        phone: userInfo.phone_number
    });
}

 

- ID Token  JWT(JSON Web Token)

๊ฐ ํด๋ ˆ์ž„์€ ํ† ํฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ (iss, aud, exp, iat), ์‚ฌ์šฉ์ž ์‹๋ณ„ (sub), ์‚ฌ์šฉ์ž ์ •๋ณด ํ‘œ์‹œ (name, email) ๋ชฉ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค.

  • ์‚ฌ์šฉ๋ชฉ์ 
    • ์ธ์ฆ(Authentication) ๋ชฉ์ 
    • ์‚ฌ์šฉ์ž ์‹ ์› ์ฆ๋ช…
    • RP๊ฐ€ ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆํ•ด์•ผ ํ•จ
  • ์‚ฌ์šฉ๋ฒ”์œ„
    • RP์™€ OP ์‚ฌ์ด์—์„œ๋งŒ ์‚ฌ์šฉ
    • ํ‘œ์ค€ํ™”๋œ ํด๋ ˆ์ž„ ํ•„์š”
// ID Token์€ JWT(JSON Web Token) ํ˜•์‹์œผ๋กœ ๋ฐœ๊ธ‰๋˜๋ฉฐ, 
// ์‚ฌ์šฉ์ž ์ธ์ฆ ํ›„ OpenID Provider๊ฐ€ Relying Party(ํด๋ผ์ด์–ธํŠธ)์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋‹ค.
{
    // ํ•„์ˆ˜ ํด๋ ˆ์ž„
    "iss": "https://op.example.com",  // ๋ฐœ๊ธ‰์ž
    "sub": "user123",                 // ์‚ฌ์šฉ์ž ์‹๋ณ„์ž
    "aud": "client123",               // ํด๋ผ์ด์–ธํŠธ ID
    "exp": 1516239022,                // ๋งŒ๋ฃŒ ์‹œ๊ฐ„
    "iat": 1516235422,                // ๋ฐœ๊ธ‰ ์‹œ๊ฐ„

    // ์„ ํƒ์  ํด๋ ˆ์ž„
    "auth_time": 1516239022,          // ์ธ์ฆ ์‹œ๊ฐ„
    "nonce": "abc123",                // ์žฌ์ƒ ๊ณต๊ฒฉ ๋ฐฉ์ง€
    "acr": "urn:mace:incommon:iap:silver", // ์ธ์ฆ ๋ฌธ๋งฅ ํด๋ž˜์Šค
    "amr": ["pwd"],                   // ์ธ์ฆ ๋ฐฉ๋ฒ•
    "azp": "client123"                // ์ธ๊ฐ€๋œ ๋‹น์‚ฌ์ž
}

 

- Access Token

  • ์‚ฌ์šฉ๋ชฉ์ 
    • ์ธ๊ฐ€(Authorization) ๋ชฉ์ 
    • ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ ๊ถŒํ•œ ํ‘œํ˜„
    • ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„๋งˆ๋‹ค ๋‹ค๋ฅธ ์š”๊ตฌ์‚ฌํ•ญ ๊ฐ€๋Šฅ
  • ์‚ฌ์šฉ๋ฒ”์œ„
    • ๋‹ค์–‘ํ•œ ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉ
    • ๊ฐ ์„œ๋น„์Šค์— ๋งž๋Š” ์œ ์—ฐํ•œ ๊ตฌ์กฐ ํ•„์š”
// Access Token - ํฌ๋งท ์ž์œ ๋กœ์›€
// ์˜ˆ์‹œ 1: ๋ถˆํˆฌ๋ช… ํ† ํฐ
"abcd1234xyz789..."

// ์˜ˆ์‹œ 2: JWT ํ˜•์‹
{
    "sub": "user123",
    "scope": ["read", "write"],
    "exp": 1516239022
}

// ์˜ˆ์‹œ 3: ์ปค์Šคํ…€ ํฌ๋งท
{
    "userId": "user123",
    "permissions": ["admin", "user"],
    "customClaim": "value"
}

 

- ID Token VS Access Token

ID Token๊ณผ Access Token์ด ์–ด๋–ป๊ฒŒ ๋‹ค๋ฅธ์ง€, ๋ฌด์—‡์„ ์œ„ํ•ด ์‚ฌ์šฉํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ณ  ๋„˜์–ด๊ฐ€์ž.
์œ„์— OpenID Connect์˜ Authorization Code Flow ๋‹ค์ด์–ด๊ทธ๋žจ์—์„œ
7๋ฒˆ. ID Token์„ ํ†ตํ•ด์„œ ์ธ์ฆ์„ ๋ฐ›๊ณ , 8๋ฒˆ. AccessToken์„ ๊ฐ€์ง€๊ณ  userinfo๋ฅผ ์š”์ฒญํ•œ๊ฑฐ๋ผ๊ณ  ์ดํ•ดํ•  ์ˆ˜ ์žˆ๋‹ค.

  ID Token Access Token
๋ชฉ์  ์ธ์ฆ(Authentication) ์ธ๊ฐ€(Authorization)
์งˆ๋ฌธ "์ด ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฌ์ธ๊ฐ€?" "์ด ์š”์ฒญ์ด ํ—ˆ์šฉ๋˜๋Š”๊ฐ€?"
์‚ฌ์šฉ ํด๋ผ์ด์–ธํŠธ ์•ฑ์—์„œ ์ง์ ‘ ์‚ฌ์šฉ API ์š”์ฒญ ์‹œ ์‚ฌ์šฉ
ํ˜•์‹ ํ•ญ์ƒ JWT ์ž์œ ๋กœ์›€
๊ฒ€์ฆ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ฐ˜๋“œ์‹œ ๊ฒ€์ฆ ๋ฆฌ์†Œ์Šค ์„œ๋ฒ„๊ฐ€ ๊ฒ€์ฆ

 

  • ID Token 
// Access Token - ํฌ๋งท ์ž์œ ๋กœ์›€
// ์˜ˆ์‹œ 1: ๋ถˆํˆฌ๋ช… ํ† ํฐ
"abcd1234xyz789..."

// ์˜ˆ์‹œ 2: JWT ํ˜•์‹
{
    "sub": "user123",
    "scope": ["read", "write"],
    "exp": 1516239022
}

// ์˜ˆ์‹œ 3: ์ปค์Šคํ…€ ํฌ๋งท
{
    "userId": "user123",
    "permissions": ["admin", "user"],
    "customClaim": "value"
}
  • Access Token
// Access Token์€ "๋ฌด์—‡์„ ํ•  ์ˆ˜ ์žˆ๋Š”์ง€"๋ฅผ ๋‚˜ํƒ€๋ƒ„
// API ํ˜ธ์ถœ ์‹œ ์‚ฌ์šฉ
async function fetchUserData(accessToken) {
    // UserInfo ์—”๋“œํฌ์ธํŠธ ํ˜ธ์ถœ
    const response = await fetch('https://api.example.com/userinfo', {
        headers: {
            'Authorization': `Bearer ${accessToken}`
        }
    });
    
    // ๋‹ค๋ฅธ API ํ˜ธ์ถœ
    const orders = await fetch('https://api.example.com/orders', {
        headers: {
            'Authorization': `Bearer ${accessToken}`
        }
    });
}
  • ์‚ฌ์šฉ์˜ˆ์‹œ
// ----------------------------------------------------------------
// ์‚ฌ์šฉ ์‹œ๋‚˜๋ฆฌ์˜ค
class AuthService {
    async handleAuthenticationFlow(authCode) {
        // 1. ํ† ํฐ ๋ฐ›๊ธฐ
        const tokens = await fetchTokens(authCode);
        const { id_token, access_token } = tokens;
        
        // 2. ID Token์œผ๋กœ ์‚ฌ์šฉ์ž ์ธ์ฆ
        if (this.validateIdToken(id_token)) {
            // ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ
            const userData = jwt.decode(id_token);
            this.setLoggedInUser({
                id: userData.sub,
                name: userData.name
            });
        }
        
        // 3. Access Token์œผ๋กœ ์ถ”๊ฐ€ ์ •๋ณด ์š”์ฒญ
        const userDetails = await this.fetchUserDetails(access_token);
        const userOrders = await this.fetchUserOrders(access_token);
    }
}

// ----------------------------------------------------------------
// ์‹ค์ œ๊ตฌํ˜„ ์˜ˆ์‹œ

// 1. ๋กœ๊ทธ์ธ ํ›„ ๋‘ ํ† ํฐ ์ €์žฅ
function handleLoginSuccess(tokens) {
    const { id_token, access_token } = tokens;
    
    // ID Token์œผ๋กœ ์‚ฌ์šฉ์ž ์ •๋ณด ์„ค์ •
    const userInfo = jwt.decode(id_token);
    localStorage.setItem('user', JSON.stringify({
        id: userInfo.sub,
        name: userInfo.name,
        email: userInfo.email
    }));
    
    // Access Token ์ €์žฅ
    localStorage.setItem('access_token', access_token);
}

// 2. API ํ˜ธ์ถœ ์‹œ Access Token ์‚ฌ์šฉ
async function callAPI() {
    const accessToken = localStorage.getItem('access_token');
    
    try {
        const response = await fetch('https://api.example.com/data', {
            headers: {
                'Authorization': `Bearer ${accessToken}`
            }
        });
        
        return await response.json();
    } catch (error) {
        // ํ† ํฐ ๋งŒ๋ฃŒ ๋“ฑ ์ฒ˜๋ฆฌ
        handleAuthError(error);
    }
}

// 3. ์‚ฌ์šฉ์ž ์ •๋ณด ํ™•์ธ ์‹œ ID Token ์ •๋ณด ์‚ฌ์šฉ
function getCurrentUser() {
    return JSON.parse(localStorage.getItem('user'));
}

 

- KeyCloak์—์„œ AccessToken์œผ๋กœ JWT๋ฅผ ์‚ฌ์šฉ ๐Ÿ˜Ž

์ดˆ์ฐฝ๊ธฐ๋ถ€ํ„ฐ KeyCloak์€ Access Token์œผ๋กœ JWT๋ฅผ ์‚ฌ์šฉํ•ด์™”์œผ๋ฉฐ, JWT๋ฅผ ์‚ฌ์šฉํ•จ์— ๋”ฐ๋ผ ์•„๋ž˜์™€ ๊ฐ™์€ ์žฅ์ ์„ ๊ฐ€์ง€๊ฒŒ ๋˜์—ˆ๋‹ค.
(์œ„์— ์„ค๋ช…๋œ๋ฐ๋กœ AccessToken์€ ํฌ๋ฉง์— ๋Œ€ํ•œ ๊ทœ์ •์ด ์—†๋‹ค.)

JWT๋ฅผ ์ง€์›ํ•˜๋Š” OpenID Connect/OAuth 2.0 ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋Š”๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค. (๋ณด์•ˆ์ทจ์•ฝ์ ์žˆ์Œ)

// -------------------------------------------------------------------
// Access Token์œผ๋กœ ์ผ๋ฐ˜ํ† ํฐ (๋ถˆํˆฌ๋ช…ํ† ํฐ) ์‚ฌ์šฉ์‹œ
+-----------+                                     +------------------+
|  ํฌํ† ๋ถ ์•ฑ  |  ----(1) Access Token ์ „๋‹ฌ ------>   |   ๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ      |
|           |  <---(2) ํ† ํฐ ๊ฒ€์ฆ ์š”์ฒญ ----------     |   (๋ฆฌ์†Œ์Šค ์„œ๋ฒ„)     |
|           |  ----(3) ์‚ฌ์šฉ์ž ์ •๋ณด ์š”์ฒญ -------->     |                  |
|           |  <---(4) ์‹ค์ œ ๋ฆฌ์†Œ์Šค ์‘๋‹ต ---------     |                  |
+-----------+                                     +------------------+
                          |
                     +------------------+
                     |   ๊ตฌ๊ธ€ OAuth      |
                     | (์ธ์ฆ ์„œ๋ฒ„)        |
                     +------------------+
   
// ๋ถˆํˆฌ๋ช… ํ† ํฐ ์ฒ˜๋ฆฌ ๊ณผ์ • ์˜ˆ์‹œ
async function handleOpaqueToken() {
    // ์ด 3๋ฒˆ์˜ ๋„คํŠธ์›Œํฌ ์š”์ฒญ
    const steps = [
        '1. ํ† ํฐ ๊ฒ€์ฆ ์š”์ฒญ โžก๏ธ Keycloak',
        '2. UserInfo ์š”์ฒญ โžก๏ธ Keycloak',
        '3. ์‹ค์ œ ๋ฆฌ์†Œ์Šค ์ฒ˜๋ฆฌ'
    ];
    // ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ = ๋„คํŠธ์›Œํฌ ์ง€์—ฐ x 3
}


// -------------------------------------------------------------------
// Access Token์œผ๋กœ JWT ์‚ฌ์šฉ์‹œ
// JWT์— ์ด๋ฏธ ํ•„์š”ํ•œ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์–ด์„œ ์ถ”๊ฐ€ ์š”์ฒญ ์—†์ด ๋ฐ”๋กœ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ ๊ฐ€๋Šฅ
+-----------+                                     +------------------+
|  ํฌํ† ๋ถ ์•ฑ  |  ---(1) JWT Access Token ์ „๋‹ฌ--->     |   ๊ตฌ๊ธ€ ๋“œ๋ผ์ด๋ธŒ    |
|           |                                     |                 |
|           |  <---(2) ์‹ค์ œ ๋ฆฌ์†Œ์Šค ์‘๋‹ต --------      |   (๋ฆฌ์†Œ์Šค ์„œ๋ฒ„)    |
+-----------+                                     +------------------+

// JWT ์ฒ˜๋ฆฌ ๊ณผ์ •
async function handleJWT() {
    // ์ด 1๋ฒˆ์˜ ๋„คํŠธ์›Œํฌ ์š”์ฒญ
    const steps = [
        '1. JWT ๋กœ์ปฌ ๊ฒ€์ฆ (๋„คํŠธ์›Œํฌ ์š”์ฒญ ์—†์Œ)',
        '2. ๊ถŒํ•œ ํ™•์ธ (๋„คํŠธ์›Œํฌ ์š”์ฒญ ์—†์Œ)',
        '3. ์‹ค์ œ ๋ฆฌ์†Œ์Šค ์ฒ˜๋ฆฌ'
    ];
    // ์ฒ˜๋ฆฌ ์‹œ๊ฐ„ = ๋„คํŠธ์›Œํฌ ์ง€์—ฐ x 1
}
  • ์ž์ฒด ํฌํ•จ(Self-contained)
    • ํ•„์š”ํ•œ ๋ชจ๋“  ์ •๋ณด๊ฐ€ ํ† ํฐ ์•ˆ์— ํฌํ•จ
    • ์ถ”๊ฐ€ ์กฐํšŒ ๋ถˆํ•„์š”
  • ์„ฑ๋Šฅ ํ–ฅ์ƒ
    • ๋„คํŠธ์›Œํฌ ์š”์ฒญ ๊ฐ์†Œ
    • ์„œ๋ฒ„ ๋ถ€ํ•˜ ๊ฐ์†Œ
  • ํ™•์žฅ์„ฑ
    • ํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ํด๋ ˆ์ž„์œผ๋กœ ์ถ”๊ฐ€ ๊ฐ€๋Šฅ
    • ๋‹ค์–‘ํ•œ ์ธ์ฆ/์ธ๊ฐ€ ์‹œ๋‚˜๋ฆฌ์˜ค ์ง€์›

 

 

 

- ํ‘œ์ค€ ํด๋ ˆ์ž„ ์„ธํŠธ

ํด๋ ˆ์ž„(Claim)์€  ID Token์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ,
"์ฃผ์žฅ" ๋˜๋Š” "๋ช…์„ธ"๋ผ๋Š” ์˜๋ฏธ๋กœ, ์‚ฌ์šฉ์ž๋‚˜ ์—”ํ‹ฐํ‹ฐ์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํ‘œํ˜„ํ•˜๋Š” key-value ์Œ์„ ๋งํ•œ๋‹ค.

// ID Token ํ•„์ˆ˜ ํด๋ ˆ์ž„
{
    "iss": "https://auth.example.com",  // ํ† ํฐ ๋ฐœ๊ธ‰์ž
    "sub": "248289761001",             // ์‚ฌ์šฉ์ž ๊ณ ์œ  ์‹๋ณ„์ž
    "aud": "client_id",                // ํ† ํฐ ์ˆ˜์‹ ์ž
    "exp": 1516239022,                 // ๋งŒ๋ฃŒ ์‹œ๊ฐ„
    "iat": 1516239022                  // ๋ฐœ๊ธ‰ ์‹œ๊ฐ„
}

// ํ”„๋กœํ•„ ๊ด€๋ จ ํด๋ ˆ์ž„
{
    "name": "John Doe",
    "family_name": "Doe",
    "given_name": "John",
    "middle_name": "William",
    "nickname": "Johnny",
    "preferred_username": "j.doe",
    "profile": "https://example.com/profile",
    "picture": "https://example.com/photo.jpg",
    "website": "http://johndoe.com",
    "gender": "male",
    "birthdate": "1990-01-01",
    "zoneinfo": "Europe/Paris",
    "locale": "en-US",
    "updated_at": 1516239022
}

// ์ด๋ฉ”์ผ ๊ด€๋ จ ํด๋ ˆ์ž„
{
    "email": "johndoe@example.com",
    "email_verified": true             // ์ด๋ฉ”์ผ ์ธ์ฆ ์—ฌ๋ถ€
}

// ์ฃผ์†Œ ๊ด€๋ จ ํด๋ ˆ์ž„
{
    "address": {
        "street_address": "123 Main St",
        "locality": "Anytown",         // ์‹œ/๊ตฐ/๊ตฌ
        "region": "State",             // ๋„/์‹œ
        "postal_code": "12345",
        "country": "US"
    }
}

 

- ์—”๋“œํฌ์ธํŠธ ์ •์˜ (OICD/ KeyCloak)

// OpenID Configuration ์—”๋“œํฌ์ธํŠธ
GET /.well-known/openid-configuration

// ์‘๋‹ต
{
    "issuer": "https://op.example.com",
    "authorization_endpoint": "https://op.example.com/auth",
    "token_endpoint": "https://op.example.com/token",
    "userinfo_endpoint": "https://op.example.com/userinfo",
    "jwks_uri": "https://op.example.com/jwks",
    "registration_endpoint": "https://op.example.com/register",
    "scopes_supported": ["openid", "profile", "email"],
    "response_types_supported": ["code", "token", "id_token"],
    "grant_types_supported": ["authorization_code", "implicit"],
    "subject_types_supported": ["public", "pairwise"],
    "id_token_signing_alg_values_supported": ["RS256", "ES256"]
}

// Keycloak์˜ OpenID Configuration ์—”๋“œํฌ์ธํŠธ
// ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ http://localhost:8080/realms/master/.well-known/openid-configuration
// ์‹ค์ œ ํ™˜๊ฒฝ https://auth.example.com/realms/my-realm/.well-known/openid-configuration
http(s)://{keycloak-host}/realms/{realm-name}/.well-known/openid-configuration

// ์‘๋‹ต์˜ˆ์‹œ
{
    "issuer": "http://localhost:8080/realms/master",
    "authorization_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/auth",
    "token_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/token",
    "introspection_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/token/introspect",
    "userinfo_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/userinfo",
    "end_session_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/logout",
    "jwks_uri": "http://localhost:8080/realms/master/protocol/openid-connect/certs",
    "check_session_iframe": "http://localhost:8080/realms/master/protocol/openid-connect/login-status-iframe.html",
    "grant_types_supported": [
        "authorization_code",
        "implicit",
        "refresh_token",
        "password",
        "client_credentials"
    ],
    "response_types_supported": [
        "code",
        "none",
        "id_token",
        "token",
        "id_token token",
        "code id_token",
        "code token",
        "code id_token token"
    ],
    "subject_types_supported": ["public"],
    "id_token_signing_alg_values_supported": ["RS256"],
    "userinfo_signing_alg_values_supported": ["RS256"],
    "request_object_signing_alg_values_supported": ["none", "RS256"],
    "response_modes_supported": ["query", "fragment", "form_post"],
    "registration_endpoint": "http://localhost:8080/realms/master/clients-registrations/openid-connect",
    "token_endpoint_auth_methods_supported": [
        "private_key_jwt",
        "client_secret_basic",
        "client_secret_post",
        "tls_client_auth",
        "client_secret_jwt"
    ],
    "token_endpoint_auth_signing_alg_values_supported": ["RS256"],
    "claims_supported": [
        "aud",
        "sub",
        "iss",
        "auth_time",
        "name",
        "given_name",
        "family_name",
        "preferred_username",
        "email",
        "acr"
    ],
    "claim_types_supported": ["normal"],
    "claims_parameter_supported": false,
    "scopes_supported": ["openid", "offline_access", "profile", "email", "address", "phone", "roles", "web-origins"],
    "request_parameter_supported": true,
    "request_uri_parameter_supported": true,
    "require_request_uri_registration": true,
    "code_challenge_methods_supported": ["plain", "S256"],
    "tls_client_certificate_bound_access_tokens": true,
    "revocation_endpoint": "http://localhost:8080/realms/master/protocol/openid-connect/revoke",
    "backchannel_logout_supported": true,
    "backchannel_logout_session_supported": true
}

 

- OIDC์˜ ์ฃผ์š” ํ™•์žฅ ๊ธฐ๋Šฅ #1 Discovery ๐Ÿ”

OP์˜ ์—”๋“œํฌ์ธํŠธ์™€ ๊ธฐ๋Šฅ์„ ์ž๋™์œผ๋กœ ๋ฐœ๊ฒฌํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜

GET /.well-known/openid-configuration

// ์‘๋‹ต ์˜ˆ์‹œ
{
    "issuer": "https://auth.example.com",
    "authorization_endpoint": "https://auth.example.com/auth",
    "token_endpoint": "https://auth.example.com/token",
    "userinfo_endpoint": "https://auth.example.com/userinfo",
    "jwks_uri": "https://auth.example.com/jwks",
    "registration_endpoint": "https://auth.example.com/register",
    // ... ๊ธฐํƒ€ ์„ค์ •๋“ค
}

- OIDC์˜ ์ฃผ์š” ํ™•์žฅ ๊ธฐ๋Šฅ #2 Dynamic Registration ๐Ÿ“

ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋™์ ์œผ๋กœ OP์— ๋“ฑ๋กํ•˜๋Š” ๊ธฐ๋Šฅ

// ๋“ฑ๋ก ์š”์ฒญ
POST /register HTTP/1.1
{
    "application_type": "web",
    "redirect_uris": [
        "https://client.example.com/callback"
    ],
    "client_name": "My Web App",
    "logo_uri": "https://client.example.com/logo.png",
    "subject_type": "pairwise"
}

// ์‘๋‹ต
{
    "client_id": "abc123",
    "client_secret": "xyz789",
    "registration_access_token": "reg-token-123"
}

- OIDC์˜ ์ฃผ์š” ํ™•์žฅ ๊ธฐ๋Šฅ #3 Session Management ๐Ÿ”„

๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜ ์„ธ์…˜ ๊ด€๋ฆฌ
OpenID ์ œ๊ณต์ž์™€ ์ตœ์ข…์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์„ธ์…˜์„ ๋ชจ๋‹ˆํ„ฐ๋ง ํ•˜๋Š” ๋ฐฉ๋ฒ•๊ณผ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋กœ๊ทธ๊ฐ€์›ƒ ๋ฐฉ๋ฒ•์„ ์ •์˜ํ•จ

// ํด๋ผ์ด์–ธํŠธ ์ธก ๊ตฌํ˜„
class SessionManager {
    checkSession() {
        const iframe = document.createElement('iframe');
        iframe.src = 'https://op.example.com/check-session';
        
        iframe.onload = () => {
            // ์„ธ์…˜ ์ƒํƒœ ํ™•์ธ
            iframe.contentWindow.postMessage(
                { clientId: 'abc123' },
                'https://op.example.com'
            );
        };
    }
    
    handleSessionChange(event) {
        if (event.data.sessionState === 'changed') {
            // ๋กœ๊ทธ์•„์›ƒ ์ฒ˜๋ฆฌ
            this.logout();
        }
    }
}

- OIDC์˜ ์ฃผ์š” ํ™•์žฅ ๊ธฐ๋Šฅ #4 Front-channel Logout ๐Ÿšช

๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•œ ๋กœ๊ทธ์•„์›ƒ (iframe)

<!-- ๋กœ๊ทธ์•„์›ƒ iframe -->
<iframe 
    src="https://op.example.com/logout?
         client_id=abc123&
         logout_uri=https://client.example.com/logout"
    style="display:none">
</iframe>

<script>
    function handleLogout() {
        // ์—ฌ๋Ÿฌ RP์— ๋กœ๊ทธ์•„์›ƒ ์•Œ๋ฆผ
        logoutIframes.forEach(iframe => {
            iframe.src = iframe.getAttribute('logout-uri');
        });
    }
</script>

- OIDC์˜ ์ฃผ์š” ํ™•์žฅ ๊ธฐ๋Šฅ #5 Back-channel Logout ๐Ÿ”’

์„œ๋ฒ„ ๊ฐ„ ์ง์ ‘ ํ†ต์‹ ์„ ํ†ตํ•œ ๋กœ๊ทธ์•„์›ƒ

// RP์˜ ๋ฐฑ์ฑ„๋„ ๋กœ๊ทธ์•„์›ƒ ์—”๋“œํฌ์ธํŠธ
app.post('/backchannel_logout', async (req, res) => {
    const logoutToken = req.body.logout_token;
    
    try {
        // ๋กœ๊ทธ์•„์›ƒ ํ† ํฐ ๊ฒ€์ฆ
        const verified = await verifyLogoutToken(logoutToken);
        
        if (verified) {
            // ํ•ด๋‹น ์‚ฌ์šฉ์ž ์„ธ์…˜ ์ข…๋ฃŒ
            await terminateUserSession(verified.sub);
            res.status(200).send('OK');
        }
    } catch (error) {
        res.status(400).send('Invalid logout token');
    }
});

 

 

 



๐Ÿ“Œ SAML

SAML์€ ์›น ๊ธฐ๋ฐ˜์˜ Single Sign-On(SSO) ๋ฐ ์ธ์ฆ์„ ์œ„ํ•œ XML ๊ธฐ๋ฐ˜์˜ ํ‘œ์ค€์ด๋‹ค.
์ฃผ๋กœ ๊ธฐ์—… ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ๋˜๋ฉฐ, ์‚ฌ์šฉ์ž ์ธ์ฆ ์ •๋ณด๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ๊ตํ™˜ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉํ•œ๋‹ค.


- ์ฃผ์š” ๊ฐœ๋…

์ตœ์ข… ์‚ฌ์šฉ์ž 
(End User)
์‹ค์ œ ์ธ์ฆ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ์‚ฌ์šฉ์ž
์„œ๋น„์Šค ์ œ๊ณต์ž 
(Service Provider, SP)
์‚ฌ์šฉ์ž๊ฐ€ ์ ‘๊ทผํ•˜๋ ค๋Š” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋˜๋Š” ์„œ๋น„์Šค. SAML ์ธ์ฆ ์š”์ฒญ์„ ์ฒ˜๋ฆฌ (์˜ˆ, ๋กœ๊ทธ์ธํŽ˜์ด์ง€)
์•„์ด๋ดํ‹ฐํ‹ฐ ์ œ๊ณต์ž 
(Identity Provider, IdP)
์‚ฌ์šฉ์ž์˜ ์‹ ์›์„ ์ฆ๋ช…ํ•˜๊ณ  SAML ์–ด์„ค์…˜์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ์„œ๋ฒ„ (์˜ˆ: ADFS, Okta)
SAML ์–ด์„ค์…˜ 
(SAML Assertion)
์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๋Š” XML ํ˜•์‹์˜ ๋ฐ์ดํ„ฐ
SAML ํ”„๋กœํ† ์ฝœ SAML ์–ด์„ค์…˜์„ ์ „์†กํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ํ”„๋กœํ† ์ฝœ.

 

- SAML ์ธ์ฆ ํ๋ฆ„

  1. ์ตœ์ข… ์‚ฌ์šฉ์ž์˜ ์„œ๋น„์Šค ์ ‘๊ทผ: ์‚ฌ์šฉ์ž๊ฐ€ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์„œ๋น„์Šค ์ œ๊ณต์ž(SP)์˜ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผ์„ ์‹œ๋„ํ•จ
  2. SP ์ธ์ฆ ํ๋ฆ„ ์‹œ์ž‘
    - SP๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ๋˜์ง€ ์•Š์•˜์Œ์„ ํ™•์ธํ•จ
    - SP-initiated flow(SP ์‹œ์ž‘ ํ๋ฆ„)๊ฐ€ ์‹œ์ž‘๋จ
  3. SAML ์ธ์ฆ ์š”์ฒญ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ: ๐Ÿ‘ˆ <samlp:AuthnRequest> ์‚ฌ์šฉ
    SP๋Š” ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด SAML ์ธ์ฆ ์š”์ฒญ์„ IdP๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธํ•œ๋‹ค.  
  4. IdP ์ธ์ฆ ํ๋ฆ„ ์‹œ์ž‘: IdP-initiated flow(IdP ์‹œ์ž‘ ํ๋ฆ„)๊ฐ€ ์‹œ์ž‘๋œ๋‹ค.
  5. ์‚ฌ์šฉ์ž ์ธ์ฆ ๋ฐ SAML ์–ด์„ค์…˜ ์ƒ์„ฑ: ๐Ÿ‘ˆ <saml:Assertion> ์ƒ์„ฑ
    - IdP๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•˜๊ณ 
    - ์ธ์ฆ ์„ฑ๊ณต ์‹œ SAML ์–ด์„ค์…˜์„ ์ƒ์„ฑํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €๋กœ ์ „์†กํ•œ๋‹ค.
  6. SAML ์–ด์„ค์…˜ ์ „๋‹ฌ: ๐Ÿ‘ˆ <saml:Assertion> ์ „๋‹ฌ
    ๋ธŒ๋ผ์šฐ์ €๋Š” IdP๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ SAML ์–ด์„ค์…˜์„ SP๋กœ ์ „๋‹ฌํ•œ๋‹ค.
  7. ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ ์„ค์ •: SP๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ์ด ์™„๋ฃŒ๋˜๋ฉด ๋ณด์•ˆ ์ปจํ…์ŠคํŠธ๋ฅผ ๋ธŒ๋ผ์šฐ์ €๋กœ ์ „์†กํ•œ๋‹ค.
  8. ๋ฆฌ์†Œ์Šค ์š”์ฒญ: ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž๊ฐ€ SP์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•œ๋‹ค.
  9. ๋ฆฌ์†Œ์Šค ์‘๋‹ต: SP๋Š” ์š”์ฒญ๋œ ๋ฆฌ์†Œ์Šค๋กœ ์‘๋‹ตํ•œ๋‹ค.

โญ๏ธโญ๏ธโญ๏ธโญ๏ธโญ๏ธ
[Service Provider] ↔ [User's Browser] ↔ [Identity Provider]
ํŠนํžˆ SAML ์ธ์ฆ ํ๋ฆ„์—์„œ ์ค‘์š”ํ•œ ์ ์€ ๋ชจ๋“  ํ†ต์‹ ์ด ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ์ด๋ฃจ์–ด์ง€๋ฉฐ(Browser Agent),
IdP์™€ SP๋Š” ์ง์ ‘ ํ†ต์‹ ํ•˜์ง€ ์•Š๋Š”๋‹ค
๋Š” ๊ฒƒ์ด๋‹ค. (SAML Browser POST Profile ๋˜๋Š” Web Browser SSO Profile ๋ผ๊ณ ๋„ ํ•จ)
์ด๋Ÿฌํ•œ ๋ฐฉ์‹์€ ์›น ๊ธฐ๋ฐ˜ SSO(Single Sign-On)์— ํŠนํžˆ ์ ํ•ฉํ•˜๋‹ค.

 

- SAML ์ธ์ฆ์š”์ฒญ ๋ฐ ์–ด์„ค์…˜ ์ƒ˜ํ”Œ

<!-- SAML ์ธ์ฆ ์š”์ฒญ -->
# ์„œ๋น„์Šค ์ œ๊ณต์ž(SP)๊ฐ€ ์•„์ด๋ดํ‹ฐํ‹ฐ ์ œ๊ณต์ž(IdP)์—๊ฒŒ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ์„ ์š”์ฒญํ•˜๊ธฐ ์œ„ํ•ด ์ƒ์„ฑํ•˜๋Š” ๋ฉ”์‹œ์ง€
<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" 
                   ID="_123456789"
                   Version="2.0"
                   IssueInstant="2023-10-01T00:00:00Z"
                   Destination="https://idp.com/SAML2/SSO">
    <saml:Issuer>https://yourapp.com</saml:Issuer>
    <samlp:NameIDPolicy AllowCreate="true" />
</samlp:AuthnRequest>

<!-- SAML ์–ด์„ ์…œ -->
#  IdP๊ฐ€ ์‚ฌ์šฉ์ž๋ฅผ ์ธ์ฆํ•œ ํ›„, SP์—๊ฒŒ ์ „๋‹ฌํ•˜๋Š” ๋ฉ”์‹œ์ง€๋กœ, ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ํฌํ•จ
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
                ID="_123456789"
                IssueInstant="2023-10-01T00:00:00Z"
                Version="2.0">
    <saml:Issuer>https://idp.com</saml:Issuer>
    <saml:Subject>
        <saml:NameID Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified">user@example.com</saml:NameID>
        <saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
            <saml:SubjectConfirmationData NotOnOrAfter="2023-10-01T01:00:00Z"
                                          Recipient="https://yourapp.com/SAML/SSO"/>
        </saml:SubjectConfirmation>
    </saml:Subject>
    <saml:Conditions NotBefore="2023-10-01T00:00:00Z"
                     NotOnOrAfter="2023-10-01T01:00:00Z">
        <saml:AudienceRestriction>
            <saml:Audience>https://yourapp.com</saml:Audience>
        </saml:AudienceRestriction>
    </saml:Conditions>
    <saml:AuthnStatement AuthnInstant="2023-10-01T00:00:00Z">
        <saml:AuthnContext>
            <saml:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml:AuthnContextClassRef>
        </saml:AuthnContext>
    </saml:AuthnStatement>
</saml:Assertion>

 


๐Ÿ“Œ Zero Trust

"์ ˆ๋Œ€ ์‹ ๋ขฐํ•˜์ง€ ๋ง๊ณ  ํ•ญ์ƒ ๊ฒ€์ฆํ•˜๋ผ(Never Trust, Always Verify)"๋Š” ๊ฐœ๋…์ด๋‹ค.

๋„คํŠธ์›Œํฌ ๋‚ด๋ถ€์™€ ์™ธ๋ถ€ ๋ชจ๋“  ์‚ฌ์šฉ์ž์™€ ์žฅ์น˜์— ๋Œ€ํ•ด ํ•ญ์ƒ ์‹ ๋ขฐ๋ฅผ ์žฌ๊ฒ€์ฆํ•˜๊ณ  ์ธ์ฆํ•˜๋ฉฐ(์ ‘๊ทผ๊ฒ€์ฆ), 
์‚ฌ์šฉ์ž์™€ ์žฅ์น˜๊ฐ€ ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ๊ถŒํ•œ๋งŒ ๋ถ€์—ฌํ•˜๊ณ (์ตœ์†Œ๊ถŒํ•œ์ ‘๊ทผ์ œ์–ด),
๋ชจ๋“  ์•ก์„ธ์Šค์™€ ์ž‘์—…์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๊ณ  ๋กœ๊น…ํ•˜์—ฌ ์ด์ƒ์ง•ํ›„๋ฅผ ๋ถ„์„ํ•˜๊ณ  ๋Œ€์‘ํ•œ๋‹ค.

- ๊ธฐ์กด ๋ณด์•ˆ๊ณผ ๋ญ๊ฐ€ ๋‹ค๋ฅธ๊ฐ€?

๊ธฐ์กด ๋ณด์•ˆ๋ชจ๋ธ์—์„œ๋Š” ๋‚ด๋ถ€ ๋„คํŠธ์›Œํฌ๋Š” ์‹ ๋ขฐํ•œ๋‹ค๋Š” ๊ฐ€์ •์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ์œผ๋ฉฐ, ์™ธ๋ถ€์—์„œ๋ถ€ํ„ฐ ์ ‘๊ทผํ•˜๋Š” ์‚ฌ์šฉ์ž๋ฐ ์žฅ์น˜์— ๋Œ€ํ•œ ๋ณด์•ˆ์— ์ง‘์ค‘๋˜์–ด์žˆ๋‹ค. 
Zero Trust๋Š” ๋„คํŠธ์›Œํฌ ๋‚ด๋ถ€์™€ ์™ธ๋ถ€์˜ ๊ตฌ๋ถ„์„ ์—†์• ๊ณ , ๋ชจ๋“  ์ ‘๊ทผ์„ ์ง€์†์ ์œผ๋กœ ํ‰๊ฐ€ํ•˜๊ณ  ๊ฒ€์ฆํ•˜๋Š” ๊ฐœ๋…์ด๋‹ค.

- ๊ธฐ์กด ๋ณด์•ˆ๋ชจ๋ธ vs Zelo Trust 

๊ธฐ์ค€ ๊ธฐ์กด ๋ณด์•ˆ ๋ชจ๋ธ Zero Trust(Zelo Trust)
๋ณด์•ˆ ๊ฒฝ๊ณ„ ๋‚ด๋ถ€์™€ ์™ธ๋ถ€๋กœ ๋ช…ํ™•ํ•˜๊ฒŒ ๊ตฌ๋ถ„ ๊ฒฝ๊ณ„๊ฐ€ ์—†์œผ๋ฉฐ ๋ชจ๋“  ์ ‘๊ทผ์„ ๊ฒ€์ฆ
๋‚ด๋ถ€ ์‹ ๋ขฐ ์ˆ˜์ค€ ๋‚ด๋ถ€ ๋„คํŠธ์›Œํฌ๋Š” ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์Œ ๋‚ด๋ถ€ ๋„คํŠธ์›Œํฌ๋„ ์‹ ๋ขฐํ•˜์ง€ ์•Š์Œ
์ ‘๊ทผ ์ œ์–ด ๋„คํŠธ์›Œํฌ ๊ธฐ๋ฐ˜(๋ฐฉํ™”๋ฒฝ, VPN) ์‚ฌ์šฉ์ž, ์žฅ์น˜, ์ปจํ…์ŠคํŠธ ๊ธฐ๋ฐ˜ ์ ‘๊ทผ ์ œ์–ด, ์ •์ฑ…๊ธฐ๋ฐ˜
์ธ์ฆ ์ ˆ์ฐจ ์ดˆ๊ธฐ ์ธ์ฆ๋งŒ ์š”๊ตฌ ์ง€์†์ ์ธ ์ธ์ฆ ๋ฐ ์ •์ฑ… ํ‰๊ฐ€
์œ„ํ˜‘ ํƒ์ง€ ์ฃผ๋กœ ์™ธ๋ถ€ ์œ„ํ˜‘ ํƒ์ง€์— ์ง‘์ค‘ ๋‚ด๋ถ€ ๋ฐ ์™ธ๋ถ€ ์œ„ํ˜‘์„ ๋ชจ๋‘ ์ง€์†์ ์œผ๋กœ ๋ชจ๋‹ˆํ„ฐ๋ง
๊ตฌํ˜„์˜ˆ์‹œ Firewall, VPN, IDS/IPS Keycloak๊ณผ AWS SSO์™€ ๊ฐ™์€ IAM ์†”๋ฃจ์…˜

์ฆ‰, ๊ธฐ์กด ๋ณด์•ˆ ๋ชจ๋ธ์€ ๋‚ด๋ถ€ ๋„คํŠธ์›Œํฌ์˜ ์‹ ๋ขฐ๋ฅผ ์ „์ œ๋กœ ํ•˜๊ณ , ์™ธ๋ถ€์—์„œ์˜ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•˜๋Š” ๋ฐ ์ค‘์ ์„ ๋‘”๋‹ค.
Zero Trust(Zelo Trust)๋Š” ๋‚ด๋ถ€์™€ ์™ธ๋ถ€๋ฅผ ๊ตฌ๋ถ„ํ•˜์ง€ ์•Š๊ณ , ๋ชจ๋“  ์ ‘๊ทผ ์š”์ฒญ์„ ์ง€์†์ ์œผ๋กœ ๊ฒ€์ฆํ•˜๊ณ  ์ตœ์†Œ ๊ถŒํ•œ ์ ‘๊ทผ์„ ์›์น™์œผ๋กœ ํ•œ๋‹ค. 

728x90