나는 50개의 오픈소스 Spring Boot 프로젝트를 스캔했습니다. 절반 이상이 조용한 config drift를 겪었습니다.
Source: Dev.to
설정 드리프트란?
Spring Boot에서는 프로파일 파일을 사용해 환경별 설정을 정의할 수 있습니다:
application.yml ← defaults
application-dev.yml ← overrides for development
application-staging.yml ← overrides for staging
application-prod.yml ← overrides for production
설정 드리프트는 하나의 프로파일에 있는 값이 다른 프로파일과 의도치 않게 달라지는 현상을 말합니다.
보통은 사소한 것부터 시작됩니다: 누군가 dev.yml에 디버깅용 설정을 추가하고 이를 잊어버렸다가, 몇 주 후에 파일을 시작점으로 복사‑붙여넣기 하면서 prod.yml에도 같은 설정이 들어가게 되는 경우가 대표적입니다.
문제는 드리프트가 눈에 띄지 않는다는 점입니다. 애플리케이션은 정상적으로 시작하고, 테스트는 통과하며, CI도 초록색을 유지합니다. 잘못된 설정은 그저 존재할 뿐, 언제든 문제가 될 수 있습니다.
내가 어디서든 보는 세 가지 패턴
1. Actuator 누수
가장 흔한 경우이며, 논쟁의 여지 없이 가장 위험합니다.
# application-dev.yml
management:
endpoints:
web:
exposure:
include: "*"
개발 환경에서는 합리적입니다 — 디버깅을 위해 모든 Actuator 엔드포인트를 사용하고 싶으니까요.
문제는 이 값이 스테이징으로, 그리고 프로덕션으로 넘어갈 때 발생합니다:
# application-prod.yml (drifted)
management:
endpoints:
web:
exposure:
include: "*" # ← exposes /actuator/env, /actuator/heapdump, …
/actuator/env 엔드포인트가 이제 모든 환경 변수를 반환합니다 — 비밀 정보까지 포함해서.
/actuator/heapdump 은 누구든지 전체 JVM 힙 덤프를 다운로드할 수 있게 합니다.
Spring Boot의 기본값은 health,info 입니다. 개발 환경에서 이를 오버라이드하고 프로덕션에서 제한하는 것을 잊는 순간, 오류 메시지도 없고 테스트 실패도 없는 정보 노출 취약점이 생깁니다.
2. 데이터베이스 스키마 파괴자
# application-dev.yml
spring:
jpa:
hibernate:
ddl-auto: update
update 는 개발 단계에서 편리합니다: Hibernate가 엔티티에 맞게 스키마를 자동으로 조정합니다.
하지만 프로덕션에서는 가장 위험한 설정 중 하나이기도 합니다.
안전한 프로덕션 값은 validate 혹은 none 입니다. 그러나 update 가 개발에서 프로덕션으로 넘어가고 엔티티 모델이 변경되면, Hibernate가 프로덕션 스키마를 조용히 수정합니다. 마이그레이션 스크립트도, 리뷰도, 경고도 없습니다.
제가 직접 본 바로는 이 때문에 프로덕션 데이터베이스가 파괴된 사례가 있습니다.
3. 누락된 기능 플래그
# application-dev.yml
feature:
new-payment-flow:
enabled: true
# application-staging.yml
feature:
new-payment-flow:
enabled: true
# application-prod.yml
# ← key doesn't exist
키가 개발 및 스테이징에는 존재하지만 프로덕션에는 없을 경우, Spring Boot은 null 로 대체합니다 (또는 런타임에 NullPointerException 을 발생시킵니다, 운이 좋다면).
이 패턴은 특히 기능 플래그에서 흔합니다 — 개발 중에 추가되고 스테이징에서 테스트된 뒤, 프로덕션 설정을 작성할 때 잊혀집니다.
왜 이것을 잡기 어려운가
- 코드 리뷰로는 찾을 수 없습니다. PR에서 파일을 나란히 비교하는 것이 아니라, 변경된 diff만 보고 있기 때문에 파일 간 관계를 보지 못합니다.
- 테스트로는 찾을 수 없습니다. 단위 테스트는 단일 프로파일에 대해 실행됩니다. 통합 테스트는 보통 테스트 프로파일에 대해 실행됩니다.
dev.yml이 말하는 것과prod.yml이 말하는 것을 비교하는 테스트는 아무도 실행하지 않습니다. - CI로는 찾을 수 없습니다. 파이프라인은 앱이 시작되고 테스트가 통과하는지 검증합니다.
prod.yml이 의도와 일치하는지는 검증하지 않습니다.
이 문제는 보통 가장 안 좋은 순간에 프로덕션에서 드러납니다.
도구를 만들어 잡기
배포 전에 YAML 파일을 수동으로 비교하는 것이 지겨워졌습니다. 그래서 spring‑drift를 만들었습니다. 이 CLI는 설정 디렉터리를 스캔하고, 모든 프로파일을 비교하며, 특히 위험한 종류의 드리프트를 표시합니다.
$ spring-drift scan ./src/main/resources
✓ Found 4 profiles: default, dev, staging, prod
✗ 7 drift issues found
[DANGEROUS_DEFAULT] management.endpoints.web.exposure.include
default: health,info
dev: *
staging: *
prod: * ← matches dev — likely accidental
[DANGEROUS_DEFAULT] spring.jpa.hibernate.ddl-auto
default: validate
dev: update
prod: update ← destructive in production
[MISSING_KEY] feature.new-payment-flow.enabled
dev: true
staging: true
prod: ← will fall back to null
Report written to drift-report.md
Linux에서 약 26 ms에 실행되며, PR에 바로 붙여넣을 수 있는 Markdown 보고서를 출력하고, 기본적으로 가장 흔한 위험한 Spring Boot 기본값들을 인식합니다. Java 21 + Picocli + GraalVM Native Image로 구축되어 단일 바이너리이며 JRE가 필요 없습니다.
워크플로에 추가하는 방법
가장 간단한 통합 방법은 사전 배포 검사입니다:
# 스테이징이나 프로덕션에 배포하기 전에:
spring-drift scan ./src/main/resources
드리프트가 발생하면 빌드를 실패시키고 싶다면, 종료 코드를 사용하세요:
spring-drift scan ./src/main/resources || exit 1
또는 GitHub Actions 파이프라인에 추가합니다:
- name: Check config drift
run: spring-drift scan ./src/main/resources
curl -L https://github.com/jolle93/spring-boot-config-drift-detector/releases/latest/download/spring-drift-linux-x64 -o spring-drift
chmod +x spring-drift
./spring-drift scan ./src/main/resources
50개의 오픈소스 프로젝트를 스캔하면서 배운 점
GitHub에 있는 50개의 잘 알려진 Spring Boot 프로젝트—공식 Spring PetClinic부터 mall, jhipster‑generated apps와 같은 대규모 프로젝트, 그리고 ShenYu, DolphinScheduler 같은 Apache 프로젝트—에 spring‑drift를 실행했습니다.
50개 프로젝트 중 26개가 최소 하나의 drift 이슈를 가지고 있었습니다 (53 %).
497개의 개별 모듈을 스캔한 결과, 도구는 다음을 발견했습니다:
| 카테고리 | 수 |
|---|---|
| 전체 drift 이슈 | 2 470 |
| 위험한 기본값 | 167 |
| 누락된 키 | 2 172 |
| 값 drift | 131 |
가장 흔한 위험한 기본값
| 기본값 | 발생 횟수 | 비고 |
|---|---|---|
management.endpoints.web.exposure.include | 78 모듈 | 공식 Spring PetClinic에서 플래그됨 – 레퍼런스 앱이 include: * 로 제공되어, 프로덕션 프로파일에서 오버라이드되지 않으면 모든 Actuator 엔드포인트가 노출됩니다. |
spring.datasource.password | 83 발생 | 프로덕션용 프로파일에서도 빈값이거나 개발 전용 플레이스홀더로 설정된 경우가 많습니다. |
관찰
- 프로젝트 규모와 관계없이 패턴이 일관됩니다: 작은 튜토리얼 레포, 대규모 엔터프라이즈 애플리케이션, 최상위 Apache 프로젝트 모두 동일한 문제를 보입니다.
- 설정 파일은 시간이 지나면서 결정들을 축적하지만, 코드와 달리 리팩터링이 거의 이루어지지 않습니다.
마무리
Config drift는 별다른 문제가 없어 보이다가 문제가 되면 심각합니다. 위의 세 가지 패턴 — Actuator 노출, ddl-auto, 그리고 누락된 기능 플래그 — 은 실제 운영 시스템에서 장애를 일으켰습니다. 이들은 특이한 예외 상황이 아닙니다.
직접 프로젝트에 spring‑drift 사용해 보기
The tool is source‑available on GitHub and takes about 30 seconds to run against an existing Spring Boot project.
If you discover a dangerous default that isn’t covered yet, please open a Severity Rule Request.
Built with Java 21, Picocli, SnakeYAML, and GraalVM Native Image.
Available for Linux (x64) and macOS (arm64).