
"로컬 개발 환경에서 AWS Private Subnet에 배치된 RDS(PostgreSQL)와 안전하게 통신하는 방법"
개발 환경에서 RDS는 보안상 Public Access가 불가능한 Private Subnet에 위치합니다. 하지만 로컬에서 DB를 직접 연결해 테스트할 일이 종종 또는 많이 발생합니다.
이 글은 Bastion 서버와 SSH 터널링을 활용해 로컬 ↔ RDS(PostgreSQL) 연결을 성공적으로 구성한 경험을 바탕으로 작성되었습니다.
🖥 Local PC
|
| SSH Tunnel (-L 5433:RDS:5432)
↓
🔗 Bastion EC2 (Public Subnet)
↓
🗄️ RDS PostgreSQL (Private Subnet)
RDS는 VPC 내부 Private Subnet에 있어서 외부에서 직접 접근이 차단됩니다.
Bastion은 Public Subnet에 있으면서 같은 VPC에 연결된 서버이기 때문에, 외부 → Bastion → RDS 경로가 열리는 유일한 방법입니다.
로컬에서 바로 접근하려면 SSH Tunnel로 Bastion을 경유해 RDS까지 안전하게 중계하는 구조가 필요합니다.
publicly_accessible = false즉, Bastion이 RDS로 가는 중계 서버 역할을 합니다.
ssh -i dev-bastion-key.pem \
-L 5433:<RDS-ENDPOINT>:5432 \
ec2-user@<BASTION-IP>
localhost:5433 → Bastion → RDS 5432 포트로 연결됨TCP 22 포트 (SSH) 허용TCP 5432 포트 열려 있어야 함ingress {
description = "PostgreSQL access from Bastion SG"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.bastion_sg.id] # Bastion 서버에서만 허용
}
.pem 키 파일brew install postgresql
psql --version
사전 준비 요약
.pem 키 파일 보유, PostgreSQL 클라이언트 설치ssh -i <YOUR_PEM_KEY>.pem \
-L <LOCAL_PORT>:<RDS_ENDPOINT>:5432 \
ec2-user@<BASTION_PUBLIC_IP>
| 인자 | 설명 |
|---|---|
-i <YOUR_PEM_KEY>.pem | Bastion EC2 접속용 .pem 키 파일 |
-L | SSH 로컬 포트 포워딩 옵션 |
<LOCAL_PORT> | 로컬에서 사용할 포트 (ex: 5433) |
<RDS_ENDPOINT> | AWS RDS PostgreSQL 엔드포인트 주소 |
5432 | PostgreSQL 기본 포트 |
<BASTION_PUBLIC_IP> | Bastion 서버의 퍼블릭 IP 주소 |
✅ 위 명령어를 실행하면 SSH 연결이 수립되며, localhost:<LOCAL_PORT>를 통해 마치 RDS에 직접 접속하듯 사용할 수 있습니다.
SSH 터널링을 활성화한 터미널은 계속 켜둔 상태에서, 다른 터미널이나 도구에서 아래처럼 접속해야 합니다.
CLI (psql)
psql -h localhost -p <LOCAL_PORT> -U <DB_USERNAME> -d <DB_NAME>
예시:
psql -h localhost -p 5433 -U myuser -d mydatabase
GUI 도구 (DBeaver / IntelliJ / pgAdmin 등)
| 항목 | 값 |
|---|---|
| Host | localhost |
| Port | 5433 (또는 위에서 지정한 로컬 포트) |
| Username | <DB_USERNAME> |
| Password | <DB_PASSWORD> (Terraform에서 설정한 값 등) |
| Database | <DB_NAME> |
ssh: connect to host <IP> port 22: Operation timed out.tf 예시:resource "aws_internet_gateway" "this" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-${var.env}-igw"
}
}
resource "aws_route_table" "public" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.this.id
}
tags = {
Name = "${var.project_name}-${var.env}-public-rtb"
}
}
resource "aws_route_table_association" "public_subnet_a" {
subnet_id = var.public_subnet_a_id
route_table_id = aws_route_table.public.id
}
psql: command not foundpsql 명령어는 터널링된 localhost:5433을 통해 RDS에 접속하기 위해 로컬에서 실행됨brew install postgresql
psql --version
psql: connection to server at "localhost", port 5433 failed: Connection refusedssh -L 명령어 실행이 안 됐거나 채널이 종료됨ssh -i dev-bastion-key.pem \
-L 5433:dev-rds.xxxxxxxxxxxx.ap-northeast-2.rds.amazonaws.com:5432 \
ec2-user@<bastion-public-ip>
psql -h localhost -p 5433 -U <username> -d <db_name>
server closed the connection unexpectedlyingress {
description = "PostgreSQL access from Bastion SG"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.bastion_sg.id] # Bastion 서버에서만 허용
}
🔐 이렇게 하면 불필요한 VPC 전체 CIDR 허용 없이, Bastion 인스턴스를 통해서만 RDS에 접근할 수 있어 보안적으로 훨씬 안전합니다.
Windows 사용자의 경우 macOS/Linux처럼 .pem 키를 바로 사용하는 것이 제한적일 수 있습니다.
따라서 아래 두 가지 방법 중 편한 방법을 선택하시면 좋을 거 같습니다 :)
Git Bash가 설치되어 있으면 Linux 명령어를 그대로 사용할 수 있어 간편합니다.
.pem 키 파일 준비bastion-key.pem 파일을 안전한 경로에 저장C:/Users/yourname/.ssh/bastion-key.pemGit Bash에서 아래 명령어 실행:
chmod 600 /c/Users/yourname/.ssh/bastion-key.pem
Windows에선 권한을 직접 조절할 수 없기 때문에 이 단계는 생략해도 동작하지만 보안 경고를 줄이기 위해 수행 추천
ssh -i /c/Users/yourname/.ssh/bastion-key.pem \
-L 5433:<RDS-ENDPOINT>:5432 \
ec2-user@<BASTION_PUBLIC_IP>
연결에 성공하면 Bastion 서버 셸이 뜹니다. 이 상태에서 터널이 유지되고 있으므로, 다른 터미널을 열어서 다음 DB 연결 명령어를 실행하시면 됩니다 :)
psql -h localhost -p 5433 -U <DB_USERNAME> -d <DB_NAME>
[성공 시 화면]

