"GitHub에 AWS Access Key가 포함된 코드가 푸시되었습니다."라는 보안 알림을 받아본 적 있으신가요?
많은 개발팀이 application.yml 파일에 DB 비밀번호나 API 키를 평문으로 저장하고 있습니다.
GitIgnore로 관리한다고 해도 배포 서버에 파일을 직접 복사해야 하는 번거로움과, 퇴사자가 발생했을 때 키를 교체해야 하는 운영 비용이 큽니다.
저희는 이 문제를 해결하기 위해 HashiCorp Vault를 도입하여 중앙 집중화된 시크릿 관리 체계를 구축했습니다.
프로덕션 환경을 위해 HA(High Availability) 모드로 구축하는 것이 좋지만, 여기서는 실습을 위해 Docker로 Dev Server를 띄웁니다.
docker run -d --name vault -p 8200:8200 -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' vault
시크릿을 저장할 경로(Path)를 생성하고 데이터를 입력합니다.
# Vault 컨테이너 접속
docker exec -it vault sh
# 로그인
export VAULT_ADDR='http://127.0.0.1:8200'
vault login myroot
# 시크릿 저장
vault kv put secret/my-app/db password=super_secure_password username=dbadmin
애플리케이션이 구동될 때 Vault에서 시크릿을 가져와서 환경 변수처럼 주입받도록 설정합니다.
implementation 'org.springframework.cloud:spring-cloud-starter-vault-config'
애플리케이션이 시작되기 전에 Vault와 통신해야 하므로 application.yml이 아닌 bootstrap.yml에 설정합니다.
(Spring Boot 2.4+ 부터는 application.yml에서도 가능)
spring:
cloud:
vault:
host: localhost
port: 8200
scheme: http
authentication: TOKEN
token: myroot # 실무에서는 AppRole 사용 권장
kv:
enabled: true
이제 코드에서는 일반 프로퍼티처럼 값을 가져다 쓸 수 있습니다.
@Value("${password}")
private String dbPassword;
중요한 점은 소스 코드 어디에도 실제 비밀번호가 없다는 것입니다. 오직 Vault 운영자만이 비밀번호를 알 수 있으며, 필요 시 Vault에서 값을 변경하고 앱을 재시작하면 키 교체가 완료됩니다.
Vault 도입으로 보안 컴플라이언스(ISMS) 요건을 충족시킬 수 있었고, 민감 정보를 코드로 관리하는 리스크를 완전히 제거했습니다. 장기적으로는 Dynamic Secrets 기능을 통해 "1시간만 유효한 임시 DB 계정"을 발급하는 방식으로 보안 수준을 더욱 높일 계획입니다.