프로젝트 기술 스택 및 버전

spring boot 2.5.4

gradle 7.1.1

mybatis 

 

프로젝트 초기 구조

DB password, id, jwt 토큰 암호화 키 등 설정파일의 민감한 정보는 당연하지만 github에 공개적으로 올리면 악용될 여지가 있어, 이러한 민감한 정보는 숨기는 것이 중요하다. 

이러한 민감한 정보를 숨기는 방법에는 여러가지가 있지만, 이번에 적용했던 방법은 설정파일을 2개로 나누는 것이다.

 

처음에 이용했던 방식은 다음과 같다. 

  1. 설정파일을 2개로 분리한다.
  2. 민감한 정보가 들어 있는 설정 파일의 경우 gitignore를 통해서 git에 올리지 않는다. 
  3. @PropertySource를 통해 2개의 설정 파일을 읽는다. 

설정 파일 분리

application.yml : 공통 설정

이 프로젝트는 mybatis를 이용하고 있어, 이에 대한 설정을 추가했다. 

(참고로 현재 프로젝트에서는 mybatis외에도 logback에 대한 설정도 되어 있지만 생략했다)

# MySQL
spring:
  datasource:
    hikari:
      connection-test-query : SELECT NOW() FROM dual
      
# mybatis
mybatis:
  configuration:
    cache-enabled : false
    jdbc-type-for-null : NULL
    map-underscore-to-camel-case : true

config.yml : DB 설정 정보

DB 연결 정보, id, password 등 민감한 정보를 담는다.

그리고 여기서 주의할 점이 username으로 적으면 여기서 설정된 계정명이 아니라 컴퓨터의 유저 이름을 읽게 된다. 따라서 username이 아니라 user-name 등으로 바꾸는 것을 권장한다. 

 

내가 의도했던 것은 username과 password를 통해 팀원과 같은 계정을 사용하기를 원했는 데,

이와 같은 문제떄문에 팀원분이 DB를 연결하는 데 애를 먹으셨다. 

이 글을 읽는 다른 분들은 꼭  username이 아니라 다른 이름으로 설정하시길 바란다. 

# MySQL
spring:
  datasource:
    hikari:
      driver-class-name : com.mysql.cj.jdbc.Driver
      jdbc-url: {url}
      user-name : {계정명}
      password : {비밀번호}

 

설정파일 읽기

@Configuration 어노테이션을 통해 Bean을 생성하고, 

@PropertySources 를 통해 설정파일을 읽는다. 

classpath는 resources 폴더까지를 의미하므로 그 아래부터의 설정 파일의 경로를 적으면 Spring에서 설정파일을 읽을 수 있다. 

그리고 @Value를 통해 값을 주입한다. 

@Configuration
@PropertySources({
        @PropertySource( value = "classpath:/properties/config.yaml", ignoreResourceNotFound = true )//db 설정 파일 경로
//        @PropertySource( value = "file:${user.home}/env/dev-config.properties", ignoreResourceNotFound = true) // 배포시 배포 환경의 디렉토리 주소
})

@Getter
public class DefaultGlobalPropertyConfig {
    @Value("${driver-class-name}")
    private String driverClassName;

    @Value("${jdbc-url}")
    private String url;

    @Value("${user-name}")
    private String username;

    @Value("${password}")
    private String password;
}

 

설정정보 이용하기

@Configuration
@EnableTransactionManagement
public class DefaultDBConfig {
    //설정파일을 읽은 클래스를 생성한다.
    @Autowired
    DefaultGlobalPropertyConfig defaultGlobalPropertyConfig;

    @Bean
    @ConfigurationProperties(prefix = "dev.spring.datasource.hikari") //다음의 prefix로 시작하는 설정을 이용해서 hikariCP의 설정 파일을 만듦
    public HikariConfig hikariConfig() {
        return new HikariConfig();
    }

    @Bean
    @Primary
    public DataSource customDataSource() { // 위에서 만든 설정 파일을 이용해서 디비와 연결하는 데이터 소스를 생성
        return DataSourceBuilder
                .create()
                .url(defaultGlobalPropertyConfig.getUrl())
                .driverClassName(defaultGlobalPropertyConfig.getDriverClassName())
                .username(defaultGlobalPropertyConfig.getUsername())
                .password(defaultGlobalPropertyConfig.getPassword())
                .build();
    }

