서버가 DB와 연결되는 부분에서의 위험
기존 RDS 연결 방식
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
//application.yml에 데이터 베이스와 연결하는 인증 정보가 그대로 노출됨
url: example.db.net
username: ohseungyun
password: passwordString
jpa:
database: mysql
generate-ddl: true
show-sql: true
위험! 깃 허브를 통해 소스코드를 관리하는 등 버전 관리 로그를 통해 소스코드가 유출되면 데이터 베이스가 직접 공격 받을 수 있다
위험! 데이터 베이스 관리자 이외에도 버전 관리에 동참하는 모든 사람은 권한과 관계없이 데이터 베이스 연결 정보를 알게 된다
개선된 RDS 연결
- 우선, 대칭키 암호 알고리즘을를 이용해 application.yml에 데이터 베이스와 연결하는 인증 정보 값을 암호화
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
//암호화된 값으로 표시됨
url: ENC(HLNVkrnK/9aSB19Ehc53W5UiVCAahkCLVkvOyqjRyN6+U5tkR3aH/Kk9jFz5giV6qzXqWOeeegDATsQYL/SQcYd5QRhpAmFXCtSBDqGupfX7G1uq275emdG1nYaT3JQ5MfYsHqInRY)
username: ENC(d76s+swPRMX6c0RYK2GKo78htB6)
password: ENC(Dbu9GoFb1HX3q0swGDX2zv7ccxQqGydNs0=)
jpa:
database: mysql
generate-ddl: true
show-sql: true
문제! 서버 자체도 해당 키 없이는 암호문을 복호화 할 수 없다
- key값을 가지고 해당 암호문을 복호화할 클래스 JasyptConfig 생성
@Configuration
public class JasyptConfig {
private String encryptKey = "key노출"; //정적 주입!
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(encryptKey);
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
}
문제! 복호화를 위해 이용되는 key값이 정적 할당 되면서 다음처럼 소스코드에 노출되는 문제, 노출되는 위치만 바뀌었을 뿐 위험이 해소되지 않았다
해결 아이디어: 모두 런타임에 동적으로 주입해 버리기
JasyptConfig에서 key값은 @Value를 활용해 application.yml에 선언한 환경변수 값을 런타임에 가져와 선언하도록 변경하고,
@Configuration
public class JasyptConfig {
@Value("${enviroment}") //런타임에 환경 변수를 찾아 값을 동적 할당할 예정
private String encryptKey;
@Bean("jasyptStringEncryptor")
public StringEncryptor stringEncryptor() {
PooledPBEStringEncryptor encryptor = new PooledPBEStringEncryptor();
SimpleStringPBEConfig config = new SimpleStringPBEConfig();
config.setPassword(encryptKey);
config.setAlgorithm("PBEWithMD5AndDES");
config.setKeyObtentionIterations("1000");
config.setPoolSize("1");
config.setProviderName("SunJCE");
config.setSaltGeneratorClassName("org.jasypt.salt.RandomSaltGenerator");
config.setIvGeneratorClassName("org.jasypt.iv.NoIvGenerator");
config.setStringOutputType("base64");
encryptor.setConfig(config);
return encryptor;
}
}
마찮가지로 application.yml에서 정적으로 환경 변수를 선언하지 않고,
환경 변수 값은 Github Action Workflow를 통해 CI/CD 과정에서 application.yml에 환경변수를 선언하는 라인을 동적으로 추가하도록 한다.
//현재 application.yml에는 환경변수 선언이 되어있지 않다.
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: ENC(HLNVkrnK/9aSB19Ehc53W5UiyN6+U5tkR3aH/Kk9jFz5giV6qzXqWOeeegDATsQYL/SQcYd5QRhpAmFXCtSBDqGupfX7G1uq275emdG1nYaT3JQ5MfYsHqInRY)
username: ENC(d76s+swPRMX6c0RtB6)
password: ENC(Dbu9GoFb1ccNGmGBzSQfxQqGydNs0=)
jpa:
database: mysql
generate-ddl: true
show-sql: true
Github Action Workflow에 리눅스 명령어를 통해 application.yml에 enviroment: key 환경 변수 선언 라인을 동적으로 추가 하도록 명령 합니다
이때, 깃에서 보안 관리해주는 Git Secrets를 통해 enviroment: key 라는 실질 적인 환경 변수 값은 아래와 같이 외부에서 주입 받도록 합니다
#jasypt 복호화 키 환경변수 application.yml에 생성하기 in 리눅스 명령어
- name: add code in application.yml for jasypt key env
run: |
cd ./src/main/resources
//선언 라인은 Git Secrets에서 주입
echo "${{ secrets.JASYPT_KEY }}" >> ./application.yml
shell: bash
정리
이렇게 되면, 깃허브 소스코드 저장소에 application.yml은 enviroment: password 이라는 라인을 가지고 있지 않아, 환경변수를 확인할 수 없다.
또한, workflow에도 Git Secrets를 이용했기 때문에 enviroment: password 이라는 라인을 확인할 수 없다.
CI수행 과정에서 동적으로 해당 라인이 생성되어 빌드되고 배포가 이루어지기 때문에 서버 구동은 정상적으로 이루어진다.
이로써, 버전 관리 과정에서 민감한 정보는 모두 숨겨졌다.
'개발자 준비 > 개발 공부' 카테고리의 다른 글
전략 패턴과 캡슐화 개념을 이용한 도메인과 검증 로직 최적 분리 과정 (0) | 2022.12.02 |
---|---|
JWT 토큰 탈취시 대처법에 대한 고찰 (0) | 2022.12.02 |
Static 장점 제대로 살리기(feat. 프로그래밍 패러다임은 어우러져야 한다) (0) | 2022.11.22 |
생산성 향상을 위한 나만의 개발 프로세스 만들어보기 (0) | 2022.11.22 |
실전을 위한 MVC 재 정리(feat. 입력을 원하는 타입으로 가공하는 책임은 어디일까?) (0) | 2022.11.22 |