diff --git a/build.gradle b/build.gradle index a633bfd9..fa6028cd 100644 --- a/build.gradle +++ b/build.gradle @@ -105,6 +105,10 @@ dependencies { // discord web hook implementation('com.github.napstr:logback-discord-appender:1.0.0') + + // ssh 터널링 세팅 + implementation 'com.github.mwiede:jsch:0.2.17' + annotationProcessor "org.springframework.boot:spring-boot-configuration-processor" } tasks.named('test') { diff --git a/src/main/java/synk/meeteam/infra/rds/SshDataSourceConfig.java b/src/main/java/synk/meeteam/infra/rds/SshDataSourceConfig.java new file mode 100644 index 00000000..711d2943 --- /dev/null +++ b/src/main/java/synk/meeteam/infra/rds/SshDataSourceConfig.java @@ -0,0 +1,36 @@ +package synk.meeteam.infra.rds; + +import javax.sql.DataSource; +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; + +@Slf4j +@Profile("stg") +@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(); + } + +} diff --git a/src/main/java/synk/meeteam/infra/rds/SshTunnelingInitializer.java b/src/main/java/synk/meeteam/infra/rds/SshTunnelingInitializer.java new file mode 100644 index 00000000..05cc94b9 --- /dev/null +++ b/src/main/java/synk/meeteam/infra/rds/SshTunnelingInitializer.java @@ -0,0 +1,82 @@ +package synk.meeteam.infra.rds; + +import static java.lang.System.exit; + +import com.jcraft.jsch.JSch; +import com.jcraft.jsch.Session; +import jakarta.annotation.PreDestroy; +import jakarta.validation.constraints.NotNull; +import java.util.Properties; +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; + +@Slf4j +@Profile("stg") +@Component +@ConfigurationProperties(prefix = "ssh") +@Validated +@Setter +public class SshTunnelingInitializer { + + @NotNull + private String remoteJumpHost; + @NotNull + private String user; + @NotNull + private int sshPort; + @NotNull + private String privateKey; + @NotNull + private String databaseUrl; + @NotNull + private int databasePort; + + private Session session; + + @PreDestroy + public void closeSSH() { + if (session.isConnected()) + session.disconnect(); + } + + public Integer buildSshConnection() { + + Integer forwardedPort = null; + + try { + log.info("{}@{}:{}:{} with privateKey",user, remoteJumpHost, sshPort, databasePort); + + log.info("start ssh tunneling.."); + JSch jSch = new JSch(); + + log.info("creating ssh session"); + jSch.addIdentity(privateKey); // 개인키 + session = jSch.getSession(user, remoteJumpHost, 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(0, databaseUrl, databasePort); + log.info("successfully connected to database"); + + } catch (Exception e){ + log.error("fail to make ssh tunneling"); + this.closeSSH(); + e.printStackTrace(); + exit(1); + } + + return forwardedPort; + } +} diff --git a/src/main/resources/logback-spring.xml b/src/main/resources/logback-spring.xml index 99867d0e..f5b20e9b 100644 --- a/src/main/resources/logback-spring.xml +++ b/src/main/resources/logback-spring.xml @@ -16,4 +16,10 @@ + + + + + + \ No newline at end of file