우아한 개발계발 블로그

Django Database SSH Tunnel 설정 본문

Programming/아글라이아 연구소 개발 일지

Django Database SSH Tunnel 설정

W00_Ah 2024. 9. 8. 16:07

이론적으로나 개발환경에서 터널링으로 연결하는 것은 꽤 있는 것 같은데,
https://newbiecs.tistory.com/353
django 자체적으로 코드를 이용해 ssh 터널링을 이용해 database로 연결하는 코드에 대한 글은 아직 tistory에 없는 것 같아 글을 올린다.

 

Django SSH tunneling(AWS SSH) , AWS RDS, inspectDB

안녕하세요 오늘은 Local 에서 AWS SSH Tunnel를 연결한 뒤 AWS RDS를 연결하여, inspect DB하는 과정을 설명하겠습니다. 우리들은 평소에 SSH tunnel은 개인 프로젝트를 할 때는 중요하게 여기지 않습니다.

newbiecs.tistory.com

 

AWS는 차갑다.

2024년 2월 부터 aws는 1개 이상의 퍼블릭 IP에 과금을 한다.

이말은 즉슨 프리티어로만 사용하려는 사람들에게는 RDS 와 EC2 에 각각 퍼블릭 액세스 IP를 할당할 수 없음을 의미한다.

 

그렇다고 해서 RDS를 돈내고 써야한다는 것은 아니다.

 

RDS에서 DB 인스턴스를 EC2 인스턴스와 연결해서 사용하면 1개의 퍼블릭 IP로 EC2와 RDS 모두 사용할 수 있다.

EC2에서만 VPC subne을 통해서만 접근가능하다는 단점이있다.

 

그럼 배포단계가아닌 개발 과정에서 RDS에 직접 연결하고 싶으면 어떻게 할까하는 문제가 있는데.

SSH Tunnel 기술이있다.

DataGrip, Pycharm 등에서는 아래와 같이 설정하면 가능하다.

 

이 후에 그럼, Django 도 충분히 SSH 터널링을 통해 개발단계에서 RDS에 접속할 수 있지 않을까 생각을 했다.

 

우선 결과는 성공적이었고 코드는 아래와 같다.

# Settings.py or settings.local.py

# ... other setting lines

# SSH Tunnel Setting
SSH_ADDRESS = env('EC2_ENDPOINT')
SSH_USERNAME = env('EC2_USERNAME')
PATH_TO_SSH_PRIVATE_KEY = env('EC2_SSH_KEY')
LOCAL_DB_ENDPOINT_ON_THE_SERVER = env('DB_HOST')  # RDS_ENDPOINT
LOCAL_DB_PORT_ON_THE_SERVER = int(env('DB_PORT'))

from sshtunnel import SSHTunnelForwarder

# SSH 터널 설정 (EC2 인스턴스를 통해 RDS에 접근)
server = SSHTunnelForwarder(
    (SSH_ADDRESS, 22),  # EC2 주소 및 SSH 포트
    ssh_username=SSH_USERNAME,  # EC2의 SSH 유저명
    ssh_pkey=PATH_TO_SSH_PRIVATE_KEY,  # PEM 키 파일 경로
    remote_bind_address=(LOCAL_DB_ENDPOINT_ON_THE_SERVER, LOCAL_DB_PORT_ON_THE_SERVER),  # RDS's Endpoint and ports
)
server.start()
print(f"Local bind port: {server.local_bind_port}")
# 보통 50000번대로 자동할당 되는 것 같음.

# Database
# <https://docs.djangoproject.com/en/5.0/ref/settings/#databases>

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.postgresql',
        'HOST': 'localhost',
        'PORT': server.local_bind_port,
        'NAME': env('DB_NAME'),
        'USER': env('DB_USER'),
        'PASSWORD': env('DB_PASSWORD'),
    },
}

sshtunnel 패키지 설치

pip install sshtunnel

SSHTunnelForwarder

우선 패키지의 사용자체는 굉장히 직관적이지만 약간의 이해가 필요하다.

SSHTunnelForwarder 클래스를 이용해 SSH 연결을 인스턴스화 하는데, 이때 사용되는 파라미터들을 보면 어렵지않다.

server = SSHTunnelForwarder(
    ('ec2 주소', 22),
    ssh_username='ec2 ssh 접속계정',
    ssh_pkey='ec2 ssh 접속 pem 키 파일 경로',
    remote_bind_address=('ec2에서 접속하는 rds 주소', 'ec2에서 접속하는 rds port 번호'),
)

이후 코드를 실행해보면 ‘Local bind port: 54824’ 라고 나오는데, 우리가 SSHTunnelForwarder를 인스턴스로 만들면 로컬머신에서 localhost:54824 에 ssh가 연결되는 것이다.

그래서 SSHTunnelForwarder.local_bind_port 속성을 통해 바인딩된 포트에 접근할 수 있는데, 이를 Django의 database 설정에 넣어줌으로써 ssh터널링으로 database를 연결하는 것이다.

 

localhost:54824 ⇒ ec2(ec2.xxx.com:22) ⇒ rds(rds.xxx.com:5432) 라고 생각하면 될 것 같다.

 

아싸 돈 아꼈다.

 

settings파일을 나눠서, 배포시에는 prod.py 에서 database설정을 불러오고,

개발시에는 local.py 에서 database 설정을 불러오게 하면 좋을 것 같다.

 

보안적으로 데이터베이스를 직접 노출하지 않으니 좋은 것 같다.

그런데, django가 ssh tunnel을 항상 연결을 열어둬야하니 이것도 문제가 될 수 있지않을까 하는 생각이든다.

 

참고

https://stackoverflow.com/questions/70743246/django-db-with-ssh-tunnel

 

django db with ssh tunnel

Is there a python native way to connect django to a database through an ssh tunnel? I have seen people using ssh port forwarding in the host machine but I would prefer a solution that can be easily

stackoverflow.com

 

Comments