Skip to Content
Software Architecture10년 된 인증 서비스를 Spring Boot 3로 올리기까지
🏗️ Software Architecture2025년 2월 15일

10년 된 인증 서비스를 Spring Boot 3로 올리기까지

#identity-platform#spring-boot#java-21#modernization#hibernate
Identity Platform · Series 1 · Platform Modernization1 / 15Software Architecture
10년 된 인증 서비스의 기반 공사 — 후속 개선을 다시 할 수 있는 상태를 만드는 데 집중했다.
Note

여기서 말하는 인증 서비스는 관리자 플랫폼의 로그인, 권한 확인, 사용자 맥락 검증을 담당하던 핵심 백엔드다.

원래 무엇 위에서 돌고 있었나

이 서비스는 Spring Boot가 아니었다. Spring MVC 4.x 위에 web.xml과 XML 설정 파일로 구성된 전통적인 WAR 배포 방식이었다. Tomcat에 WAR를 올리는 구조로, 자동 설정 같은 건 없었다. Bean 정의, 데이터소스, 보안 필터, 서블릿 매핑까지 모든 것이 명시적 XML이나 Java Config로 수동 관리되고 있었다.

항목전환 전전환 후
프레임워크Spring Framework 4Spring Boot 3 (Spring 6)
런타임Java 8Java 21
보안Spring Security 4Spring Security 6
배포 방식WAR → 외장 Tomcat (Servlet 2.5)내장 Tomcat (executable JAR)
설정 방식web.xml + XML ConfigJava Config + Spring Boot 자동 설정
ORMHibernate 4Hibernate 6
검증Hibernate Validator 4Hibernate Validator 8
API 패키지javax.*jakarta.*
테스트Mockito 1Mockito 5
DB 마이그레이션Flyway 2Flyway 10
API 문서Springfox SwaggerSpringDoc
메트릭Codahale MetricsSpring Boot Actuator

10년 가까이 이 구조로 운영되면서, 설정의 이유를 아는 사람은 떠나고 설정만 남은 상태였다.

왜 이 업그레이드가 먼저였나

서비스는 오래 버텼지만, 더 이상 안전하게 유지할 수 있는 상태는 아니었다. 구버전 Spring과 Java 위에서는 보안 패치 대응이 느려질 수밖에 없었고, 로그 체계나 운영 도구를 현대화하려 해도 기반이 계속 발목을 잡았다.

이 작업의 목적은 “최신 버전 사용”이 아니라 다음 개선을 다시 할 수 있는 상태를 만드는 것이었다. 새 기능이 아니라는 이유로 범위가 단순해 보이기 쉽지만, 실제로는 서비스가 수년간 떠안고 있던 모든 수동 규칙을 다시 읽어내고, 무엇을 유지하고 무엇을 없앨지 결정을 반복해야 했다.

규모감: 한 줄 요약에 숨은 3만 줄

겉으로 보면 “메이저 업그레이드” 한 줄이지만, 실제로는 거의 모든 레이어를 건드리는 일이었다.

PR 규모: 약 +16,000 / -14,000

위 표에서 보듯이, 바뀐 것이 런타임·프레임워크·보안·ORM·배포·테스트·API 문서·메트릭까지 사실상 전 영역이었다. 그중에서도 특히 어려웠던 세 가지가 있었다.

  • 수동 설정 vs Boot 자동 설정 충돌 — 기존 XML로 수동 생성하던 Bean과 Boot가 자동 생성하는 Bean이 부딪히면서, 어떤 것을 유지하고 어떤 것을 Boot에 맡길지 하나하나 판단해야 했다.
  • Hibernate 4 → 6, 두 메이저를 건너뛴 ORM 전면 재작성 — Criteria API 삭제, Type 시스템 교체로 모든 동적 쿼리를 다시 짜야 했다.
  • 테스트 코드 — 이 서비스의 테스트 케이스만 수천 개였는데, Mockito부터 Spring 테스트 인프라까지 전부 바뀌면서 사실상 전면 재작성이 필요했다. 전체 변경의 절반 이상을 차지했고, 가장 시간이 많이 들었다.

이 세 가지는 다음 글에서 코드 수준으로 자세히 다룬다.

운영 배포는 계획대로 이루어지지 않았다

PR 리뷰가 오래 걸리고 있었다. 3만 줄짜리 빅뱅 PR이었으니 당연했다. 그 사이에도 테스트는 계속 진행 중이었고, Production을 제외한 모든 Pre-Production 환경에는 이미 새 버전이 배포돼 있었다.

