본문 바로가기

DevOps/Keycloak

[Keycloak]개요

설명

Keycloak은 오픈소스 아이덴티티 및 액세스 관리(IAM) 솔루션으로, OAuth 2.0, OpenID Connect, SAML과 같은 표준 프로토콜을 지원합니다. 이를 통해 인증(Authentication), 권한 부여(Authorization), 사용자 관리(User Management)를 간소화하며, 싱글 사인온(SSO), 소셜 로그인, 사용자 디렉토리 통합 등의 강력한 기능을 제공합니다.

주요 용어

  • Realm: Keycloak에서 다중 테넌시 환경을 구현하는 논리적 단위로, 각 Realm은 독립적인 인증 및 권한 부여 정책을 가집니다.
  • Client: Keycloak이 보호하는 애플리케이션이나 서비스로, OAuth 2.0에서의 클라이언트와 유사합니다.
  • User Federation: 외부 디렉토리 서비스(e.g., LDAP, Active Directory)와 Keycloak을 통합하는 기능입니다.
  • Identity Provider (IdP): 외부 인증 소스로, 이를 통해 소셜 로그인 또는 외부 인증 연동이 가능합니다.
  • Admin Console: Keycloak 설정과 관리를 위한 웹 기반 UI입니다.
  • Access Token: 사용자가 클라이언트에 인증된 후 부여받는 토큰으로, API 호출 시 인증 정보를 전달합니다.

핵심 개념

  1. 싱글 사인온(SSO):
    • 사용자가 한 번의 로그인으로 여러 애플리케이션에 접근할 수 있습니다.
    • OAuth 2.0과 OpenID Connect를 통해 구현됩니다.
  2. 멀티-테넌시 지원:
    • 각 Realm은 고유한 사용자, 클라이언트, 인증 정책을 가지며 완전히 분리된 환경을 제공합니다.
    • 예: 개발 환경과 프로덕션 환경을 별도의 Realm으로 분리해 관리.
  3. 확장 가능성:
    • 사용자 정의 테마와 플러그인을 통해 다양한 요구사항을 지원합니다.
  4. 표준 준수:
    • OAuth 2.0, OpenID Connect, SAML 2.0과 같은 인증/권한 부여 표준을 준수합니다.

작동 방식

  1. 사용자가 클라이언트 애플리케이션에 접속합니다.
  2. 클라이언트는 사용자를 Keycloak으로 리디렉션합니다.
  3. Keycloak에서 사용자를 인증하고 Access Token을 발급합니다.
  4. 클라이언트는 Access Token을 사용해 API 호출 시 인증 정보를 전달합니다.
  5. Keycloak이 토큰의 유효성을 검증하고 요청을 처리합니다.

사용 예시

SSO를 활용한 인증 구현

  1. Keycloak에서 새로운 Realm을 생성합니다.
  2. 클라이언트를 등록하고 리디렉션 URI를 설정합니다.
  3. 클라이언트 코드에서 OpenID Connect 라이브러리를 활용해 인증 로직을 구현합니다.
  4. Access Token을 활용해 사용자 정보를 보호된 리소스에서 조회합니다.
# Python example using requests library
import requests

# Token request
response = requests.post(
    "https://<keycloak-server>/realms/<realm>/protocol/openid-connect/token",
    data={
        "client_id": "<client_id>",
        "client_secret": "<client_secret>",
        "grant_type": "password",
        "username": "<username>",
        "password": "<password>"
    }
)
token = response.json().get("access_token")

# Access protected resource
headers = {"Authorization": f"Bearer {token}"}
protected_response = requests.get(
    "https://<protected-api>/resource",
    headers=headers
)
print(protected_response.json())