DB 접속 정보 관리 개선 프로젝트 회고 (Memcached)
- -
📌 프로젝트 진행 기간: 23.04.~24.05.
📝 프로젝트 배경
우리 서비스는 매년 정보보호관리체계(ISMS) 인증을 받기 위해 보안 점검을 실시한다. 이 과정에서 다양한 보안 취약점을 점검하는데, 내가 프로젝트를 맡기 전 점검에서는 DB 접속 정보 관리 방식에서 보안 이슈가 발견되었다.
당시에는 쇼핑몰별 DB 접속 정보(ID/PW)가 웹서버의 설정 파일에 평문으로 저장되어 있었다. 이로 인해 웹 서버에 접근할 수 있는 누구나 해당 파일을 확인하면 DB 접속 정보를 유출할 위험이 있었다. 즉, DB 데이터가 직접 탈취될 수 있는 구조였으며, 보안 강화를 위한 개선이 시급했다.
이에 따라 DB 접속 정보 관리 방안을 개선하는 프로젝트를 진행하게 되었다.
⚒️ 1차 개선안: 솔루션 내 암호화를 통한 보안 강화
Task를 할당 받고 가장 먼저 떠올린 해결책은 단순했다.
"DB 패스워드가 평문으로 저장되어 있으니, 암호화하여 보관하자!
그리고 DB 커넥션 시에는 적절하게 복호화하여 사용하면 되지 않을까?"
최소한의 변경으로 빠르게 적용할 수 있는 방안을 고민한 끝에, AES-256-CBC 방식으로 DB 패스워드를 암호화하여 저장하는 방식을 도입하기로 했다. 각 상점의 고유 키를 사용해 암호화하고, 필요 시 복호화하는 방식을 생각했다.
🔹 적용 방식
- DB접속 정보 암호화: DB 설정 파일에 저장할 때 DB 패스워드를 AES-256-CBC 방식으로 암호화
- 복호화 및 커넥션 처리: DB 연결 시 암호화된 패스워드를 복호화하여 사용
- 추가 API 제공(타 파트의 DB 접속 정보 관리 지원용)
- DB 접속 정보 조회 API
- DB 계정 정보 추가/변경 API: API에서 생성한 복호화된 정보가 포함된 임시 파일을 수정하도록 안내
- 설정 파일 암호화 API: 복호화된 파일을 다시 암호화하여 저장
🔸 개선안의 한계
사실 이 방식도 단점은 존재했다.
- DB 계정 정보 변경 시 보안 취약성: 변경 작업 중 일정 시간 동안 복호화된 파일이 웹서버에 존재
- 비효율적인 수작업 관리: 접속 정보 파일의 변경이 자동화되지 않아 관리 부담 증가
다만, 당시 DB 계정 정보가 자주 변경되지 않는 상황을 고려해 일정상의 문제로 이 방식으로 진행하기로 결정했다.
그래서 1차 계획에 따라 개발을 진행하였으나, QA 단계까지 올라간 상황에서 또다른 요구사항이 등장하였다.
⚠️ 추가 요구사항: 고객의 DB 접속 정보 변경 기능 지원
"고객이 DB 접속 정보를 직접 변경할 수 있는 기능도 필요해요." - 기획
초기 설계에서는 웹서버에서 사용하는 DB 접속 정보만 고려했지만, 한 가지 중요한 점을 간과하고 있었다.
우리 서비스는 고객이 phpMyAdmin을 통해 직접 DB에 접속하여 데이터를 수정할 수 있도록 지원하고 있었다. 기존에는 웹서버에서만 DB 접속을 처리했기 때문에 문제가 없었지만, 정책이 변경되면서 고객이 마이페이지에서 DB 정보를 직접 변경할 수 있어야 했다.
문제는 웹서버에서 사용하는 DB 계정과 phpMyAdmin에서 사용하는 계정이 동일하다는 점이었다..🤨 즉, 고객이 DB 패스워드를 변경하면 웹서버의 DB 접속 정보 파일도 함께 수정되어야 했으며, 이 과정에서 오류가 발생하면 쇼핑몰 접속이 중단될 위험이 있었다. 추가 요구사항을 반영하기 위해 새로운 해결책이 필요했다.
이를 해결하기 위해, ALTER USER 쿼리를 실행하고 DB 접속 정보 파일을 갱신하는 신규 API를 개발하는 방안을 고려했지만, 두 가지 치명적인 보안 문제가 있어 즉시 폐기했다.
1️⃣ SQL 바인딩 문제
ALTER USER 구문은 바인딩 처리를 지원하지 않아서 SQL 인젝션 공격에 취약했다.
2️⃣ API 기반 비밀번호 변경의 보안 취약점
DB 비밀번호 변경을 API로 제공하는 것 자체가 보안상 위험했다. 만약 공격자가 다른 상점의 비밀번호 변경 API를 호출하면, 해당 DB를 통째로 탈취할 수도 있는 구조였다. 따라서 어플리케이션이 직접 DB 계정 정보를 변경하는 방식 자체가 보안상 안전하지 않다고 판단했다.
위 문제들로 인해 새로운 접근 방식이 필요했다.
⚒️ 1차 추가 개선안: 컨슈머를 활용한 DB 비밀번호 변경 처리
한 차례 고민을 한 다음, 비밀번호 변경을 비동기 방식으로 처리하는 구조로 계획을 변경했다.
🔹 변경된 구조
1. 고객이 마이페이지에서 DB 비밀번호 변경 요청
2. 비밀번호 변경 토픽 발행
3. DB 접속 정보 파일을 갱신하는 어플리케이션 API 호출
4. 컨슈머에서 요청 수신 후 ALTER USER 실행
컨슈머를 활용하면 애플리케이션이 직접 비밀번호를 변경하지 않아도 되기 때문에, 보안성이 향상될 것으로 판단했다.
하지만… 이 방식에도 예상치 못한 문제가 있었다😭 (진짜... 끝이 없는 문제...)
⚠️ 예상치 못한 장애 가능성
비밀번호 변경을 토픽 기반으로 처리하면서, 고객에게 즉각적인 응답을 제공하기 어려운 문제가 있었다. 하지만 🚨 더 심각한 문제는 비밀번호 변경 중 장애가 발생하면 쇼핑몰 접속이 중단될 위험이 존재한다는 것이었다.
DB 접속 정보 파일 업데이트 → ALTER USER 실행 사이의 공백 문제가 제일 컸다.
- DB 접속 정보 파일이 변경된 후, ALTER USER 실행 전까지 쇼핑몰이 DB에 접속할 수 없는 상태
- 만약 ALTER USER 실행이 실패하면, 이전 상태로 자동 복구할 방법이 없음
즉, 장애 발생 시 매번 사람이 직접 개입해야 하는 비효율적인 구조였다. 본격적인 개발에 들어가기 전 Flow를 다시 점검하면서 이 문제를 발견했고, 팀장님과 논의한 끝에 계획을 처음부터 다시 고민하기로 결정했다.
⚒️ 2차 개선안: 웹서버용 접속 계정과 고객 접속 계정의 분리, 중앙 DB 도입
1차 개선안에서 발생한 보안 문제 및 장애 가능성을 해결하기 위해, 웹서버에서 DB 접속 정보를 완전히 제거하는 방향으로 설계를 변경했다. 이를 위해 중앙 DB를 도입하여 DB 접속 정보를 중앙 관리하도록 설계했다.
📌 중앙 DB를 활용한 DB 접속 정보 관리
DB 접속 정보의 저장 위치가 중앙 DB로 변경됨에 따라, 중앙 DB 조회 프로세스를 구축하고 중앙 DB에서 가져온 DB 접속 정보를 솔루션에서 캐싱 처리하여 사용할 수 있도록 개선했다. 조금 더 구체적으로 말하자면, 중앙 DB API를 호출하면 아래 순서로 동작한다.
1️⃣ 중앙 DB는 자체 보유한 데이터베이스 정보와
2️⃣ Vault에서 조회한 DB 계정 정보를
➡️ 응답 값으로 함께 반환한다.
이제는 진짜 DB 접속 정보를 안전하게 관리하면서도, 필요할 때 빠르게 가져올 수 있게 되었다! 💡
(이걸 만들기 위해 Flow를 몇번을 갈아엎었는지...😵💫)
🛠️ 캐싱 방식 결정: Redis vs Memcached
DB 접속 정보를 캐싱할 때 Redis와 Memcached 중에서 고민했지만, 최종적으로 Memcached를 선택했다.
✔ 우리 서비스는 Redis는 Global Cache(+ Distributed Cache) 용도로 사용 중
✔ Redis에 과도한 트래픽 집중 시 부하 발생 가능성 고려
✔ 웹서버별 캐싱이 가능한 Memcached가 적절
따라서 DB 접속 정보 캐싱은 Memcached를 활용하는 방향으로 결정했다.
🔄 DB 접속 정보 변경 방식
DB 접속 정보가 변경될 경우, 아래 절차로 적용하도록 개선했다.
1. 변경할 DB 계정을 추가하고, 중앙 DB에 저장
2. 솔루션 내 캐시 초기화 API 호출
3. 솔루션이 중앙 DB에서 최신 DB 정보를 가져와 DB 연결 테스트 진행
4. 결과에 따라 두 가지 처리 방식 적용
✔️ 테스트 성공 → 새로운 정보를 캐시에 저장
✔️ 테스트 실패 → 기존 캐시 데이터를 유지 & API 호출부에서 중앙 DB 데이터를 롤백
이제는 무중단으로 DB 접속 정보를 변경할 수 있게 되었다!! 🎉
⚠️ 분산 서버의 DB 연결 테스트 문제
큰 틀은 완벽해 보였지만… (또..) 숨은 문제가 하나 있었다. 😨 우리 서비스는 트래픽이 많은 쇼핑몰의 경우 분산 서버를 붙여 부하를 분산시키고 있는데, 캐시 초기화 API 요청이 원본 서버에서만 처리된다는 점이 문제였다.
🚨 문제 발생 이유
✔ Memcached는 웹서버별 캐시이므로, 원본 서버에서 정상적으로 갱신되었더라도
✔ 분산 서버에서는 갱신되지 않을 가능성이 있음
✔ 결과적으로, 분산 서버에서 DB 연결이 실패할 수도 있음
아쉽지만.. 이 부분에 대해서는 일부 트래픽이 높은 쇼핑몰에 한해 유관부서에서 DB 접속 정보 변경 시 API 요청을 특정 분산 서버로 고정하는 방식의 수작업을 추가하기로 했다. 완전히 자동화를 하지 못한 점은 아쉽지만.. 향후 개선 방향을 지속적으로 찾아보기로 했다.
✅ 프로젝트 회고
이상하게도 내가 맡은 프로젝트들은 항상 '간단'하게 시작했지만, 진행할수록 예상치 못한 문제들이 계속 나왔다. 매일매일 새로운 이슈가 등장하는 양파 같은..🧅 이번 프로젝트도 처음엔 단순한 수정으로 끝날 거라 생각했는데, 결국 DB 접속 정보 관리 방식 자체를 바꾸게 되었다. 하지만 사이드 이펙트를 꼼꼼히 점검하고 찜찜한 부분을 확실히 해결한 덕분에, 1차 개선안보다 훨씬 안정적인 결과를 만들 수 있었다 💪
🎯 이번 프로젝트에서 알게된 점들
1️⃣ 보안과 운영 효율성을 같이 가져가자
- DB 접속 정보를 웹서버에서 제거하고 중앙 DB 활용한 중앙 관리 방식을 도입함
- 보안성을 높이면서도, 유지보수와 운영 효율성도 향상시킴
2️⃣ 캐싱 전략 수립 시, 고려할 점
- Redis를 사용할 수도 있었지만, 과부하 문제를 고려해 Memcached를 선택
- 캐시 활용 목적과 시스템 구조를 고려해 적절한 캐시 솔루션을 선택하는 것이 중요하다!
3️⃣ 무중단 DB 접속 정보 변경 프로세스
- DB 접속 정보를 실시간으로 변경할 수 있도록 캐시 초기화 API + 연결 테스트 로직을 설계함
- 이를 통해 운영 중인 서비스에서도 안정적으로 DB 접속 정보를 갱신할 수 있었음
이제 진짜 프로젝트 회고 끝!!! 어렵기도 했지만, 그만큼 이번 프로젝트를 통해 이슈를 하나씩 해결하는 과정에서 얻게 된 소중한 인사이트들이 많았다. 앞으로도 작은 문제라도 애매하게 넘어가지 않고, 끝까지 문제를 해결하는 태도를 유지해야지 🚀
'Development > Review' 카테고리의 다른 글
[OAuth] 4개월 간의 통합회원 로그인 연동 및 프로젝트 회고 (1) | 2024.12.29 |
---|---|
주니어 백엔드 개발자의 2주년 회고: 일잘러가 되고 싶었던 (7) | 2024.09.30 |
2023년, 주니어 개발자로서 내가 걸어온 길 (5) | 2023.12.31 |
1년 차 주니어 개발자가 느낀, 성장하기 좋은 근무 환경 (3) | 2023.08.06 |
소중한 공감 감사합니다