이 서비스는 인증 서비스다. 수십 개의 서비스가 이 서비스를 호출해서 인증을 체크하고, 사용자 정보와 권한 정보를 가져간다. 그래서 테스트에 모든 팀이 총동원됐다. 각 팀이 자기 서비스에서 인증 흐름이 정상 동작하는지 확인해야 했기 때문이다. 릴리즈 일정은 이 전체 검증이 마무리된 뒤에 잡을 계획이었다.

그런데 기존 서비스에 장애가 터졌다.

원인은 Spring XML 설정의 schemaLocation 참조 실패였다. XML 설정 파일이 기동 시 원격 서버에서 XSD 스키마를 가져오는데, Zero Trust 정책이 적용되면서 인증서 검증에 실패해 XSD를 불러오지 못했고 XML 파싱 자체가 깨졌다. 코드 변경이 아니라 인프라 정책 변경이 원인이었기 때문에 기존 컨테이너 이미지를 재배포해도 같은 에러로 죽었고, 롤백으로는 해결할 수 없었다.

글로벌 팀은 결정을 내렸다 — “UAT까지 끝난 새 버전을 올려보자.”

Spring Boot 3로 전환한 버전에는 XML 설정이 없었다. Java Config와 application.properties로 전면 재구성된 상태였기 때문에, 장애 원인이었던 XML 파싱 자체가 존재하지 않았다.

빅뱅이었다. 그런데 문제없이 떴다.

이 일은 한국 팀이 자고 있는 시간에 일어났다. 아침에 일어나니 배포가 끝나 있었고, 글로벌 팀으로부터 “장애 때문에 새 버전 올렸는데 잘 돌아간다”는 얘기를 듣게 됐다.

계획된 릴리즈가 아니라 장애가 배포를 앞당긴 셈이었다. 돌이켜 보면, UAT를 충분히 돌려둔 것과 테스트 커버리지를 올려둔 것이 이 순간에 발을 맞춰준 셈이다. 만약 테스트 없이 “일단 올려보자”였다면 장애 위에 장애를 쌓는 일이 됐을 수도 있다.

이 사건 이후, 사내 Zero Trust 환경에서 HTTPS 통신에 필요한 내부 Root CA 인증서를 컨테이너 이미지의 trust store에 포함시키는 것이 표준이 됐다. 기존 이미지에는 이 인증서가 없었기 때문에 외부 XSD 참조 시 TLS 핸드셰이크에서 실패한 것이었다.

아이러니하게도, 이 서비스를 현대화해야 했던 이유 — 오래된 설정 체계가 더 이상 유지 가능하지 않다 — 를 장애가 직접 증명해 준 사건이었다.

이 업그레이드가 남긴 실제 효과

  • 버전이 올라가면서 그 자체로 많은 알려진 취약점이 해소됐고, 보안 패치 대응도 더 이상 별도 프로젝트처럼 취급하지 않아도 됐다.
  • 이번 전환과 함께 컨테이너 이미지 취약점 검사(Wiz)와 코드 레벨 보안 취약점 스캔이 CI 파이프라인에 추가돼, 배포 전 보안 검증 체계가 갖춰졌다.
  • 구조화 로깅과 운영용 공통 규칙을 넣을 수 있는 기반이 생겼다.
  • 비동기 처리와 이벤트 발행 방식을 현대적인 방식으로 정리할 수 있었다.
  • 이후 성능 분석과 병목 개선에서도 로그와 계측을 붙이기 쉬워졌다.
  • 테스트 커버리지가 이전보다 크게 올라가서, 이후 변경에 대한 신뢰도가 높아졌다.

즉, 이 작업의 가치는 “버전이 올라갔다”보다 후속 개선의 진입 비용을 낮췄다는 데 있었다.

3만 줄짜리 PR을 잘게 쪼개고 싶었지만, 그럴 수 없는 구조였다. Spring Framework 버전을 올리는 순간 Security, Hibernate, Servlet, 테스트 인프라까지 전부 연쇄적으로 깨지기 때문에, “이 부분만 먼저 올려서 리뷰받겠다”는 게 불가능했다. 결국 한 번에 다 바꾸고 한 번에 리뷰받는 수밖에 없었고, 그만큼 리뷰와 운영 검증 비용도 컸다.

레거시 서비스를 현대화한다는 건 “최신 프레임워크로 갈아탔다”는 말보다 훨씬 구체적이다. 오래된 수동 규칙을 읽고, 어떤 규칙은 없애고, 어떤 규칙은 명시적으로 남기고, 이후 변화가 다시 가능하도록 바닥을 고치는 일에 더 가깝다.

다음 글에서는 이 마이그레이션에서 실제로 가장 많은 시간을 잡아먹었던 세 영역 — Bean 충돌, ORM 재작성, 테스트 전면 교체 — 을 코드 수준에서 더 깊이 들여다본다.

Last updated on