요즘 회사 다니면서 정작 손 가는 기술적인 실험을 못 하니까, 사이드 프로젝트에서라도 갈증을 풀어보자고 파고들었다. RDS로 DB만 띄워놨는데, 테이블도 거의 없는데도 슬금슬금 3만 원씩 나가더라. 데이터도 거의 없는데 이건 아니다 싶어서, “그럼 EC2에 DB 직접 올려서 굴려보자”로 방향을 틀었다. 예전에 대충 퍼블릭 열어두고 쓰다 봇들 스캔에 긁히는 걸 본 뒤로는, 이번엔 보안부터 단단히.
간략한 흐름은 아래와 같다
- DB는 절대 퍼블릭 금지.
- Elastic IP도 안 달고, VPC 안에서만 살게 한다. 비용도 깎이고, 공격면도 줄어든다.
- BE → DB는 오직 Private IP.
- 같은 VPC/서브넷에서만 붙인다. application.yml에는 DB의 프라이빗 IP만 적는다.
- 운영툴 접속은 SSH 터널링만.
- DataGrip 같은 클라이언트는 BE를 점프 서버로 삼는다. DB 3306은 안 보이게.
최소 아키텍처를 머릿속에 그려보면 아래와 같다.
[Client] ──HTTPS──▶ [EC2: BE (Public IP 有)]
│
├─(VPC 내부, 3306)─▶ [EC2: DB (Private IP 仅)]
│
(운영툴) DataGrip ──SSH Tunnel(22)──▶[BE]──(Private 3306)──▶[DB]
핵심은 “바깥에서 DB로 가는 길은 없다”. 바깥→BE(22/80/443), BE→DB(3306, 프라이빗)만 존재.
보안그룹은 이렇게 딱 자른다
SG-BE
- Inbound
- 22/TCP: 내 노트북 공인 IP/32 딱 하나만
- 80, 443/TCP: 0.0.0.0/0 (또는 ALB SG로 제한)
- (가능하면) 8080/TCP 외부 미개방. Nginx/ALB 뒤에 숨긴다.
- Outbound
- 기본 All 허용(필요하면 축소)
SG-DB
- Inbound
- 3306/TCP: Source = SG-BE (보안그룹 간 참조)
- Outbound
- 기본 All 허용(패치/백업 고려. 필요 시 축소)
왜 이렇게? SG→SG 참조로 해두면 BE를 교체하거나 오토스케일해도 DB 접근 규칙이 자동으로 따라온다. 그리고 3306을 퍼블릭에 안 내놓으니 스캐닝·사전대입 봇이 접근할 구멍 자체가 없다.
애플리케이션(Spring Boot) 설정
spring:
datasource:
url: jdbc:mysql://10.0.1.23:3306/mydb?characterEncoding=UTF-8&serverTimezone=UTC
username: app
password: strongPW!
DB 호스트는 프라이빗 IP. 비밀번호 같은 건 환경변수나 SSM/Secrets Manager로 뺀다. 커넥션풀(HikariCP) 최소/최대도 프로젝트 규모에 맞춰 잡아둔다.
DataGrip은 BE를 점프로 쓴다(SSH 터널)
- SSH/Proxy
- Use SSH tunnel: ON
- Host: <BE 퍼블릭 IP>
- Port: 22
- User: ubuntu(Ubuntu) / ec2-user(Amazon Linux)
- Auth: 키페어 .pem, Keep alive 체크
- General
- Host: <DB 프라이빗 IP> (예: 10.0.1.23)
- Port: 3306
- DB: mydb
- User/PW: app / strongPW!
그리고 SG 전제는 다시 확인:
- SG-DB 인바운드 3306 ← Source = SG-BE
- SG-BE 인바운드 22 ← 내 공인 IP
이런식으로 설정을 완료하면 DB서버로 연결하지 않고도 터널링을 통해 충분히 DB EC2서버에서 DDL,DML을 작성할 수있다... 후... 네트워크 지식이없으니... 이것도 몰랐다... 다른 분들에게도 도움이 되길