[Jasypt] yaml 파일의 암호화

haeny-dev·2021년 7월 26일
3
post-thumbnail

📌 배경

Jasypt 를 사용하게 된 배경이자, 해당 라이브러리를 사용하는 목적은 yml 파일안의 중요한 정보에 대한 암호화이다.

AWS EC2 인스턴스에 Github을 연동하여 스프링부트 프로젝트를 만드는 개인 프로젝트 진행하는 도중 데이터베이스를 연동하는 과정에서 DataSource를 만들기 위해 yml 파일에 나의 데이터베이스 정보들이 들어가게 되었다.

그리고 그 정보가 Github에 노출되는 상황이 되어 yml 파일 내 해당 정보들에 대해서 암호화하는 과정이 필요하게 되어 해당 라이브러리를 사용하게 되었다.

🔐 Jasypt

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 는 개발자가 깊은 지식이 없이도 최소한의 노력으로 자신의 프로젝트에 기본적인 암호화 능력을 가질 수 있도록 하는 자바 라이브러리다.

🍃 SpringBoot x Jasypt

➕ application.yml 작성

PostgreSql 연동을 위해 application.yml 파일에 DataSource 정보를 작성합니다. 아래 사진에는 localhost 의 데이터베이스에 연동하는 것처럼 작성하였습니다.

실제로 AWS 에 있는 데이터베이스에 연동하는 정보를 그대로 작성하여 GitHub 에 올린다고 하면, 모든 사람이 제 데이터베이스에 접근할 수 있게 되는 것입니다.

spring:
  datasource:
    hikari:
      maximum-pool-size: 4
    url: jdbc:postgresql://localhost:5432/postgres
    username: postgres
    password: 1234

➕ 라이브러리 적용

1. Gradle 추가

  • build.gradle 파일
dependencies {
    ...
    implementation 'com.github.ulisesbocchio:jasypt-spring-boot-starter:3.0.3'
    ...
}

2. Config 생성

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;
    }
}

3. application.yml 작성

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

➕ 암호화 적용

1. 테스트 코드 작성

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);
    }

}

2. application.yml 수정

  • 테스트 코드 실행 결과
> 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

➕ 추가 설정

Jasypt Password 노출방지

위와 같은 과정을 통해 application.yml 파일의 암호화를 설정해 주었습니다. 하지만, application.yml 파일 내 jasypt.encryptor.password 가 노출되어있다면, 암호화는 해주었지만 암호화를 풀 수 있는 열쇠를 지어준 꼴이 됩니다.

이러한 현상을 방지해주기 위해서 VM Options 를 사용해 줄 수 있습니다.

1. IntelliJ 에서 VM Options 적용

Run > Edit Configurations 내 해당 SpringBoot Configuration 에서 VM options 에 -Djasypt.encryptor.password={암호} 입력

2. Gradle task:test 에서 Property 적용

build.gradle 파일에 추가

test {
    useJUnitPlatform()
    systemProperty "jasypt.encryptor.password", project.getProperties().get("jasypt.encryptor.password")
}

gradle 빌드 시 옵션으로 프로퍼티 추가

./gradlew build -Pjasypt.encryptor.password=5678

3. Docker 에서 JAVA_OPTS 적용

도커 실행 시 환경변수 값으로 옵션값을 주어 적용하고자 할 때, 명령어에 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"]

📖 REFERENCE

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/프로퍼티-파일-암호화)

0개의 댓글