티스토리 뷰

WEB

Keycloak 시작하기 2

마시멜로co. 2025. 1. 23. 10:33

1. OAuth 2.0 을 이용한 접근 권한 인가

OAuth2.0은 현재 널리 사용되는 업계 표준 프로토콜입니다. OAuth2.0의 핵심은 전체 웹 사이트 생태계를 서로 통합할 수 있는 OAuth2.0 프레임워크가 위치합니다. OAuth2.0을 사용하면 서드파티 어플리케이션과 사용자 데이터를 쉽게 공유하고, 사용자 자격증명을 공유할 필요가 없으며 공유할 데이터를 제어할 수 있습니다.

 

OAuth2.0은 서드파티 애플리케이션을 제어하는 것 외에도 자체 애플리케이션에 대한 접근 제한에도 매우 유용합니다. 

서드파티 애플리케이션이 다른 사이트에서 사용자 이름과 패스워드를 요청하는 것이 일반적인 것처럼 기업 내부에서도 이는 일반적인 패턴이었습니다. 예를 들어 LDAP 사용자 이름과 패스워드를 요청하고 기업 내부의 다른 서비스에 접근하기 위해 해당 자격증명을 사용합니다.즉 하나의 애플리케이션이 보안 위험에 노출되면 기업 내부의 모든 서비스 또한 위협에 노출될 수 있음을 의마합니다. 

 

OAuth2.0에는 다음과 같은 롤이 있습니다.

- 리소스 오너 (Resource Owner) : 일반적으로 애플리케이션이 접근하고자 하는 리소스를 소유한 최종 소유자.

- 리소스 서버 (Resource Server) : 보호된 자원을 소유한 서비스.

- 클라이언트(Client) : 리소스에 접근하는 애플리케이션

- 인가 서버 ( Authorization Server) : 클라이언트에게 접근 권한을 발급하는 서버이며 Keycloak이 해당 역할을 수행함.

 

기본적으로 OAuth2.0 프로토콜 흐름에서 클라이언트는 인가 서버에서 리소스 오너를 대신해 리소스에 대한 접근을 요청합니다. 인가 서버는 리소스에 대한 제한된 접근 권한을 가진 접근 토콜을 발급합니다. 접근 토큰을 획특한 후 , 클라이언트는 요청에 접근 토큰을 포함해 리소스 서버에 있는 리소스에 접근 할 수 있습니다.

 

애플리케이션 유형 및 사용자 활용 사례에 따라, 사용 가능한 여러가지 흐름이 존재합니다. 적절한 애플리케이션 흐름 유형을 선택하기 위해 다음과 같은 공식을 사용할 수 있습니다.

- 애플리케이션 자체적으로 리소스에 접근하는 경우( 애플리케이션이 리소스 오너의 경우) Client Credentials flows를 사용

- 애플리케이션이 브라우저가 없는 장치에서 실행 중이거나 입력이 제한된 경우 Device flow를 사용 (ex, 스마트TV)

- 그 밖의 경우에는 Authorizaion Code flow를 사용

- Implicit flow : 네이티브 애플리케이션 및 클라이언트 사이드 애플리케이션을 위해 간소화된 흐름 (안전하지 않아 현재 사용하지 않음)

- Resource Owner Password Credentials flow :  애플리케이션 사용자의 자격증명을 직접 수집하고, 해당 자격증명을 접근 토큰과 교환함. (현재 사용하지 않음)

 

[OAuth2.0 간소화된 인가 코드 승인]

 

① 애플리케이션은 인가 요청을 처리하고, 사용자의 브라우저를 Keycloak으로 리다이렉트시킵니다.

② 사용자의 브라우저는 사용자를 인가 엔드 포인트라는 Keycloak엔드포인트로 리다이렉트합니다.

③ 사용자가 Keycloak을 통해 인증되지 않은 경우, Keycloak이 사용자를 인증합니다. 인증이 완료된 후 Keycloak은 사용자를 대신해 애플리케이션이 서비스에 접근 할 수 있도록 하기 위해 사용자의 동의를 요청합니다.

④ 애플리케이션은 인가 응답에서 인가 코드를 Keycloak으로부터 수신합니다.

⑤ 애플리케이션은 Keycloak의 토큰 엔드포인트에 대한 접근 토큰 요청을 통해 인가 코드를 접근 토큰으로 교환합니다.

⑥ 이제 애플리케이션은 보호된 리소스를 호출하기 위해 접근 토큰을 사용합니다.

 

