본문 바로가기

Backend/Study

[DevOps] AWS EC2와 RDS 연결 설정 가이드

반응형

0. 개요

  1. AWS EC2와 RDS 연결 설정 가이드 
  2. 설계 개요: VPC·서브넷·보안 그룹 전략
    • 2-1. 토폴로지 결정(프라이빗 RDS, 퍼블릭 최소화)
    • 2-2. 라우팅·NACL·엔드포인트 고려
  3. RDS 인스턴스 준비하기
    • 3-1. 서브넷 그룹·파라미터 그룹·옵션 그룹
    • 3-2. 엔진별 포트와 엔드포인트
  4. EC2 인스턴스 준비하기
    • 보안 그룹·IAM 역할(SSM)·유저 데이터
  5. 보안 그룹 연결 규칙 설정
    • 5-1. RDS 인바운드 소스를 EC2 SG로 제한
    • 5-2. NACL·퍼블릭 접근 주의사항
  6. 연결 테스트와 클라이언트 설치
    • 6-1. MySQL·PostgreSQL·SQL Server 실습
    • 6-2. telnet/nc로 포트 진단
  7. 애플리케이션 코드에서의 연결
    • Python·Node.js·Java 연결 예시
  8. 고급 보안: IAM DB 인증과 SSL
    • 8-1. 토큰 발급·CA 번들 적용
    • 8-2. 파라미터로 SSL 강제
  9. 운영 가드레일과 비용 팁
  10. Terraform으로 한 번에 구성
  11. 자주 발생하는 오류와 해결
  12. 체크리스트(도입 전/운영 중)
  13. 결론 요약
  14. FAQ

1. AWS EC2와 RDS 연결 설정 가이드

이 문서는 같은 VPC 내 EC2에서 프라이빗 서브넷의 RDS로 안전하게 접속하는 표준 패턴을 단계별로 안내합니다. 네트워킹·보안 그룹·클라이언트 설정·SSL·IAM DB 인증·운영 가드레일까지 포함하므로, 실무에서 바로 복붙해 적용할 수 있습니다.

2. 설계 개요: VPC·서브넷·보안 그룹 전략

2-1. 토폴로지 결정(프라이빗 RDS, 퍼블릭 최소화)

  • 권장: RDS는 프라이빗 서브넷에 배치하고 Publicly accessible = No. EC2는 퍼블릭 또는 프라이빗 어디에 있어도 무방하지만, 인터넷 노출 최소화를 권장합니다.
  • 외부에서 DB 도구로 점검이 필요하면 일시적 윈도우만 열고, 소스 IP 고정·시간제한·SSL 강제를 함께 적용하세요.
  • 운영 편의: 배스천 대신 SSM Session Manager로 포트 포워딩을 쓰면 SSH 포트를 열 필요가 없어 보안과 감사를 동시에 확보할 수 있습니다.

2-2. 라우팅·NACL·엔드포인트 고려

  • 같은 VPC라면 서브넷 간 라우팅은 기본적으로 가능하지만, 피어링 또는 공유 VPC(리소스 액세스 매니저)라면 라우트 테이블과 SG 범위를 재확인하세요.
  • NACL을 커스텀했다면 데이터베이스 포트와 에페메럴 포트(1024~65535) 양방향 허용이 필요합니다.
  • RDS는 호스트명 기반 엔드포인트로 접근합니다. Aurora는 라이터/리더 엔드포인트가 분리되며, 읽기 전용 트래픽은 리더로 분리하면 효율적입니다.

3. RDS 인스턴스 준비하기

3-1. 서브넷 그룹·파라미터 그룹·옵션 그룹

  • 서브넷 그룹: 서로 다른 가용 영역의 프라이빗 서브넷 최소 2개 포함(멀티 AZ를 고려한 설계).
  • 파라미터 그룹: PostgreSQL은 rds.force_ssl=1, MySQL 계열은 require_secure_transport(엔진 버전에 따라 옵션명이 다를 수 있음)으로 SSL을 강제할 수 있습니다.
  • 옵션 그룹: Oracle/SQL Server 등의 부가 기능(TDE 등)에 필요합니다.

3-2. 엔진별 포트와 엔드포인트

# RDS 엔드포인트 확인 예시
aws rds describe-db-instances \
  --db-instance-identifier myapp-db \
  --query "DBInstances[0].{Endpoint:Endpoint.Address,Port:Endpoint.Port,Engine:Engine}" \
  --output table
# 기본 포트: MySQL 3306, PostgreSQL 5432, SQL Server 1433, Oracle 1521

4. EC2 인스턴스 준비하기

- 보안 그룹·IAM 역할(SSM)·유저 데이터

  • EC2 보안 그룹: 인바운드는 최소(예: 80/443), 아웃바운드는 기본 허용으로 DB에 나가는 트래픽을 허용합니다.
  • IAM 역할: AmazonSSMManagedInstanceCore 정책을 부여하면 배스천 없이 SSM으로 접속 가능하며 감사 로그가 남습니다.
  • 유저 데이터(필수 도구 설치):