	// 커스텀한 DataSource를 이용해서 MyBatis와 DataSource 연결
    @Bean
    public SqlSessionFactory sqlSessionFactory() throws Exception { //DataSource를 참조하여 MyBatis와 Mysql 서버를 연동시켜준다.
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        factoryBean.setDataSource(customDataSource());
        PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
        factoryBean.setMapperLocations(resolver.getResources("classpath:/mapper/**/*Mapper.xml"));
        //Mapper 파일 위치를 설정. [classpath]: resource 폴더 의미, [/mapper/**/]: mapp 폴더 밑의 모든 폴더를 의미, [*Mapper.xml]: 이름이 Mapper로 끝나고 확장자가 xml인 모든 파일을 의미

        factoryBean.setTypeAliasesPackage("com.naturemobility.seoul.domain");
        factoryBean.setConfiguration(mybatisConfig()); //Mybatis의 설정파일의 위치를 참조
        return factoryBean.getObject();
    }

    @Bean
    @ConfigurationProperties(prefix = "dev.mybatis.configuration")
    public org.apache.ibatis.session.Configuration mybatisConfig() {
        return new org.apache.ibatis.session.Configuration();
    }

    @Bean
    public SqlSessionTemplate sqlSession() throws Exception {
        return new SqlSessionTemplate(sqlSessionFactory());
    }

    @Bean
    public PlatformTransactionManager transactionManager(){
        return new DataSourceTransactionManager(customDataSource());
    }
}

 

문제점

그런데 이와 같이 설정을 했는 데 발생했던 문제는 다음과 같다. 

 

1. 다른 팀원이 DB 설정 정보를 작성하기 어려움 

설정파일을 하나 만들고 임의의 폴더 위치에 둔 다음, @PropertySource에 폴더의 주소를 적기만 하면되기 때문에 설정하기 쉬울 것이라고 생각했었는데, 나름 쉽게 설명드렸음에도 다른 팀원 분이 DB 설정을 하기 힘들어 하셨다... 

git ignore로 인해 파일이 공유되지 않다보니 상대방 입장에서는 이해하기 힘들다는 것을 고려하지 못했다. 

이는 아예 설정이 완료된 프로젝트 전체(config.yml 포함)을 따로 전달해드려서 해결하긴 했지만, 처음 의도대로 username이 개인 PC의 username으로 설정되는 바람에 한 번 더 어려움을 겪어야 했다. 

이 문제도 root 계정에서 개인 PC의 username의 계정을 하나 만드는 것으로 해결했었다. 

 

2. 배포시 설정파일 관리의 어려움

API를 서버에 올릴 때, jenkins와 github web hook를 이용해서 배포를 했었다. 

그런데 git ignore로 인해 설정파일이 빠지게 되면서 빌드 시에 에러가 발생했다. 

이는 약간의 꼼수로 서버에 동일한 설정파일을 만들어두고, jenkins에서 빌드 시에 복사해서 사용하도록 했었다. 

그러나 이렇게 관리를 하면 매번 새로운 설정 정보가 생길 경우, 직접 server에 있는 파일을 수정해야해서 매우 번거로웠다. 

 

이와 같은 문제를 해결하기 위해 spring cloud config 를 적용하게 되었다. 

 

프로젝트 깃허브

https://github.com/nh0317/KW-Whole_In_One-Backend

 

GitHub - nh0317/KW-Whole_In_One-Backend

Contribute to nh0317/KW-Whole_In_One-Backend development by creating an account on GitHub.

github.com

 

참고했던 블로그

https://4urdev.tistory.com/48

 

Spring Boot - (6) 민감 정보 숨기기(DB id, password, etc.)

GitHub 소스 위치 : https://github.com/Simplify-study/SpringBootSample.git 여기까지 개발하고 나서 GitHub에 소스 코드를 공유하려고 보니, Database에 대한 접속 정보가 그대로 노출되어 있습니다. applicat..

4urdev.tistory.com

+ Recent posts