OAuth2.0 흐름에는 기밀 및 공용 클라이언트 흐름이 존재합니다. 기밀 클라이언트는 인가 서버를 인증하기 위한 자격증명을 안전하게 저장할 수 있는 서버 사이드 애플리케이션입니다.

공용 클라이언트는 자격증명을 안전하게 저장할 수 없는 클라이언트 사이드 애플리케이션입니다. 공용 클라이언트 인가 서버를 인증할 수 없기 때문에 다음과 같은 2가지 보안을 수행합니다.

- 인가 서버는 사전 등록된 리다이렉트 URL을 가진 애플리케이션에 인가코드를 전송합니다.

- OAuth2.0의 확장 기능인 Proof key for Code Exchange는 노출된 인가 코드를 접근 토큰으로 교환되지 않도록 합니다.

 

접근 토큰은 애플리케이션에서 서비스로 전달되기 때문에 일반적으로 짧은 수명을 가집니다. 전체 흐름을 수행하지 않고 애플리케이션이 신규 접근 토큰을 사용하려면 리프레시 토큰을 사용합니다.

 

OAuth2.0핵심 프레임워크 외에도 추가적으로 알아둬야할 사양이 있습니다.

- Bearer Tokens(RFC 6750)  : OAuth2.0은 접근 토큰 유형이나 사용 방법에 대해 정의돼 있지않습니다. Bearer 토큰은 현재 가장 일반적으로 사용되는 접근 토큰 유형이며 일반적으로 HTTP인가 헤더를 통해 리소스 서버로 전송됩니다. 또한 인코딩 처리된(form-endocded) 페이로드(body), 또는 쿼리 파라미터로 전달됩니다. 여기서 주의해야할 점은 Bearer 토큰을 쿼리 파라미터로 전송되는 것은 그 자체로 보얀취약점이기 때문에 사용하지 말아야합니다.

- Token Introspection(RFC 7662) : OAuth2.0 접근 토큰의 내용은 애플리케이션에 노출되지 않습니다. 따라서 애플리케이션은 접근 토큰의 내용을 알 수 없습니다. 클라이언트는 토큰 점검 엔드포인트(token introspection endpoint)를 통해 접근 토큰의 형식을 이해하지 않고로 접근 토큰에 대한 정보를 얻을 수 있습니다. 

- Token Revocation(RFC 7009) : OAuth2.0은 접근 토큰을 애플리케이션에서 발급하는 방법을 고려하지만 취소하는 방법은 고려하지 않습니다.

 

또한 OAuth2.0사용방법에 대한 다양한 베스트 프랙티스가 존재합니다. 보안 고려 사항과 베스트 프랙티스를 포함해 네이티브 애플리케이션, 브라우저 기반 애플리케이션에 대한 권장 사항도 있습니다. 

OAuth2.0은 리소스에 접근 권한을 부여할 수 있지만, 사용자 인증을 수행하지 않습니다. 인증은 OpenID Connect라는 OAuth2.0확장에서 수행됩니다.

 

2. OpenID Connect를 통한 사용자 인증

OAuth2.0은 인가 프로토콜이기 때문에 인증을 수행하지 않습니다. 인증을 수행하기 위해 OpenID Connect가 OAuth2.0과 함께 사용됩니다.

OpenID Connect의 핵심은 OpenID Connect Core specification이며, 전체 웹사이트 생태계에서 더이상 사용자 관리 및 사용자 인증을 처리하지 않도록 만들었습니다. 또한 사용자 인증을 수행하는 횟수와 사용자가 기억해야 하는 다양한 패스워드의 개수, 즉 사용자가 접근하는 모든 웹사이트에 필요한 패스워드 관리 부담을 감소시켰습니다.

구글 또는 기타 소셜 네트워크를 사용해 로그인할 수 있는 수많은 웹사이트들이 존재합니다. OpenID Connect를 구현하는 대신 OAuth2.0을 상황에 맞게 수정해야 사용하는 일부 웹사이트들과 비교할 때 구글은 구글 로그인하기 기능을 아주 쉽게 추가할 수 있는 OpenID Connect를 제대로 구현하고 있기 때문에 다른 소셜 네트워크보다 구글을 강조하고자 합니다.