#!/bin/bash
set -eux
apt-get update
apt-get install -y postgresql-client mysql-client telnet netcat-openbsd
echo 'export DB_HOST=<your-rds-endpoint>' >> /etc/profile.d/db.sh

5. 보안 그룹 연결 규칙 설정

5-1. RDS 인바운드 소스를 EC2 SG로 제한

# EC2 보안 그룹(예시)
aws ec2 create-security-group --group-name ec2-sg --description "App EC2" --vpc-id <VPC_ID>

# RDS 보안 그룹(예시)

aws ec2 create-security-group --group-name rds-sg --description "DB inbound" --vpc-id 

# RDS SG 인바운드: 소스를 'EC2 SG'로 지정(예: PostgreSQL 5432)

aws ec2 authorize-security-group-ingress 
--group-id  
--protocol tcp --port 5432 
--source-group 
  • 보안 그룹을 SG→SG 참조로 구성하면 EC2의 IP가 바뀌어도 자동 반영되어 운영이 단순해집니다.

5-2. NACL·퍼블릭 접근 주의사항

  • NACL이 엄격하면 에페메럴 포트가 막혀 초기 핸드셰이크 후 연결이 끊길 수 있습니다. 허용 규칙을 점검하세요.
  • 퍼블릭 접근을 켜야 한다면 소스 IP를 엄격히 제한하고, 짧은 기간만 열어두며 SSL을 필수로 적용하세요.

6. 연결 테스트와 클라이언트 설치

6-1. MySQL·PostgreSQL·SQL Server 실습

# 포트 오픈 여부 확인(Connected가 뜨면 포트 레벨은 통과)
nc -vz myapp-mysql.XXXX.ap-northeast-2.rds.amazonaws.com 3306
nc -vz myapp-pg.XXXX.ap-northeast-2.rds.amazonaws.com    5432

# MySQL 접속

mysql -h myapp-mysql.XXXX.ap-northeast-2.rds.amazonaws.com -u admin -p

# PostgreSQL 접속(SSL 요구)

psql "host=myapp-pg.XXXX.ap-northeast-2.rds.amazonaws.com port=5432 dbname=app user=appuser sslmode=require"

# SQL Server (Ubuntu)

sqlcmd -S myapp-sql.XXXX.ap-northeast-2.rds.amazonaws.com,1433 -U admin -P '******'

6-2. telnet/nc로 포트 진단

포트가 닫혀 있으면 보안 그룹/NACL/라우팅 문제일 확률이 높고, 포트가 열리는데 연결 실패라면 자격 증명·SSL·파라미터 설정 이슈를 우선 의심하세요.

7. 애플리케이션 코드에서의 연결

- Python·Node.js·Java 연결 예시

# Python (psycopg2)
import os, psycopg2
conn = psycopg2.connect(
  host=os.environ["DB_HOST"],
  port=5432, dbname="app",
  user="appuser", password=os.environ["DB_PASS"],
  sslmode="require"
)

# Python (PyMySQL)

import os, pymysql
conn = pymysql.connect(
host=os.environ["DB_HOST"], user="admin",
password=os.environ["DB_PASS"], database="app",
port=3306, ssl={"ssl":{}}
)

# Node.js (pg)

const { Pool } = require('pg');
const pool = new Pool({
host: process.env.DB_HOST, user: 'appuser',
password: process.env.DB_PASS, database: 'app',
port: 5432, ssl: { rejectUnauthorized: true }
});

# Java (JDBC, PostgreSQL)

String url = "jdbc:postgresql://myapp-pg...:5432/app?sslmode=require";
Connection conn = DriverManager.getConnection(url, "appuser", System.getenv("DB_PASS"));
  • 비밀번호는 Secrets Manager/Parameter Store에서 주입하고, 연결 풀은 최소/최대 값을 트래픽 패턴에 맞춰 설정하세요.

8. 고급 보안: IAM DB 인증과 SSL

8-1. 토큰 발급·CA 번들 적용

  • IAM DB 인증(MySQL·PostgreSQL): 비밀번호 대신 15분 내외 유효한 토큰을 사용합니다(클라이언트에 시간 동기화 필요).
# PostgreSQL용 IAM 인증 토큰 발급 예시
aws rds generate-db-auth-token \
  --hostname myapp-pg.XXXX.ap-northeast-2.rds.amazonaws.com \
  --port 5432 --region ap-northeast-2 --username appuser
  • SSL: 최신 RDS CA 번들을 클라이언트에 설치하고, PostgreSQL은 sslmode=require 또는 verify-full, MySQL은 --ssl-mode=REQUIRED를 권장합니다.

8-2. 파라미터로 SSL 강제

  • PostgreSQL: 파라미터 그룹에 rds.force_ssl=1 설정(적용을 위해 재부팅 필요).
  • MySQL 계열: 엔진 버전에 따라 require_secure_transport=ON 또는 유사 옵션을 사용합니다.

