Jasypt 를 사용하게 된 배경이자, 해당 라이브러리를 사용하는 목적은 yml 파일안의 중요한 정보에 대한 암호화이다.
AWS EC2 인스턴스에 Github을 연동하여 스프링부트 프로젝트를 만드는 개인 프로젝트 진행하는 도중 데이터베이스를 연동하는 과정에서 DataSource를 만들기 위해 yml 파일에 나의 데이터베이스 정보들이 들어가게 되었다.
그리고 그 정보가 Github에 노출되는 상황이 되어 yml 파일 내 해당 정보들에 대해서 암호화하는 과정이 필요하게 되어 해당 라이브러리를 사용하게 되었다.
Jasypt is a java library which allows the developer to add basic encryption capabilities to his/her projects with minimum effort, and without the need of having deep knowledge on how cryptography works.
Jasypt 는 개발자가 깊은 지식이 없이도 최소한의 노력으로 자신의 프로젝트에 기본적인 암호화 능력을 가질 수 있도록 하는 자바 라이브러리다.
PostgreSql 연동을 위해 application.yml 파일에 DataSource 정보를 작성합니다. 아래 사진에는 localhost 의 데이터베이스에 연동하는 것처럼 작성하였습니다.
실제로 AWS 에 있는 데이터베이스에 연동하는 정보를 그대로 작성하여 GitHub 에 올린다고 하면, 모든 사람이 제 데이터베이스에 접근할 수 있게 되는 것입니다.
spring:
datasource:
hikari:
maximum-pool-size: 4
url: jdbc:postgresql://localhost:5432/postgres
username: postgres
password: 1234
dependencies {
...
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.3'
...
}
import org.jasypt.encryption.StringEncryptor;
import org.jasypt.encryption.pbe.PooledPBEStringEncryptor;
import org.jasypt.encryption.pbe.config.SimpleStringPBEConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class JasyptConfig {
@Value("${jasypt.encryptor.password}")
private String PASSWORD;
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor(){
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(PASSWORD);
config.setPoolSize("1");
config.setAlgorithm("PBEWithMD5AndDES");
config.setStringOutputType("base64");
config.setKeyObtentionIterations("1000");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
encryptor.setConfig(config);
return encryptor;
}
}
jaspt.encryptor.bean
에는 위에서 만들어준 config 객체 내 Bean으로 설정해준 대상을 넣어주면 된다.
spring:
datasource:
hikari:
maximum-pool-size: 4
url: jdbc:postgresql://localhost:5432/postgres
username: postgres
password: 1234
jasypt:
encryptor:
bean: jasyptStringEncryptor
password : 5678
import org.assertj.core.api.Assertions;
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.junit.jupiter.api.Test;
class JasyptConfigTest {
@Test
void jasypt(){
String url = "jdbc:postgresql://localhost:5432/postgres";
String username = "postgres";
String password = "1234";
String encryptUrl = jasyptEncrypt(url);
String encryptUsername = jasyptEncrypt(username);
String encryptPassword = jasyptEncrypt(password);
System.out.println("encryptUrl : " + encryptUrl);
System.out.println("encryptUsername : " + encryptUsername);
System.out.println("encryptPassword" + encryptPassword);
Assertions.assertThat(url).isEqualTo(jasyptDecryt(encryptUrl));
}
private String jasyptEncrypt(String input) {
String key = "5678";
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setAlgorithm("PBEWithMD5AndDES");
encryptor.setPassword(key);
return encryptor.encrypt(input);
}
private String jasyptDecryt(String input){
String key = "5678";
StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
encryptor.setAlgorithm("PBEWithMD5AndDES");
encryptor.setPassword(key);
return encryptor.decrypt(input);
}
}
> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :compileTestJava
> Task :processTestResources NO-SOURCE
> Task :testClasses
> Task :test
encryptUrl : +XPODfbCmaEUcFm0NFTFcIRBn96DqfB8KiA1wep/kszK2yKypopESCkZXk13Wuj0/BH1A1iNAGU=
encryptUsername : GSpxgpIVOhZVryh0i9gn5hx0MD/qinGC
encryptPassword : vOKU56G/+aomdpR97oe99Q==
BUILD SUCCESSFUL in 3s
해당 테스트를 통해 얻은 암호화된 문자열로 application.yml 을 수정해줍니다. 암호화된 문자열을 입력할때는 ENC() 로 감싸서 입력해주어야 합니다.
spring:
datasource:
hikari:
maximum-pool-size: 4
url: ENC(+XPODfbCmaEUcFm0NFTFcIRBn96DqfB8KiA1wep/kszK2yKypopESCkZXk13Wuj0/BH1A1iNAGU=)
username: ENC(GSpxgpIVOhZVryh0i9gn5hx0MD/qinGC)
password: ENC(vOKU56G/+aomdpR97oe99Q==)
jasypt:
encryptor:
bean: jasyptStringEncryptor
password : 5678
위와 같은 과정을 통해 application.yml 파일의 암호화를 설정해 주었습니다. 하지만, application.yml 파일 내 jasypt.encryptor.password
가 노출되어있다면, 암호화는 해주었지만 암호화를 풀 수 있는 열쇠를 지어준 꼴이 됩니다.
이러한 현상을 방지해주기 위해서 VM Options 를 사용해 줄 수 있습니다.
Run > Edit Configurations 내 해당 SpringBoot Configuration 에서 VM options 에 -Djasypt.encryptor.password={암호}
입력
build.gradle 파일에 추가
test {
useJUnitPlatform()
systemProperty "jasypt.encryptor.password", project.getProperties().get("jasypt.encryptor.password")
}
gradle 빌드 시 옵션으로 프로퍼티 추가
./gradlew build -Pjasypt.encryptor.password=5678
도커 실행 시 환경변수 값으로 옵션값을 주어 적용하고자 할 때, 명령어에 JAVA_OPTS
으로 넘겨주도록 합니다.
$ docker run -p 8080:8080 -e JAVA_OPTS=-Djasypt.encryptor.password=5678 sprint-boot
이 경우 Dockerfile 에서도 수정이 필요한데, 아래와 같이 작성하는 경우가 많습니다.
ENTRYPOINT ["java","${JAVA_OPTS}","-jar","/app.jar"]
하지만, 이렇게 작성할 경우 적용이 되지 않습니다. 저렇게 사용하는 경우에는 Dockerfile 내 JAVA_OPTS
를 설정해주었을 때 저렇게 선언하는 작성하는 경우가 있지만, 이번 경우에는 적용되지 않습니다.
지금과 같은 경우에는 아래와 같이 작성해주어야 제대로 환경변수로 적용이 가능합니다.
ENTRYPOINT ["sh", "-c", "java ${JAVA_OPTS} -jar /app.jar"]
➕ jasypt (http://www.jasypt.org/encrypting-passwords.html)
➕ Jasypt (https://velog.io/@sixhustle/Jasypt)
➕ Spring Boot Docker (https://spring.io/guides/topicals/spring-boot-docker/)
➕ 프로퍼티 파일에 필드 암호화 (Jasypt) (https://warpgate3.tistory.com/entry/프로퍼티-파일-암호화)