[스프링 부트] Jasypt 설정 암호화로 Github Repo 에 안전하게 올리기
안녕하세요.
스프링 부트에서 Jasypt 라이브러리를 사용해서 설정을 암호화하는 방법을 알아봅시다.
application.yml 파일에 아래와 같이 DB 접속 정보를 저장해둔다면, Github 레포에 올리지 못하겠죠?
spring:
profiles: local
datasource:
url: DB주소
username: DB계정
password: DB비밀번호
driver-class-name: com.mysql.cj.jdbc.Driver
applicaiton.yml 을 .gitignore 파일에 추가하면, Git Stage 에 올라가지 않습니다.
그 다음에 작업자들끼리만 application.yml 파일을 공유해도 되지만,
공개 가능한 다른 설정까지 번거롭게 변경할 때 마다 모든 작업자들끼리 동기화하는 게 여간 귀찮은 일이 아닙니다.
Jasypt 라이브러리를 사용하면 환경 변수나 IDE VM Option 에 암호화 키만 등록하면,
설정 파일에 민감한 정보를 그대로 Github 깃허브 레포에 올릴 수 있게 됩니다.
설정 파일에는 아래와 같이 암호화된 문자열만 들어가서 안전합니다.
spring:
profiles: local
datasource:
url: ENC(qJcIphp38nLaMwEHY2nO22BQEPIEF8yWA1eQIUCs70jIm8XjBGlxKblYHGFx/MaGU7c0Zz2I4nnLYTe3YD8ne+n9g1VZwwhpdS666PEEkkhFraY9Ck84lIoFmTROXRhW38rkBLyxoOSQlQI55T1bpH63BQnf+HoTp04ZMF34fp8cuRUSTY=)
username: ENC(CVvoCs9unAb7HYSbkbF+mPj)
password: ENC(45XIx7pX22h/sW7SQIrL7q/N9bpb5acKBks=)
1. Jasypt 라이브러리 Gradle 의존성 추가
implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.4'
위 코드로 Gradle 의존성에 추가하여 설치합니다.
인텔리제이 기준 Gradle 정보가 변경되면, 에디터 우측 상단에 Gradle 의존성을 새로고침하는 버튼이 나타납니다.
이 버튼을 눌러 Gradle 의존성을 새로 설치합니다.
또는 우측 Gradle 탭을 눌러 새로고침을 해줘 Jasypt 라이브러리 의존성을 설치합니다.
2. Jasypt Configuration 빈 등록
Jasypt 관련 설정해주는 @Configuration 빈을 등록합니다.
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 encryptKey;
@Bean(name = "jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(encryptKey); // 암호화할 때 사용하는 키
config.setAlgorithm("PBEWithMD5AndDES"); // 암호화 알고리즘
config.setKeyObtentionIterations("1000"); // 반복할 해싱 회수
config.setPoolSize("1"); // 인스턴스 pool
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator"); // salt 생성 클래스
config.setStringOutputType("base64"); //인코딩 방식
encryptor.setConfig(config);
return encryptor;
}
}
JasyptConfig 빈을 생성할 때, 설정에서 jasypt.encryptor.password 값을 가져와 encryptKey 변수에 주입합니다.
jasypt.encryptor.password 는 암호화 해주는 키이며, 스프링 부트 서버를 실행할 때 외부에서 주입할 예정입니다.
바로 설정 해볼까요?
3. Jasypt.encryptor.password 값 설정
인텔리제이 기준으로 Application 클래스에다 코드 라인 넘버에 있는 실행 버튼을 누릅니다.
Modify Run Configuration 메뉴를 누릅니다.
Modify options > Add VM options 를 눌러, VM options 텍스트 칸을 활성화 시킵니다.
-Djasypt.encryptor.password=랜덤문자열
으로 설정합니다.
실행 설정한 걸 보려면 상단 메뉴 Run > Edit Configurations ... 에서 모두 확인이 가능합니다.
다른 작업자에게 설정 방법을 공유하거나, 앞으로 테스트 코드에서도 또 설정해야 하므로 숙지해주시면 좋습니다.
4. 암호화 문자열을 구할 테스트 코드 작성
그렇다면 이제 암호화한 문자열을 어떻게 얻을 수 있을까요?
매 번 문자열을 암호화할 때 마다, 다른 프로덕션 코드와 같이 실제 서버를 실행시키면서 얻는다면 시간도 오래 걸리고
비효율적으로 얻을 겁니다.
테스트 코드를 활용하면 프로덕션 코드를 실행하지 않고도 간단하게 암호화한 문자열을 얻을 수 있습니다.
테스트 코드를 실행할 때마다 jasypt.encryptor.password 값을 넣어줘야 한다면, 어떻게 해야 할까요?
Gradle 코드에서 아래처럼 추가해줄 수 있습니다.
테스트를 실행시킬 때 jasypt.encryptor.password 를 VM options 에서 가져오고 프로퍼티에 등록해줍니다.
tasks.named('test') {
useJUnitPlatform()
systemProperty "jasypt.encryptor.password", System.getProperty("jasypt.encryptor.password")
}
plainText 변수에 암호화하고 싶은 값을 입력하여 테스트를 실행하면,
System.out.println(encryptedText) 으로 암호화한 값을 확인할 수 있습니다.
import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import static org.assertj.core.api.Assertions.assertThat;
public class JasyptTest extends JasyptConfig {
@Test
public void jasypt_encrypt_decrypt_test() {
String encryptKey = System.getProperty("jasypt.encryptor.password");
String plainText = "";
StandardPBEStringEncryptor jasypt = new StandardPBEStringEncryptor();
jasypt.setPassword(encryptKey);
String encryptedText = jasypt.encrypt(plainText);
String decryptedText = jasypt.decrypt(encryptedText);
System.out.println(encryptedText);
assertThat(plainText).isEqualTo(decryptedText);
}
}
마찬가지로 VM options 에 등록시켜줍니다.
plainText 값을 변경한 다음 테스트 코드를 실행합니다.
String plainText = "암호화하고싶은문자열";
테스트 결과창을 보면 아래처럼 암호화한 값을 얻을 수 있습니다.
이제 환경설정에 암호화한 값을 입력해줍니다.
5. 암호화한 문자열 설정 파일에 대체
application.yml 에 아래처럼 등록해줍니다.
암호화한 문자열을 그대로 넣는게 아니라, 'ENC(암호화한문자열)' 형태로 넣어줍니다.
spring:
datasource:
url: ENC(qJcIphp38nLK6wAUrFUJv6MsP1XaMwEHY2nO22BQEPIEF8yWA1eQIUCsVxDIZ6XJm70jIm8XjBGlxKblYHGFx/MaGU7c0Zz2I4nnLYTe3YD8ne+n9g1VZwwhpdS666PEEkkhFraY9Ck84lIoFmTR=)
username: ENC(CVvoCs9unAbL2iuSbkbF+mPj)
password: ENC(45XI2J452h/sW7S58rL7q/N9bpb5oks=)
6. jasypt.encryptor.password 값 작업자끼리 공유
설정한 jasypt.encryptor.password 값을 작업자끼리 공유하여 IDE에 똑같이 설정합니다.
스프링 부트 jar 파일을 실행할 때도 jar -Djasypt.encryptor.password=설정한키값 형태로 넘겨주는 것도 잊지 않기를 바랍니다.
7. Github 에 안심하고 업로드
Github 에 암호화한 키를 실수로 올리지 않는 한, 안심하고 민감한 정보가 들어간 설정 파일을 업로드할 수 있습니다.
긴 글 봐주셔서 감사합니다.
도움이 되었다면, 공감과 댓글 부탁드려요.