리버스 프록시 기반 분산 아키텍처 구축 - 2
SSH 터널링
by HOON
1
Last updated on Jan. 31, 2025, 6:57 p.m.
안녕하세요. 오늘은 바로 직전에 작성했던 분산 아키텍쳐에서 어떻게 하면 보안성 좀 더 강화하기위해 작업한 내용을 공유 드립니다.
저희는 SSH 터널링을 설정하여 B 서버에서만 접속이 가능하도록 수정 할 예정입니다!
분산 아키텍쳐 구축 👉🏻 이 내용을 먼저 보고 오시면 편해요!
1. 개요
저번 블로그 그림에서 작업 한 내용은 서버의 부하를 줄이기위해 Main 서버, Sub 서버 로 나누었습니다.
앞으로 편의성을 위해 A (Main), B (Sub)
서버로 나누어 설명드리겠습니다.
저는 기존에 A서버와 B서버로 나누는것까진 좋았으나, 한가지 보안상 결점이 존재했습니다.
바로 외부에 노출되다보니, hongjunghoon.com/prometheus
, 혹은 hongjunchoon.com/grafana
로 바로 다이렉트로 접근이 가능했습니다.
물론, 로그인을 해야하지만 이걸론 안전하다 할 수 없죠? 로그인을 우회하는 공격기법(brute force 등)은 손쉽게 할 수 있으니깐요.
그래서 생각한 방법들이 있습니다.
- 서브도메인 grafana.hongjunghoon.com 으로 설정
- url 자체를 난수로 지정 ( hongjunghoon.com/grafana-zxkcl-nklda-123)
- 어차피 fail2ban도 깔려있겠다 fail2ban으로 여러번 시도하는 ip를 ban 하자
우선, 1번은 추가적인 도메인 구매가 필요하여 드랍했습니다.
그리고 3번은 너무 fail2ban에 의존하는것 같고, 시원한 해결책이 아닌것같아 드랍했습니다.
그래서 선택한게 2번입니다. 물론 난수로 지정하면 노출이 된다해도 접근이 쉽지 않겠지만, 언젠가 접근이 되지 않을까?? 싶어서 깊은 고민에 빠졌습니다.
💡근데 생각해보니 저는 신한투자증권 프디아 클라우드 수업에서 SSH 터널링에 대해 학습 했습니다.
지금과 같은 상황에서 B 서버를 private 하게 두고, 로컬에서 SSH 터널링을 이용해서 접근하게되면 B 서버는 완벽하게 외부와 차단되어있는 상태에서
터널링으로 접근해야만 로컬에서 grafana,prometheus, jenkins등에 접근 할 수 있습니다.
2. SSH 터널링
그럼 이제 계획은 세워졌으니, 작업을 해보겠습니다.
우선 큰 그림은 다음과 같습니다.
각 서비스는 통신을 하기 위해 포트번호가 필요합니다. (ex. prometheus -> 9090, grafana -> 3000, jenkins -> 8080)
하지만, 그림에서 보는것과같이 저희는 어디에도 포트번호를 노출하지 않았습니다.
벌써 보안이 강화 된 것 같아서 기분이 좋아요 ㅎ
이게 어떻게 가능할지 제가 작성한 yml 파일을 보면서 설명드리겠습니다.
저는 monitoring.yml, jenkins.yml 로 나뉘어있습니다. 대표적으로 monitoring.yml 만 작업 해보겠습니다.
1.docker-compose-monitoring.yml
version: '3'
services:
prometheus:
image: prom/prometheus:latest
container_name: new_godjango_prometheus
network_mode: "host"
volume: ""
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- #Redirect 삭제
grafana:
image: grafana/grafana:latest
container_name: new_godjango_grafana
network_mode: "host"
volume: ""
environment:
- GF_SERVER_HTTP_ADDR=127.0.0.1
- GF_SERVER_HTTP_PORT=3000
- #Redirect 삭제
depends_on:
- prometheus
보면, 프로메테우스와 그라파나의 설정이 약간 다릅니다.
하지만 큰 틀은 비슷합니다. 기존 hongjunghoon.com/grafana or prometheus 로 접근했으니 저희는 당연히 redirect가 정의되어있어요.
이제 저희는 서비스를 로컬로 띄울것이기때문에 redirect가 되면 안됩니다.
따라서 기존에 정의해줬던 redirect 구문은 다 삭제가 된 것을 확인 할 수 있어요.
이 상태로 docker를 띄우고, 실제 3000번을 잡아보면
$ netstat -tulnp | grep 3000
(Not all processes could be identified, non-owned process info
will not be shown, you would have to be root to see it all.)
tcp 0 0 127.0.0.1:3000 0.0.0.0:* LISTEN
좋습니다. 저희가 설정한 127.0.0.1:3000 으로 grafana가 실행되고있네요!
그럼 이제 접속해볼까요? 여기서 SSH 터널링 방법이 나옵니다.
ssh -i Key-2.pem -L 3000:127.0.0.1:3000 ubuntu-name@<B-ip>
명령어에 대해서 설명을 조금 드리자면, ssh -i ~.pem 은 lightsail 인스턴스 키값입니다.
-
-L 3000:127.0.0.1:3000 : 로컬(내 PC)의 3000번 포트를 원격 서버(B-ip)의 127.0.0.1:3000 포트와 연결
-
결과적으로 로컬 브라우저에서 http://localhost:3000 에 접속하면, 원격 서버의 127.0.0.1:3000으로 요청이 전달되어 애플리케이션(Grafana, Jenkins 등)에 접근할 수 있게 됩니다.
접속이 잘 됐다면, 이제 localhost:3000 으로 접속해볼까요??
성공이네요! 이제 127.0.0.1:3000 으로 grafana로 접속이 가능합니다. 그럼 외부에서는 접속이 안되겠죠?
이렇게 SSH 터널링을 적용해서 보안을 강화해봤습니다!!
3. exporter는요?
생각해보니 저희 A 서버에는 nginx, postgres exporter들이 있었어요, 얘네들의 역할은 서버에서 nginx, postgres 관련 데이터를 수집하여 B서버의 prometheus가 데이터를 요청하면 보내는 역할을 하고 있었어요.
각각 포트번호가 1000,2000이라 가정해볼게요.
얘네는 B서버에서 요청이 올때마다 A서버의 1000,2000번으로 통신을 해야하니깐 inbound에 남겨둬야겠죠?
저는 간단하게 설정했습니다.
B서버의 public IP 주소에서의 요청만 수용하면 됩니다.
Lightsail - Instance - Networking 탭에서
그럼 B 서버에서 해당 포트로 요청이 들어와야 A서버에 접근이 가능하겠죠??
SSH 터널링은 여기까지 작성하겠습니다.
감사합니다.
Leave a Comment: