SSH 사용으로 DB 원격 터널링하기

lsj8367·2021년 3월 17일
0

@WebListener 어노테이션

서블릿 3.0 이상을 사용하는 스프링 프레임워크에서 가능한 기능이다.

WebListener이라는 어노테이션을 사용해서 쉽게 터널링을 할 수 있다.

기본 MariaDB, Mysql, Oracle 또는 Mongodb등 어떠한 데이터베이스에 접속하던지 간에 해당 어노테이션을 잘 활용하면 같은 모양으로 터널링이 가능하다.

서블릿 3.0 이상이 지원되는 환경을 구성하는게 가장 중요하다.

WebListener는 스프링에서 정의한 Listener의 종류이다.

스프링에서 정의한 웹 어플리케이션 구조를 먼저 살펴보면,

  1. 서블릿(Servlet) : 외부 클라이언트 요청에 대한 내용 수행
  2. 필터(Filter) : 요청 처리 전 또는 후에 해야할 일을 수행
  3. 리스너(Listener) : 특정 상태(조건)에 놓일 때 작업을 수행
  1. 서블릿 컨텍스트 영역에서의 시작, 종료시에 대한 내용을 정의 (ServletContext 객체가 생성 또는 소멸되기 전)

  2. 외부 클라이언트의 요청이 들어오거나 서버에서 응답을 수행할 때 발생하는 내용을 정의 (ServletRequet 객체가 생성 또는 소멸 하였을 때)

  3. ServletRequet의 객체에 등록, 수정 및 삭제 행위가 수행할 때

여기서 리스너의 1번 개념을 적용해서 공통적으로 데이터베이스에 대한 터널링이 가능 하다.

		<!-- https://mvnrepository.com/artifact/com.jcraft/jsch -->
		<!-- SSH 포트연결 라이브러리 -->
		<dependency>
		    <groupId>com.jcraft</groupId>
		    <artifactId>jsch</artifactId>
		    <version>0.1.55</version>
		</dependency>
		
		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
		<!-- @WebListener 사용하기 위한 라이브러리 -->
		<dependency>
		    <groupId>javax.servlet</groupId>
		    <artifactId>javax.servlet-api</artifactId>
		    <version>4.0.1</version>
		    <scope>provided</scope>
		</dependency>

이것들을 pom.xml에 우선 추가를 해준뒤에 클래스를 하나 생성하는데 그 클래스에서는
ServletContextListener를 implements 해준다.

ServletContextListener란?

    - 웹 어플리케이션이 시작되거나 종료될 때 호출할 메서드를 정의한 인터페이스.
    - public void contextInitialized(ServletContextEvent sce) : 웹어플리케이션을 초기화할 때 호출
    - public void contextDestroyed(ServletContextEvent sce) : 웹 어플리케이션을 종료할 때 호출.

생성한 클래스에 @WebListener 어노테이션을 붙여주고 ServletContextListener 인터페이스를 상속받는다.

    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    @WebListener
    public class DataBaseListener implements ServletContextListener{
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
        }
        @Override
        public void contextInitialized(ServletContextEvent sce) {
        }
    }

이렇게 생성하게되면 ServletContext가 생성될때 해당내용이 수행된다.

아래의 방법이 터널링하는 방법이다.
처음에 pom.xml에 등록한 JSCH를 활용하여 ssh 접속을 설정한다.

SSH 연결 클래스

import java.util.Properties

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.Session;

public class SSHConnector {
    private final static String remoteHost = "192.168.0.1";
    private final static String user = "admin";
    private final static String password = "admin";
    private final static int port = 1234;
    
    private Session session;
    
    public void closeSSH() {
    	session.disconnect();
    }
    
    public SSHConnector() {
      try {
        JSch jSch = new JSch();
        session = jSch.getSession(user, remoteHost, port);
        session.setPassword(password);
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        session.setConfig(config);
        session.connect();
        session.setPortForwardingL(port, remoteHost, 3306);
        System.out.println("연결성공");
      }catch (Exception e){
          e.printStackTrace();
          }
    }
}

SSH연결 구현 클래스

@WebListener
public class SSHContextListener implements ServletContextListener {
	private SSHConnector sshConnector;

	@Override
	public void contextInitialized(ServletContextEvent sce) {
		System.out.println("시작!");
		try {
			sshConnector = new SSHConnector();
			System.out.println("끝!");
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	public void contextDestroyed(ServletContextEvent sce) {
		System.out.println("끝!");
		sshConnector.closeSSH();
	}
}

먼저 첫번째 포트번호는 ssh로 접속할 포트번호이다

그리고 가상포트는 말 그대로 가상포트, 아무숫자나 써 주어도 상관없는 포트이다.

-> 데이터베이스 서버에서 충돌나지 않도록 주의!!

사용할데이터베이스포트 는 mysql, oracle 또는 몽고db가 열어준 포트를 의미한다.

실제 데이터베이스에서 사용중인 포트가 3306이라고 하자.

그리고 가상포트를 1234라고 가정을 한다.

만약 1234로 접속을 시도하는 행위를 발견하면 알아서 스스로 127.0.0.1:3306 으로 접속 행위를 돌려준다.

여기까지 하였다면 내가 접속할 Mysql, 오라클, 몽고db의 접속 주소를 아래처럼 바꾸어 주어야 한다.

기존 접속방식은 그대로두고 접속할 아이피와 포트만 바꾸면 된다.

mybatis-config.xml

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close" >
  <property name="driverClassName" value="com.mysql.jdbc.Driver" />
  <property name="url" value="jdbc:mysql://127.0.0.1:1234/databaseName" />
  <property name="username" value="username" />
  <property name="password" value="password" />
  <property name="validationQuery" value="SELECT 1 FROM DUAL" />
  <property name="testWhileIdle" value="true" />
</bean>

이렇게 한다면 1234를 요청하는데 위에서 설정해준 터널링 처리로 인해 SSH포트를 연결한 3306의 mysql에서 데이터를 가져와서 데이터를 뿌려주게 된다.

web.xml에서 사용할 경우

<listener>
	<listener-class>SSHContextListener클래스의 경로</listener-class>
</listener>
profile
기록을 많이 하자!💻

0개의 댓글