Kotlin Springboot에서 Datasource 정보 암호화하기
보통 DB connection을 하기위한 정보를 application.properties
혹은 application.yaml
파일에 저장해서 해당 설정으로 커넥션을 생성한다.
spring:
datasource:
url: jdbc:mysql://localhost:3306/test
username: username
password: password
driver-class-name: com.mysql.cj.jdbc.Driver
근데, 또 이런 정보들을 형상관리하기 위해 git을 이용하는데 해당 정보가 그대로 올라간다는 점이다. 그럴 경우, 2가지 문제가 있을 수 있는데
- github에서는 해당 파일에 대한 보안성이 떨어진다고 분석하면서 경고를 낸다. 커밋 또한 제한됨
- public 레포지토리 일 경우, DB 커넥션 정보가 그대로 유출된다. (오남용 가능성)
그러면 어떻게 해야할까? 서칭을 통해서 알아본 방법은 Jasypt 를 이용하는 방법이다. Jasypt 는 Java Simplified Encryption의 약자로서, 자바 영역에서 간단하게 암호화를 제공해준다. 해당 github: https://github.com/ulisesbocchio/jasypt-spring-boot
1. 먼저 Jasypyt 디펜던시 적용
implementation("com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.5")
현재 기준으로 3.0.5 버전이 latest version이다.
2. application 설정에 암호화 방식을 정의한다.
jasypt:
encryptor:
bean: jasyptStringEncryptor # java 빈 이름
algorithm: PBEWithMD5AndDES # 사용 알고리즘
pool-size: 2 # 암호화 요청을 담을 pool 크기 설정 (2 권장)
string-output-type: base64 # 암호화 이후 받을 타입
key-obtention-iterations: 1000 # 암호화를 수행할 반복할 해시 횟수
password: password # 암호화 키 (노출 x)
해당 설정값들에 대한 내용은 공식 깃헙이나 위 설정의 주석을 참고하자.
3. 프로퍼티 변수화
// EncryptProperties.kt
@ConstructorBinding
@ConfigurationProperties(prefix = "jasypt.encryptor")
data class EncryptProperties(
val bean: String,
val algorithm: String,
val poolSize: Int,
val stringOutputType: String,
val keyObtentionIterations: Int,
val password: String
)
보통 application에 설정된 값들은 @Value
로 가져오는 경우가 많은데,
설정값이 많거나 Relaxed Binding을 지원이 필요한 경우 @ConfigurationProperties
를 사용할 수 있다.
@ConfigurationProperties
를 사용하는 방법은 여기에 좀 더 자세하게 정리했다.
4. 빈에 등록할 암호화 설정
// Encryptor.kt
@Configuration
@EnableEncryptableProperties
class Encryptor(val encryptProperties: EncryptProperties) {
@Bean("jasyptStringEncryptor")
fun jasyptEncryptor(): PooledPBEStringEncryptor {
val pooledPBEStringEncryptor = PooledPBEStringEncryptor()
return pooledPBEStringEncryptor.apply {
setAlgorithm(encryptProperties.algorithm)
setPoolSize(encryptProperties.poolSize)
setStringOutputType(encryptProperties.stringOutputType)
setKeyObtentionIterations(encryptProperties.keyObtentionIterations)
setPassword(encryptProperties.password)
}
}
}
일반적인 setter를 적용하면된다.
5. 암호화하여 application 설정에 적용
// applicationTest.kt
@Autowired
@Qualifier(value = "jasyptStringEncryptor")
lateinit var encryptor: PooledPBEStringEncryptor;
@Test
fun getEncrypt() {
println(encryptor.encrypt("jdbc:mysql://localhost:3306/simple"))
}
위와 같은 결과를 얻을 수 있는데, 이를 application.yaml에 적용하면 된다.
적용할 때는,
ENC(${암호화된 데이터})
로 넣어주어야 한다.
spring:
datasource:
url: ENC(VvwNibGd5OiLOsIh8BOZEfrh9y5u1uwoCB9qWL48txOmhQmsHY3TKcCHGzSWgfcA)
username: ...
password: ...
driver-class-name: com.mysql.cj.jdbc.Driver
application.yaml에 있는 Jasypt.encryptor.password는 노출되지 말아야 한다. (노출되면 암호화를 적용하는게 의미가 없어짐)
그렇기에 password 정보는 별도의 파일로 관리하여 .gitignore로 관리하는 것이 좋을 듯 하다.