GUI 기반으로 설정하고 접속할 수 있는 가장 일반적인 방법입니다.
.pem → .ppk 변환.pem 파일 선택 (파일 형식 변경 필요).ppk 파일로 저장ec2-user@<BASTION_PUBLIC_IP>22Private key file for authentication: 변환된 .ppk 파일 선택5433<RDS-ENDPOINT>:5432Local 선택 → [Add] 클릭접속에 성공하면 PuTTY 터미널에 Bastion 서버 셸이 뜨고, 터널도 열려있습니다.
| 항목 | 값 |
|---|---|
| Host | localhost |
| Port | 5433 |
| Username | <DB_USERNAME> |
| Password | <DB_PASSWORD> |
| Database | <DB_NAME> |
🚨 .pem 및 .ppk 키 파일은 절대 깃허브나 공유 폴더에 올리면 안 됩니다.
가능한 경우, RDS 접근은 Bastion Security Group을 통해서만 허용하세요.
EC2 대신 [AWS Session Manager]로 Bastion 없이 구성하는 것도 장기적으론 고려해볼 수 있습니다.
| 항목 | 설명 |
|---|---|
| Bastion | Public Subnet에 위치한 중계 EC2 |
| RDS | Private Subnet, public 접근 불가 |
| SSH Tunnel | 로컬 ↔ RDS 간 보안 통신 연결 |
| Key 포인트 | IGW, 보안 그룹, 퍼블릭 라우팅, 로컬 포트 포워딩 |