OpenID Connect는 소셜 로그인 기능뿐만 아니라 싱글 사인온 기능을 지원하는 통합 인증 솔루션을 구축하고자 하는 기업에게도 매우 유용합니다. 도한 애플리케이션이 사용자 자격증명에 직접 접근할수 없기때문에 보안을 크게 향상 시킬 수 있으며, 애플리케이션에 추가적인 설정을 하지 않고도 OTP 또는 WebAuthn과 같은 강력한 인증을 사용할 수 있습니다.

 

OpenID Connect는 기업의 인증 도입을 용이하게 할 뿐만 아니라 파트너 회사의 직원과 같은 제3자가 기업 내에서 개별 계정을 생성하지 않고도 애플리케이션에 접근할 수 있도록 합니다. OAuth2.0과 마찬가지로 OpenID Connect 또한 프로토콜과 관련된 다양한 역할이 정의돼 있습니다.

- 최종 사용자 (End User) : OAuth2.0의 리소스 오너에 해당되며 사용자를 인증함

- Relying Party(RP) : 사용자의 ID를 인증하는 OpenID Connect Provider를 신뢰하기 때문에 신뢰자(Relying Party)라고 합니다.

- OpenID Provider(OP) : 사용자를 인증하는 ID 제공자이며, keycloak이 해당 역할을 수행합니다.

 

기본적으로 OpenID Connect 프로토콜 흐름에서 신뢰자는 OpenID Provider가 인증한 사용자의 ID를 요청합니다. OAuth2.0과 연동돼 있기 때문에 사용자의 ID를 요청함과 동시에 접근 토큰을 획득할 수 있습니다.

OpenID Connect는 OAuth2.0인가 인가 코드(Authorization Code)승인 유형을 사용합니다. 주요 차이점은 클라이언트의 초기 요청에 scope = openid가 포함되며 인가 요청이 아닌 인증 요청을 생성하는 것입니다.

OAuth2.0은 서로 다른 흐름 승인 유형을 요청하지만 OpenID Connect에서 해당 요청들을 흐름으로 처리합니다. OpenID Connect에는 알고 있어야 하는 2개의 흐름이 존재합니다. 

 - 인가 코드 흐름 : OAuth2.0 인가 코드 승인 요청과 동일한 흐름을 사용하고 OAuth2.0과 같은 인가 코드를 반환합니다. 해당 인가 코드는 ID 토큰 , 접근 토큰 그리고 리프레시 토큰과 교환 할 수 있습니다.

- 하이브리드 흐름 : 하이브리드 흐름에서 ID 토큰은 인증코드와 함께 초기 요청에서 반환됩니다.

 

OAuth2.0과 마찬가지로 OpenID Connect 또한 암시적 흐름(Implicit flow)을 정의합니다. 하지만 암시적 흐름 사용을 권장하지 않습니다. OpenID Connect 클라이언트 자격증명 흐름 및 장치 흐름에 해당하는것은 정의하지 않습니다. 해당 흐름은 사용자를 인증할 필요가 없으므로 서비스에 대한 접근 권한만 부여하면 됩니다. 

OpenID Connect의 인가 코드 흐름에 익숙하지 않은 경우 , 다음 다이어그램을 통해 코드흐름의 동작 방식을 이해할 수 있습니다.

 

[간소화된 OpenID Connect 인가 코드 흐름]

 

 

① 애플리케이션은 인가 요청을 생성하고 사용자의 브라우저를 Keycloak으로 리다이렉트시킵니다.

② 사용자의 브라우저는 사용자를 Keycloak의 인가 엔드포인트로 리다이렉트시킵니다.

③ 사용자가 Keycloak에 인증되지 않은 경우 , Keycloak은 사용자를 인증합니다.

④ 애플리케이션은 Keycloak의 인가 응답으로부터 인가 코드를 수신합니다.

⑤ 애플리케이션은 Keycloak의 토큰 엔드포인트에 대한 토큰 요청을 통해 인가 코드를 ID 토큰 및 접근 토큰으로 교환합니다.

⑥ 애플리케이션은 사용자의 ID를 검증할 수 있는 ID 토큰을 가지고 사용자와 인증된 세션을 수립합니다.

 

OpenID Connect Core 명세 외에도 알아야 할 몇가지 추가 명세가 있습니다.

- Discovery : 클라이언트가 OpenID 제공자에 대한 정보를 동적으로 검색합니다.

- Dynamic Registration : 클라이언트가 OpenID 제공자에 동적으로 자신을 등록합니다.

- Session Management : OpenID 제공자와 최종 사용자의 인증 세션을 모니터링 하는 방법과 클라이언트가 로그아웃 방법을 정의합니다.

