7.1 KiB
7.1 KiB
ADR-004: Keycloak 전환 후 자체 인증 자산 일괄 제거
Status
Accepted
Date
2026-04-17 (ADR-002 와 동일 PR 묶음)
Context
ADR-002 가 인증 주체를 Keycloak 으로 옮긴 직후, auth-server 내부에는 다음이 기능적으로 무용해진 상태로 남아 있었다.
- 자체 JWT 발급기 (
NimbusJwtTokenIssuerAdapter, RSA key source, Vault Transit signer) - 로컬 회원가입 / 로그인 endpoint, BCrypt password hasher, password 도메인 규칙
- 자체 OIDC discovery / JWKS endpoint
- Multi-provider (LOCAL / GOOGLE / GITHUB) 분기
이걸 그대로 두면 "어느 issuer 의 token 을 신뢰하는가", "회원 식별자의 source of truth 는 어디인가" 가 흐려지고, 운영 장애 가능 지점도 늘어난다 (예: 로컬 RSA key 파일 누락 시 부팅 실패, Vault Transit endpoint 변경 시 영향 등).
Decision Drivers
- Keycloak 으로 인증 주체가 옮겨졌으므로, auth-server 의 모든 인증 발급 / 키 관리 책임은 중복.
provider컬럼이LOCAL/GOOGLE/GITHUB/KEYCLOAK4 종으로 분기되어 있으면 auth lookup 쿼리, audit event, error code 모두 분기 비용이 남는다.- password 가 디스크에 저장되는 한 비밀번호 정책 / 해시 회전 / 누설 시 회전 책임이 따라온다 — IdP 가 처리하는 게 정석.
- 부분 제거 (deprecation 표기 후 점진 제거) 는 6~12 개월 dead code 가 portfolio 에 남는 비용이 큼.
Considered Options
Option 1: 점진적 deprecation (각 클래스에 @Deprecated + 주석)
- 장점: 기존 클라이언트가 일시적으로 호환됨.
- 단점: dead code 가 PR diff 마다 노이즈가 됨. 보안 책임 (password 저장, 자체 키 보관) 이 제거 전까지 계속 살아 있음.
- 트레이드오프: portfolio 관점에서 "제거를 못 끝내는 사람" 시그널.
Option 2: 일괄 제거 + DB 스키마 정리 (V4 → V5 마이그레이션 2 단)
- 장점: 책임 경계가 한 PR 로 깨끗하게 정리됨. password / Vault Transit 운영 위험이 즉시 사라짐.
- 단점: 기존
/auth/login//auth/oauth2/*클라이언트가 곧장 깨짐 (다만 Keycloak 으로 이미 옮겼으니 이 시점에 클라이언트는 없음). - 트레이드오프: 초기 변경량이 크지만, 이후 운영 표면이 작아짐.
Decision
Option 2 채택. 자체 인증 발급 / 로컬 회원가입 / Vault Transit signing 자산을 일괄 제거하고, DB 스키마는 V4__add_keycloak_provider.sql (KEYCLOAK 값 허용) → V5__keycloak_only_provider.sql (encoded_password 컬럼 제거 + LOCAL/social 체크 제약 제거 + provider 체크를 KEYCLOAK 단일값으로 고정) 두 단계로 정리.
제거된 책임
| 이전 사용처 | 역할 | 처리 |
|---|---|---|
AuthLoginController |
/api/v1/auth/login 로컬 로그인 endpoint |
제거 |
AuthOAuth2Controller |
Keycloak broker 시작 / 완료 endpoint | 제거 |
OAuth2SecurityConfiguration |
OAuth2 login filter chain | ResourceServerSecurityConfiguration 으로 대체 |
UserSignUpController / SignUp* |
로컬 회원가입 use case 와 DTO | 제거 (회원가입은 Keycloak 담당) |
BcryptPasswordEncoderAdapter / PasswordHasherPort |
bcrypt 비밀번호 해싱 | 제거 (auth-server 는 password 를 다루지 않음) |
EncodedPassword / UserPasswordPolicy / InvalidUserPasswordException |
비밀번호 도메인 규칙 | 제거 |
User.registerLocal |
LOCAL provider 등록 경로 | 제거 (registerKeycloak 만 남음) |
AuthProvider.LOCAL/GOOGLE/GITHUB |
social/local provider 분기 값 | 제거 (KEYCLOAK 만 남음) |
NimbusJwtTokenIssuerAdapter |
자체 RS256 JWT 발급 | 제거 |
JwtKeyConfiguration / ConfiguredJwtSigningKeySource |
로컬 RSA signer 구성 | 제거 |
VaultTransitClient / VaultTransitJwtSigner |
Vault Transit 서명 API 호출 | 제거 |
ConfiguredOpenIdDiscoveryDocumentProvider / OpenIdDiscoveryController |
자체 issuer / JWKS 공개 | 제거 |
auth-login.html |
auth-server 로그인 페이지 | 제거 |
AuthAuditEventType.LOGIN_* / OAUTH_LOGIN_* / TOKEN_ISSUED / SIGNUP_* |
로컬 인증 / 발급 감사 이벤트 | KEYCLOAK_USER_NOT_FOUND 로 축소 |
AuthErrorCode.INVALID_CREDENTIALS / OAUTH_* |
로컬 로그인 에러 코드 | KEYCLOAK_CLAIMS_INVALID / KEYCLOAK_ACCOUNT_CONFLICT 로 교체 |
UserErrorCode.* / ApiSuccessCode.USER_SIGNED_UP |
로컬 회원가입 에러 / 성공 코드 | 제거 |
남은 책임
| 현재 사용처 | 역할 |
|---|---|
ResourceServerSecurityConfiguration |
Keycloak issuer 기반 Bearer token 검증 |
KeycloakJwtAuthenticationConverter |
claim / role → project principal 매핑 |
AuthenticatedUserController |
현재 사용자 조회 진입점 |
KeycloakUserLoader |
(KEYCLOAK, sub) 기준 내부 사용자 식별 |
KeycloakUserClaimsValidator |
검증된 JWT 에서 올라온 claim 의 내부 도메인 적합성 확인 |
DB 스키마 변화
V4__add_keycloak_provider.sql:KEYCLOAK값을 허용하는 중간 단계 migrationV5__keycloak_only_provider.sql:encoded_password컬럼과 LOCAL / social 체크 제약을 제거하고,provider_subject를 NOT NULL 로,provider체크를KEYCLOAK단일값으로 고정
Consequences
긍정적 결과
- auth-server 는 더 이상 token 을 만들거나 공개키를 배포하거나 password 를 저장하지 않습니다.
- issuer / JWKS source of truth 가 Keycloak 한 곳으로 고정.
- DB 스키마에서
encoded_password, LOCAL provider 분기, social subject 체크 제약이 모두 제거 — 코드 분기뿐 아니라 데이터 모델 도 단순해짐. - Vault Transit endpoint 의존성이 사라져 dev 환경에서 Vault 가 secret store 역할만 하면 됨.
부정적 결과
- 클라이언트는 더 이상 auth-server 로그인 / 회원가입 endpoint 를 사용할 수 없음 (이 시점에 그런 클라이언트는 없었음 — pre-emptive 제거).
- 회원가입 UX 가 Keycloak realm 설정 / 테마에 묶임.
- Keycloak realm 설정은 API 인증의 필수 운영 의존성 — 운영자는 JWKS 회전과 issuer URI 고정을 책임.
위험 완화
GET /api/v1/auth/me의 token 검증은 ResourceServer 가 담당.- 연결된 내부 사용자가 없으면 ADR-005에 따라 email 충돌 검사 후 내부 사용자 자동 등록.
- role / claim mapping 은
KeycloakJwtAuthenticationConverter한 곳에 모임. - 조회 흐름은 내부 DB lookup 만 수행하므로
GET에 숨은 쓰기 부작용 없음.
관련 문서
- 02-adr-keycloak-resource-server.md — 인증 주체 이전 결정 (ADR-002)
- 05-adr-keycloak-user-auto-registration.md — Keycloak 인증 사용자 내부 자동 등록 결정 (ADR-005)
- 01-architecture.md — 현재 ResourceServer 아키텍처
- 03-claim-role-design.md — claim / role 매핑 정책