-
Ory 스택 완전 가이드: 오픈소스 인증/인가 시스템실제 경험과 인사이트를 AI와 함께 정리한 글 2025. 12. 18. 12:27
작성일: 2025년 12월 18일
카테고리: Authentication, Authorization, Security
키워드: Ory, Kratos, Hydra, Oathkeeper, Keto, OAuth2, OIDC, Identity요약
Ory는 4개의 독립적인 오픈소스 컴포넌트(Kratos, Hydra, Oathkeeper, Keto)로 구성된 인증/인가 시스템이다. 각 컴포넌트는 단일 책임 원칙을 따르며, 필요한 것만 선택적으로 사용할 수 있다. Kratos는 사용자 인증, Hydra는 OAuth2 토큰 발급, Oathkeeper는 API 인증 프록시, Keto는 권한 관리를 담당한다. 이 글에서는 각 컴포넌트의 역할과 동작 방식, 그리고 실전 적용 방법을 다룬다.
왜 Ory인가?
인증/인가 시스템을 구축할 때 세 가지 선택지가 있다:
방식 장점 단점 직접 구현 완전한 커스터마이징 보안 취약점 위험, 유지보수 비용 올인원 솔루션 (Auth0, Keycloak) 빠른 도입 벤더 종속, 커스터마이징 한계 마이크로서비스 조합 (Ory) 필요한 것만 선택, 확장성 초기 학습 곡선 Ory를 선택해야 하는 이유:
선택 이유 설명 오픈소스 Apache 2.0 라이선스 모듈러 설계 필요한 컴포넌트만 선택 사용 Cloud Native Kubernetes 친화적 설계 보안 검증 CNCF 프로젝트, 보안 감사 완료 Ory vs 올인원 솔루션
특성 Ory Keycloak Auth0 라이선스 Apache 2.0 Apache 2.0 상용 배포 방식 컴포넌트별 모놀리식 SaaS 메모리 사용 가벼움 (Go) 무거움 (Java) N/A 커스터마이징 API 기반 Admin UI 제한적 OAuth2/OIDC Hydra (별도) 내장 내장 Ory 생태계
Ory는 4개의 핵심 컴포넌트로 구성된다:
flowchart TB subgraph ory["Ory 4대 컴포넌트"] K["Kratos"] H["Hydra"] O["Oathkeeper"] E["Keto"] end K -.->|세션| O H -.->|토큰| O E -.->|권한| O style K stroke:#16a34a,stroke-width:2px style H stroke:#dc2626,stroke-width:2px style O stroke:#2563eb,stroke-width:2px style E stroke:#a855f7,stroke-width:2px컴포넌트 역할 비유 Kratos "너 누구야?" 신분증 발급 창구 Hydra "토큰 발급해줄게" 출입증 발급기 Oathkeeper "출입증 확인합니다" 경비실 Keto "이 권한 있어?" 권한 관리 시스템 Ory의 각 컴포넌트는 하나의 역할만 담당한다. 이 단일 책임 원칙 덕분에 필요한 것만 선택적으로 사용할 수 있다.
Kratos: Identity Management
왜 별도의 Identity 서비스가 필요한가?
로그인/회원가입을 직접 구현할 때 고려해야 할 것:
직접 구현 시 고려사항 위험 비밀번호 암호화 (bcrypt, argon2) 잘못하면 평문 노출 세션 관리, CSRF 토큰 보안 취약점 비밀번호 재설정 플로우 이메일 인증 연동 MFA (2단계 인증) 복잡한 구현 Kratos는 이런 사용자 신원(Identity) 관리를 전담한다.
핵심 기능
Self-Service Flows Identity Data Registration Identity Login Session Password Recovery Schema Verification Settings Kratos가 하는 일 vs 하지 않는 일
Kratos가 하는 일 Kratos가 하지 않는 일 사용자 등록/로그인 UI 렌더링 세션 관리 OAuth2 토큰 발급 비밀번호 암호화 API 인가 이메일 인증 권한 관리 MFA (2FA) 외부 서비스 연동 Self-Service Flows
Kratos는 Headless 아키텍처다. UI가 없고 API만 제공한다.
Headless란? 머리(UI)가 없다는 뜻이다. 일반적인 인증 서비스는 로그인 화면까지 제공하지만, Kratos는 API만 제공하고 화면은 직접 구현한다. 덕분에 브랜드에 맞는 완전한 커스터마이징이 가능하다.
sequenceDiagram participant B as 브라우저 participant F as 프론트엔드 participant K as Kratos B->>K: GET /self-service/login/browser K-->>B: flow_id, csrf_token 발급 B->>F: 로그인 페이지 요청 F-->>B: 로그인 폼 렌더링 (직접 구현) B->>K: POST /self-service/login<br/>{identifier, password} K-->>B: Set-Cookie: ory_kratos_session<br/>세션 생성 완료Identity Schema
Kratos는 JSON Schema로 사용자 프로필을 정의한다:
{ "$id": "https://example.com/user.schema.json", "type": "object", "properties": { "traits": { "type": "object", "properties": { "email": { "type": "string", "format": "email", "title": "이메일", "ory.sh/kratos": { "credentials": { "password": { "identifier": true } }, "verification": { "via": "email" }, "recovery": { "via": "email" } } }, "name": { "type": "string", "title": "이름" } }, "required": ["email"] } } }Hydra: OAuth2/OIDC Provider
왜 토큰이 필요한가?
Kratos로 로그인하면 세션 쿠키가 발급된다. 하지만 쿠키만으로는 한계가 있다:
상황 세션 쿠키 OAuth2 토큰 브라우저에서 API 호출 가능 가능 서버에서 API 호출 불가 가능 모바일 앱이 API 호출 불가 가능 권한 범위(Scope) 제한 불가 가능 만료 시간 설정 제한적 자유롭게 Hydra는 이런 OAuth2 토큰 발급을 전담한다.
Hydra가 하는 일 vs 하지 않는 일
Hydra가 하는 일 Hydra가 하지 않는 일 OAuth2 Client 관리 사용자 인증 (Kratos 담당) Access/Refresh Token 발급 사용자 등록 Token Introspection 세션 관리 OIDC ID Token 발급 권한 결정 Grant Types
Hydra가 지원하는 OAuth2 Grant Types:
Grant Type 용도 사용자 Client Credentials 서버-서버 통신 백엔드 서비스 Authorization Code 사용자 대신 API 호출 웹/모바일 앱 Refresh Token 토큰 갱신 모든 클라이언트 sequenceDiagram participant C as 백엔드 서비스 participant H as Hydra C->>H: POST /oauth2/token<br/>grant_type=client_credentials<br/>client_id=xxx<br/>client_secret=yyy H-->>C: access_token<br/>(JWT, 1시간 유효)Token Introspection
발급된 토큰의 유효성을 검증한다:
# 토큰 검증 요청 POST /oauth2/introspect Content-Type: application/x-www-form-urlencoded token=<access_token>// 응답 { "active": true, "client_id": "my-service", "scope": "read write", "sub": "my-service", "exp": 1702915200, "ext": { "custom_claim": "value" } }Oathkeeper: Identity & Access Proxy
왜 API 앞에 경비원이 필요한가?
API 서비스가 10개 있다고 상상해보자. 각 서비스에 인증 로직을 직접 넣으면:
문제 결과 인증 코드 복붙 10번 한 곳 고치면 9곳도 수정 필요 실수로 빠뜨린 API 보안 구멍 발생 토큰 검증 로직 변경 10개 서비스 모두 재배포 Oathkeeper는 API Gateway 앞단에서 모든 인증을 한 곳에서 처리한다.
동작 방식
flowchart TB R["Consumer + Token"] subgraph O["Oathkeeper 파이프라인"] direction TB A["1. Authenticator"] B["2. Authorizer"] C["3. Mutator"] A --> B --> C end S["Backend API"] R --> O --> S style R stroke:#475569,stroke-width:2px style O stroke:#2563eb,stroke-width:2px style S stroke:#16a34a,stroke-width:2px처리 파이프라인
단계 컴포넌트 역할 예시 1 Authenticator 토큰 검증 OAuth2 Introspection 2 Authorizer 권한 결정 allow, deny, remote 3 Mutator 요청 변환 헤더 추가, JWT 재서명 Access Rules 예시
- id: "api-gateway-oauth2" upstream: url: "http://backend-service" match: url: "<https|http>://<.*>/api/<.*>" methods: ["GET", "POST", "PUT", "DELETE"] # 1. 토큰 검증 authenticators: - handler: oauth2_introspection config: introspection_url: "http://hydra:4445/oauth2/introspect" # 2. 권한 확인 (검증 통과 시 허용) authorizers: - handler: allow # 3. 헤더 변환 mutators: - handler: header config: headers: X-User-Id: "{{ print .Extra.user_id }}" X-Client-Id: "{{ print .Subject }}"ext_authz 모드
Oathkeeper는 Envoy의 ext_authz 서버로 동작할 수 있다:
sequenceDiagram participant C as Consumer participant E as Envoy Gateway participant O as Oathkeeper participant H as Hydra participant B as Backend C->>E: API 요청 + Token E->>O: ext_authz 검증 요청 O->>H: POST /oauth2/introspect H-->>O: Token 유효성 정보 O-->>E: OK + Headers<br/>(X-User-Id 등) E->>B: 요청 전달 + 인증 헤더 B-->>C: 응답Keto: Permission Engine
왜 별도의 권한 엔진이 필요한가?
Oathkeeper가 "이 사람 토큰이 유효해요"라고 확인해도, 그것만으로는 부족하다:
질문 Oathkeeper Keto "토큰이 유효한가?" 가능 - "이 리소스에 접근할 수 있는가?" 모름 가능 "이 리소스를 삭제할 수 있는가?" 모름 가능 Keto는 이런 세밀한 권한(Permission) 관리를 전담한다.
RBAC vs ReBAC
모델 설명 예시 RBAC 역할 기반 "admin은 모든 것 가능" ReBAC 관계 기반 "이 문서의 owner만 삭제 가능" Keto는 ReBAC (Relation-Based Access Control)을 지원한다:
Keto 관계 모델:
namespace:object#relation@subject관계 튜플 예시 의미 organizations:org-123#owner@user-456user-456은 org-123의 owner documents:doc-789#viewer@user-456user-456은 doc-789의 viewer 권한 체크 흐름
sequenceDiagram participant A as API participant K as Keto A->>K: check(documents:doc-123#edit@user-456) K-->>A: allowed: true아키텍처 적용
Control Plane vs Data Plane
Ory 컴포넌트는 두 개의 영역에서 다르게 사용된다:
Control Plane (관리 영역)
flowchart LR subgraph clients["클라이언트"] Web["Web"] API["API"] Service["Service"] end subgraph ory["Ory"] K["Kratos"] H["Hydra"] E["Keto"] end Web -->|세션| K API -->|whoami| K API -->|권한| E Service -->|토큰| H style clients stroke:#2563eb,stroke-width:2px style ory stroke:#14b8a6,stroke-width:2pxData Plane (API Gateway 영역)
flowchart TB C["Consumer"] subgraph gateway["Envoy Gateway"] E["Envoy"] O["Oathkeeper"] H["Hydra"] end B["Backend"] C -->|API 호출| E E -->|ext_authz| O O -->|introspect| H E --> B style gateway stroke:#a855f7,stroke-width:2px컴포넌트별 사용처
컴포넌트 Control Plane Data Plane Kratos 웹 로그인 - Hydra 서비스 인증 Consumer 토큰 Oathkeeper - ext_authz Keto RBAC 체크 - 인증 방식 요약
클라이언트 인증 방식 Ory 컴포넌트 Web App Session Cookie Kratos 백엔드 서비스 JWT (Client Credentials) Hydra 외부 Consumer OAuth2 / API Key Hydra + Oathkeeper 결론
핵심 요약
컴포넌트 한 줄 요약 용도 Kratos 사용자 인증 (로그인, 세션) 웹 대시보드 로그인 Hydra OAuth2 토큰 발급 서비스/Consumer 인증 Oathkeeper API 인증 프록시 Envoy ext_authz Keto 권한 관리 (ReBAC) 리소스 접근 제어 왜 4개 모두 필요한가?
Q: Kratos만 쓰면 안 되나요?
Kratos는 세션 기반이다. API 토큰이 필요하면 Hydra가 필요하다.
Q: Hydra만 쓰면 안 되나요?
Hydra는 토큰만 발급한다. 사용자 등록/로그인 UI Flow는 Kratos가 처리한다.
Q: Oathkeeper 없이 직접 검증하면 안 되나요?
가능하지만, Envoy ext_authz + 헤더 변환을 Oathkeeper가 표준화해서 처리해준다.
Q: Keto 없이 코드로 권한 체크하면 안 되나요?
가능하지만, 관계 그래프 기반 권한 상속이 복잡해지면 Keto가 훨씬 유연하다.
참고 자료
공식 문서
- Ory Documentation
- Kratos Quickstart
- Hydra OAuth2 Guide
- Oathkeeper Configuration
- Keto Permission Model
관련 자료
'실제 경험과 인사이트를 AI와 함께 정리한 글' 카테고리의 다른 글
Claude Code로 세련된 UI 만들기 (0) 2025.12.18 Ory Kratos 로그인 플로우 Deep Dive (0) 2025.12.18 Kubernetes Gateway API 설계 철학: Ingress를 넘어서 (0) 2025.12.18 Kubernetes Operator 패턴과 Reconciliation: 선언적 인프라의 핵심 (0) 2025.12.18 gRPC 완전 가이드: REST와의 비교부터 실전 활용까지 (0) 2025.12.18