9. 운영 가드레일과 비용 팁

  • Secrets Manager: 자격 증명 저장·자동 로테이션. 애플리케이션은 환경 변수나 SDK로 주입.
  • 모니터링: CloudWatch로 커넥션 수, CPU/메모리, 스토리지·IOPS, 접속 실패율 경보를 구성합니다.
  • 백업/복구 훈련: 스냅샷 보존 주기·포인트 인 타임 리커버리 절차를 분기별로 리허설하세요.
  • 비용: 개발/스테이징은 자동 중지 스케줄과 작은 인스턴스, 성능 인사이트는 문제 분석 구간에 한정해 사용합니다.

10.Terraform으로 한 번에 구성

# VPC/서브넷은 미리 존재한다고 가정
resource "aws_security_group" "ec2" {
  name        = "ec2-sg"
  description = "App EC2"
  vpc_id      = var.vpc_id
}

resource "aws_security_group" "rds" {
name        = "rds-sg"
description = "DB inbound from EC2 SG"
vpc_id      = var.vpc_id
ingress {
protocol        = "tcp"
from_port       = 5432
to_port         = 5432
security_groups = [aws_security_group.ec2.id]
}
egress {
from_port = 0; to_port = 0; protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}

resource "aws_db_subnet_group" "db" {
name       = "db-subnets"
subnet_ids = var.private_subnet_ids
}

resource "aws_db_instance" "pg" {
identifier             = "myapp-pg"
engine                 = "postgres"
engine_version         = "15"
instance_class         = "db.t4g.micro"
allocated_storage      = 20
db_subnet_group_name   = aws_db_subnet_group.db.name
vpc_security_group_ids = [aws_security_group.rds.id]
username               = "appuser"
password               = var.db_password
publicly_accessible    = false
backup_retention_period= 7
storage_encrypted      = true
skip_final_snapshot    = true
}

11. 자주 발생하는 오류와 해결

  • 연결 타임아웃: RDS SG 인바운드에 EC2 SG가 등록되어 있는지, 라우팅/NACL이 에페메럴 포트를 허용하는지 확인하세요.
  • 인증 실패: 사용자/DB 이름 혼동(특히 PostgreSQL 역할), IAM 토큰 만료, 특수문자 이스케이프 문제를 점검하세요.
  • SSL 오류: 최신 RDS CA 번들 적용 여부, sslmode 또는 --ssl-mode 옵션 일치 여부, 파라미터 그룹의 SSL 강제 설정을 확인하세요.
  • 커넥션 폭주: 연결 풀 최소/최대 값을 트래픽에 맞게 조정하고, 읽기 부하는 리더 엔드포인트로 분리하세요(Aurora).

12. 체크리스트(도입 전/운영 중)

도입 전

  • EC2와 RDS를 같은 VPC에 배치(또는 피어링/공유 VPC 라우팅 확인).
  • RDS는 프라이빗 서브넷, Publicly accessible = No.
  • RDS SG 인바운드: 소스 = EC2 SG(포트 5432/3306/1433 등).
  • EC2에 SSM 역할 부여, 보안 업데이트 자동화.
  • Secrets Manager 도입 및 초기 비밀번호 회전.
  • 파라미터 그룹으로 SSL 강제 설정 검토.

운영 중

  • CloudWatch 알람: 커넥션 수, CPU/메모리, 스토리지, IOPS, 접속 실패율.
  • 슬로 쿼리 로깅과 실행 계획 점검, 인덱스 유지.
  • 백업/스냅샷 보존 주기 준수, 정기 복구 테스트.
  • 정기 점검: 보안 그룹에 0.0.0.0/0 인바운드가 없는지 탐지.
  • 비용 점검: 스토리지 자동 확장, 성능 인사이트 사용 구간 관리.

13. 결론 요약

핵심은 프라이빗 RDS와 최소 권한 보안 그룹, SG→SG 참조를 통한 안정적 연결, SSL 및 IAM DB 인증으로 비밀을 코드 밖에 두는 것입니다. 여기에 SSM 기반 운영과 모니터링·백업·비용 가드레일을 결합하면, 안전하고 반복 가능한 표준 구성이 완성됩니다.

14. FAQ

Q1. 퍼블릭 액세스를 켜면 설정이 쉬워지나요?

A1. 일시적으로는 그렇지만 보안 리스크가 큽니다. 프라이빗 배치 + SSM 포트 포워딩이 권장됩니다.

Q2. 배스천 호스트가 꼭 필요합니까?

A2. 필수는 아닙니다. SSM을 쓰면 SSH 포트 개방 없이 접속·감사가 가능하고 운영이 단순해집니다.

Q3. 어떤 엔진을 선택할까요(MySQL vs PostgreSQL)?

A3. 팀의 기존 역량과 필요한 기능을 기준으로 선택하세요. 어떤 엔진이든 SSL·비밀 관리·풀링만 표준화하면 운영 난이도는 비슷합니다.

반응형