- Front-Channel Logout : 임베디드 iframe을 사용해 여러 애플리케이션의 싱글 사인아웃 매커니즘을 제공합니다.

- Back-Channel Logout : back-channel 요청 매커니즘을 사용해 여러 애플리케이션에 대한 단일 로그아웃 매커니즘을 정의합니다. 

 

OpenID Connect는 OAuth2.0외의 2개의 추가적인 개념을 가집니다. 해당 개념은 OAuth2.0의 접근 토큰과 달리 모호하지않은 JWT 명세를 활용해 ID 토큰의 형식을 명확하게 정의합니다.

해당 개념은 포맷이 잘 정의돼 있으며, 토큰에 포함된 값은 클라이언트가 직접 확인할 수 있습니다. 이것을 통해 클라이언트는 인증된 사용자에 대한 정보를 일반적인 방법으로 검색할 수 있습니다. 또한 접근 토큰으로 호출할 수 있는 userinfo endpoint를 정의하며, ID 토큰에 포함된 것과 동일한 표준 클레임을 반환합니다. 

높은 보안 수준이 필요한 활용 사례에 경우 Financial-grade API 워킹 그룹이라고 하는 프로파일 집합이 있다. 해당 프로파일은 OpenID Connect 및 관련 명세를 고위험 시나리오에서 사용하는 방법에 대한 베스트 프랙티스를 설명합니다.

지금까지 OpenID Connect에 대한 기본적인 동작 방식과 애플리케이션에 적용하는 방법을 알아봤습니다.

OpenID Connect 토큰에 대한 표준 포맷을 정의하지만 접근 토큰은 정의하지 않습니다. Keycloak에서 왜 JWT를 디폴트 접근 토큰으로 사용하지 않는지 알아보겠습니다.

 

3. JWT를 토큰으로 활용

프로젝트 초창기 때부터 Keycloak은 접근 토큰 포맷으로 JWT를 사용해왔습니다. 성능과 호환성을 고려한 결정입니다.

비교적 쉽게 사용할 수있는 표준형식을 사용해 해당 포맷이 Keycloak과 유연하게 통합될 수 있도록 했습니다. JWT는 JSON기반이기 때문에, 모든 프로그래밍 언어에서 쉽게 파싱할 수 있고 이해할 수 있습니다.

또한 리소스 서버는 이제 접근 토큰의 값을 직접 읽을 수 있으므로 OAuth2.0 토큰 검사 엔드포인트 또는 OpenID Connect Userinfo 엔드포인트에 해당 요청을 전송할 필요가 없습니다. 따라서 Keycloak의 리소스 서버 요청에 대한 2개의 추가적인 요청을 하지 않아도 되며, 지연 시간이 단축될뿐만 아니라 Keycloak에 대한 요청 개수가 크게 감소합니다.

JWT JOSE 제품군에 속하며, JWT는 Javascript Object Sigining And Encryption의 약자입니다.

관련 명세는 다음과 같습니다.

- JSON WEB Token(JWT, RFC 7519) : 점 dot, 헤더 및 클레임 집합으로 구분된 2개의 base64url-encoded JSON 문서로 구성

- JSON WEB Signature(JWT, RFC 7515) : 헤더 및 클레임의 디지털 시그니처 추가

- JSON WEB Encryption(JWT, RFC 7516): 클레임 암호화

- JSON WEB Algorithms(JWT, RFC 7518) : JWS 및 JWE에서 사용할 암호화 알고리즘 정의

- JSON WEB Key(JWT, RFC 7517) : 암호화 키를 JSON 형식으로 나타내는 형식 정의

 

위의 명세 외에도 OpenID Connect Discovery 엔드포인트는 JWKS(JSON Web Key Set)를 검색할 수 있는 엔드포인트와 JWA 명세에서 지원하는 서명 및 암호화 메커니즘을 포함합니다.

리소스 서버가 접근 토큰을 수신하면 다음과 같은 방법으로 토큰을 검증합니다.

- OpenID Connect Discovery 엔드포인트에서 JWKS URL을 검색합니다.

- JWKS URL 엔드포인트에서 OpenID 제공자에 대한 공개 서명 키 public signing key를 다운로드합니다. 해당 키는 일반적으로 리소스 서버에 캐시/저장됩니다.

- OpenID 제공자의 공개 서명키를 사용해 토큰의 서명을 검증합니다.

 

