[JAVA - spring] jsch를 활용한 ssh db 커넥션

Devcury·2022년 12월 18일
3

JAVA-spring

목록 보기
1/1
post-custom-banner

먼저 mvn repository에서 JSch라이브러리를 받는다.
JSch 라이브러리 바로가기

dependencies {

	...
    
    // https://mvnrepository.com/artifact/com.jcraft/jsch
    implementation 'com.jcraft:jsch:0.1.55'

}

필자는 gradle을 활용했으므로 위처럼 입력.
maven이나 jar를 이용하신다면, 그에 맞게 설정하시면 됨.

SshTunnelingInitializer.java

package der.ssh;

import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import javax.annotation.PreDestroy;
import java.util.Properties;

@Slf4j
@Profile("prod")
@Component
@ConfigurationProperties(prefix = "ssh")
@Validated
@Setter
public class SshTunnelingInitializer {

    private String host;
    private String user;
    private int sshPort;
    private String privateKey;
    private int databasePort;

    private Session session;

    @PreDestroy
    public void closeSSH() {
        if (session != null && session.isConnected())
            session.disconnect();
    }

    public Integer buildSshConnection() {

        Integer forwardedPort = null;

        try {
            log.info("{}@{}:{}:{} with privateKey",user, host, sshPort, databasePort);

            log.info("start ssh tunneling..");
            JSch jSch = new JSch();

            log.info("creating ssh session");

            jSch.addIdentity(privateKey);  // 개인키

            session = jSch.getSession(user, host, sshPort);  // 세션 설정
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            log.info("complete creating ssh session");

            log.info("start connecting ssh connection");
            session.connect();  // ssh 연결
            log.info("success connecting ssh connection ");

            // 로컬pc의 남는 포트 하나와 원격 접속한 pc의 db포트 연결
            log.info("start forwarding");
            forwardedPort = session.setPortForwardingL(33306, "localhost", databasePort);
            log.info("successfully connected to database");

        } catch (JSchException e){
            this.closeSSH();
            e.printStackTrace();
            log.error("fail to make ssh tunneling : {}", e.getMessage());
        }

        return forwardedPort;
    }
}

SshDataSourceConfig.java

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.Profile;

import javax.sql.DataSource;

@Slf4j
@Profile("prod")
@Configuration
@RequiredArgsConstructor
public class SshDataSourceConfig {

    private final SshTunnelingInitializer initializer;

    @Bean("dataSource")
    @Primary
    public DataSource dataSource(DataSourceProperties properties) {

        Integer forwardedPort = initializer.buildSshConnection();  // ssh 연결 및 터널링 설정
        String url = properties.getUrl().replace("[forwardedPort]", Integer.toString(forwardedPort));
        log.info(url);
        return DataSourceBuilder.create()
                .url(url)
                .username(properties.getUsername())
                .password(properties.getPassword())
                .driverClassName(properties.getDriverClassName())
                .build();
    }

}

위 두파일을 생성하고, profile에 properties에 맞게 입력한다. properties가 따로 없으면 삭제. 필자의 properties는 prod이다.

해당 properties에

spring.datasource.driverClassName={DB 드라이버}
spring.datasource.url=jdbc:{사용할 DB 드라이버}//127.0.0.1:33306/{DB명(스키마)}

spring.datasource.username={DB USER}
spring.datasource.password={DB Password}

ssh.host={접속할 ssh ip}
ssh.ssh_port={ssh 포트}
ssh.user={user}
ssh.private_key={ssh 비밀키 경로}
ssh.database_port={ssh 접속환경에서 활용할 DB}

위 내용을 입력한다.
여기서 database url에 해당 되는 포트는

위의 포트와 일치해야한다. (proxy원리이기 때문 33306 -> 3306)

다음은 ssh 키 생성이 필요하다.

ssh-keygen -f id_rsa -m PEM

입력한 후 키 생성을 한다.

다음 생성 된 ssh 공개키를 서버의 유저 -> .ssh파일 -> authorized_keys에 입력 (자세한 내용은 공개키 비밀키를 통한 서버 접속을 찾아보면 된다.)

일반적인 open ssh rsa 키 생성으로는 invalid 키라고 에러를 만들기 때문에 꼭 위의 명령어를 입력하여 새로운 키를 만들고 활용하도록 하자.

profile
잘하고 싶은 개발자
post-custom-banner

0개의 댓글