Files
project-auth-server/docs/topics/03-keycloak/04-adr-token-ownership-cleanup.md

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/KEYCLOAK 4 종으로 분기되어 있으면 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 값을 허용하는 중간 단계 migration
  • V5__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 에 숨은 쓰기 부작용 없음.

관련 문서