JWT를 검증할 때 JWT 명세에 몇 가지 잠재적인 문제로 보안을 적절히 수행하지 않은 경우 예기치 못한 취약점이 발생할 수 있습니다. 해당 명세를 잘못 적용해 발생할 수 있는 두가지 취약점은 다음과 같습니다. 

- alg=none : JWS 명세에서 알고리즘 값을 none으로 설정 할 수 있습니다. 해당 값의 의미는 기본적으로 JWS가 서명되지 않았음을 의미합니다. 해당 값은 정상적인 값이기 떄문에 JWT 라이브러리는 JWS가 실제로 서명되지 않더라도 해당값을 유효하다고 인식합니다.

- RSA to HMAC : 잘 알려진 또 다른 이슈는 공용 RSA 키를 사용하지만 알고리즘을 HMAC으로 설정하는 것입니다. 몇몇 라이브러리는 공개 RSA 키를 선택해 HMAC을 비밀키로 사용하기 때문에 이러한 유형의 토큰을 검증 없이 사용합니다.

 

해당 유형의 취약점은 다음과 같은 방법으로 회피할 수 있습니다.

- alg=none을 처리하지 않습니다.

- 알고리즘과 필요한 경우에만 키를 사용하고, JWT 헤더의 값을 무조건 신뢰하지 않습니다.

 

일반적으로 신뢰할 수 있는 JWT 라이브러리를 선택해 적절한 방법을 사용해야 합니다.

접근 토큰으로 JWT를 지원하는 OpneID Connect/OAuth2.0 라이브러리를 사용하는 것을 가장 권장합니다. 위의 두가지 방법을 모두 사용할 수 없는 경우 토큰의 유효성을 직접 확인하는 것보다 토큰 점검 엔드포인트를 사용하는 것이 더욱 안정적인 방법입니다.

 

4. SAML2.0 이란?

SAML2.0(Security Assertion Markup Language2.0) 은 성숙하고 신뢰할 수 있는 인증 및 인가 프로토콜입니다. 해당 프로토콜은 기업 내부 및 교육 , 정부기관의 싱글사인온을 구현하기 위해 널리 사용됩니다. 

SAML2.0은 기존 사용자를 신규 배포하는 애플리케이션에서 인증을 수행할 수 있게 해주는 것과 같이 기업 애플리케이션에서 매우 다양하게 활용됩니다.  자체 호스팅 애플리케이션을 포함해 세일즈포스,구글앱스,오피스365와 같은 여러 SaaS(Software as  a Service) 솔루션에서도 활용될 수 있습니다. 기업 입장에서는 클라우드에서 호스팅되는 솔루션을 선택할 때 각 직원에 대한 계정을 생성할 필요없이 모든 직원이 해당 솔루션에 신속하게 접근할수 있도록 해주는 옵션입니다.

SAML2.0이 좀 더 신뢰성 있고 더 널리 사용되곤 있지만, 신규 애플리케이션의 경우 SAML2.0보다 OpenID Connect를 사용하는 것을 더 선호할 수 있습니다. OpenID Connect는 단일 페이지 애플리케이션, 모바일 애플리케이션, REST API 및 마이크로서비스와 같은 최신 아키텍처에 좀 더 중점을 두고 있기 떄문에 추후 활용에 더욱 적합합니다. 개발자는 또한 OpenID Connect가 JSON 및 간소화된 쿼리 파라미터를 활용하는 반면, SAML2.0은 더 복잡한 XML 문서를 사용하기 떄문에 OpenID Connect가 더 이해하기 쉬움을 알게 될 것입니다.

OAuth2.0, OpenID Connect, SAML2.0의 세부 사항에 익숙하지 않은 경우 OAuth2.0 및 OpenID Connect 학습부터 하는것을 권장합니다.

Keycloak의 가장 큰 장점은 두가지 옵션을 모두 사용할 수 있다는 것입니다. 또한 동일 싱글사인온 환경에서 OpenID Connect를 사용하는 경우와 SAML2.0을 사용하는 애플리케이션을 원활하게 통합할 수 있습니다.

 

'WEB' 카테고리의 다른 글

Keycloak 시작하기 3  (0) 2025.02.03
Keycloak 시작하기 1  (0) 2025.01.21
vis.js 네트워크 라이브러리 및 샘플코드 다운로드  (0) 2024.09.27
[PWA] Vue.js + Express + MySQL 연동 2  (12) 2021.01.06
[PWA] Vue.js + Express + MySQL 연동 1  (10) 2021.01.05
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크