간단하게 암호화를 알아보면 암호화는 보통 대칭키, 비대칭키를 이용해 암호화를 합니다. 대칭키의 경우 같은 비밀키를 server, client가 공유하여 송신자가 이 비밀키를 이용해 평문을 암호화하고 수신자는 같은 비밀키를 이용해 복호화를 진행합니다. 이런 경우 비대칭키에 비해 암호화와 복호화가 빠르다는 장점이 있지만 이 비밀키를 하나만 알아내면 쉽게 보안적인 문제가 발생한다는 단점이 존재합니다.
비대칭키의 경우 공개키, 개인키가 한 쌍을 이루어 암호화와 복호화를 합니다. 통상적으로 공개키를 이용해 암호화를 하고, 개인키를 이용해 복호화를 진행합니다. 암호화를 진행한 공개키의 경우 개인키로만 복호화가 가능하기 때문에 공개해도 상관없다는 측면에서 공개키라 불리웁니다. 그렇기 때문에 대칭키보다 상대적으로 보안적인 이슈가 덜하지만 대칭키보다는 느린 단점이 존재합니다.
그래서 이 암호화를 이용해서 무엇을 구현하고자 하냐면 데이터베이스 관련 설정을 암호화하려고 합니다. 현재까지 데이터베이스에 관한 설정들은 service의 application.yml파일에 그대로 노출되어 있습니다. 하지만 이 데이터베이스의 데이터의 노출은 굉장히 큰 보안적인 문제이기 때문에 이러한 정보를 암호화해보고자 합니다.
암호화를 위해서 config-server에 디펜던시를 추가하고 bootstrap.yml 파일에 설정을 하도록 하겠습니다.
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
encrypt:
key: this-key-is-for-encrypt
그리고 config-server가동시켜 암호화와 복호화가 잘 작동하는지 확인해보도록 하겠습니다.
이런 식으로 암호화가 잘 동작하고 있음을 알 수 있습니다.
다음과 같이 데이터베이스에 대한 설정 정보를 주석 처리하고 지우도록 하겠습니다.
server:
port: ${port:7000}
spring:
application:
name: auth-service
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
jpa:
generate-ddl: true
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
hibernate:
ddl-auto: create
properties:
hibernate:
show_sql: true
format_sql: true
use_sql_comments: true
# datasource:
# url: "jdbc:mariadb://localhost:3306/AUTHSERVICE?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC"
# username: biuea
# password: password
# driver-class-name: org.mariadb.jdbc.Driver
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: http://127.0.0.1:8761/eureka
management:
endpoints:
web:
exposure:
include: refresh, health, beans, busrefresh
그리고 이 주석처리된 데이터베이스에 관한 정보는 local-repository로 옮기도록 하겠습니다. 실제 서비스에서는 git-repository를 private하게 만들어 인가된 사용자만 접근하게 만들거나, native혹은 local을 이용하여 개인 pc에서 이 정보들에 대해 접근하는 게 보안적인 측면에서 유리합니다.
그래서 지금까지는 외부 git-repository를 사용했으나 local-repository를 이용하도록 하겠습니다.
config-server의 applicatio.yml 파일의 설정을 다음과 같이 local repository로 변경하고 해당 repository로 이동해서 auth-service에 관한 설정 파일을 만들어 보도록 하겠습니다.
server:
port: ${port:8888}
spring:
application:
name: config-server
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
cloud:
config:
server:
git:
uri: file://${user.home}/Desktop/MyRentalPlatform/git-local-repo
management:
endpoints:
web:
exposure:
include: health, beans, httptrace, busrefresh
datasource:
url: "jdbc:mariadb://localhost:3306/AUTHSERVICE?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC"
username: biuea
password: password
driver-class-name: org.mariadb.jdbc.Driver
token:
exp_time: 43200000
secret: user_token
gateway:
ip: 127.0.0.1
그리고 auth-service.yml파일이라는 이름으로 auth-service에 관한 설정을 만들었으므로 auth-service에서 접근하는 config-server의 설정을 바꿔주도록 하겠습니다.
spring:
cloud:
config:
uri: http://127.0.0.1:8888
name: auth-service
전반적인 설정은 끝났습니다. 그러면 이제 데이터베이스에 접근하기위한 패스워드를 암호화시켜 서비스 구동시 데이터베이스에 접근할 때는 앞서 설정해주었던 키로 복호화를 진행하고 데이터베이스에 접근할 수 있도록 해보겠습니다.
우선 데이터베이스의 암호인 password를 암호화를 진행하겠습니다.
그러면 이 암호화된 값을 다음과 같이 auth-service.yml파일에 적용하겠습니다.
datasource:
url: "jdbc:mariadb://localhost:3306/AUTHSERVICE?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC"
username: biuea
password: '{cipher}2c668425af56a7f35420b07994327359ea13e0012d6b253210d7ff5699551609'
driver-class-name: org.mariadb.jdbc.Driver
token:
exp_time: 43200000
secret: user_token
gateway:
ip: 127.0.0.1
password부분에 {cipher}는 암호화되어 있는 글자라는 의미이므로 꼭 적어주셔야 합니다.
이런 식으로 암호화에 대한 설정이 되었으니 config-server를 재구동하고 암호화가 잘 되어 있는지 확인해보겠습니다. 앞서 암호화를 '{cipher}encrypted_password'로 만들었으니 localhost:8888/auth-service/default로 접속했을 때 나타나는 복호화가 된 password로 나타나야겠죠.
// 20210824100253
// http://localhost:8888/auth-service/default
{
"name": "auth-service",
"profiles": [
"default"
],
"label": null,
"version": "a192cd4681b7a784d3989048823c7242b41edf17",
"state": null,
"propertySources": [
{
"name": "file:///home/biuea/Desktop/MyRentalPlatform/git-local-repo/auth-service.yml",
"source": {
"datasource.url": "jdbc:mariadb://localhost:3306/AUTHSERVICE?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC",
"datasource.username": "biuea",
"datasource.driver-class-name": "org.mariadb.jdbc.Driver",
"token.exp_time": 43200000,
"token.secret": "user_token",
"gateway.ip": "127.0.0.1",
"datasource.password": "password"
}
},
{
"name": "file:///home/biuea/Desktop/MyRentalPlatform/git-local-repo/application.yml",
"source": {
"token.exp_time": 43200000,
"token.secret": "user_token",
"gateway.ip": "127.0.0.1"
}
}
]
}
다음과 같이 http://localhost:8888/auth-service/default로 접속한 결과 복호화가 된 암호가 나타난 것을 볼 수 있습니다.
지금까지 대칭키를 이용해 암호화와 복호화를 진행해보았습니다. 하지만 대칭키는 앞서 설명한대로 보안에 있어서 큰 문제가 생길 수 있습니다. 그렇기 때문에 비대칭키를 이용하여 속도는 대칭키보다는 떨어지지만 보안 측면에서 강점인 암호화와 복호화를 진행해보겠습니다.
저는 ~/Desktop/MyRentalKeyStore라는 디렉토리를 만들어 여기에 키를 관리하도록 하겠습니다. 그리고 다음과 같은 명령어로 encryptionKey.jks라는 파일을 생성하도록 하겠습니다.
key tool -genkeypair -alias encryptionKey -Keyalg RSA -dname "CN=biuea, OU=API Development, O=rental.microservices.com, L=Seoul C=KR" -keypass "password" -keystore encryptionKey.jks -storepass "password"
다음의 명령어로 encryptionKey.jks를 살펴 보도록 하겠습니다.
keytool -list -keystore encryptionKey.jks
키 저장소 비밀번호 입력:
키 저장소 유형: jks
키 저장소 제공자: SUN
키 저장소에 1개의 항목이 포함되어 있습니다.
encryptionkey, 2021. 8. 24, PrivateKeyEntry,
Certificate fingerprint (SHA-256): AC:A0:63:CB:A0:56:F3:C7:BC:B5:D7:0B:A9:41:F2:7F:7E:66:E7:C6:E5:0A:A9:7B:B0:E3:C7:49:1F:ED:D6:64
확인 결과 privateKey를 확인할 수 있네요. 즉, 해당 키는 복호화에 사용되는 개인키입니다. 개인키를 만들었으니 한 쌍이 되는 공개키를 생성하도록 하겠습니다.
keytool -export -alias encryptionKey -keystore encryptionKey.jks -rfc -file trustServer.cer
keytool -import -alias trustServer -file trustServer.cer -keystore publicKey.jks
이렇게 공개키를 만들고 한번 확인해보도록 하겠습니다.
keytool -list -keystore publicKey.jks
키 저장소 비밀번호 입력:
키 저장소 유형: jks
키 저장소 제공자: SUN
키 저장소에 1개의 항목이 포함되어 있습니다.
trustserver, 2021. 8. 24, trustedCertEntry,
Certificate fingerprint (SHA-256): AC:A0:63:CB:A0:56:F3:C7:BC:B5:D7:0B:A9:41:F2:7F:7E:66:E7:C6:E5:0A:A9:7B:B0:E3:C7:49:1F:ED:D6:64
공개키와 개인키를 이용해 config-server의 설정을 바꿔주도록 하겠습니다.
encrypt:
key-store:
location: file://${user.home}/Desktop/MyRentalKeyStore/encryptionKey.jks
password: password
alias: encryptionKey
config-server를 재구동하고 postman을 통해 password에 대한 암호화와 복호화를 진행해보겠습니다.
암호화와 복호화가 잘 진행되는 모습을 볼 수 있습니다.
그러면 이 암호화된 값을 가지고 auth-service.yml파일을 다음과 같이 수정하도록 하겠습니다.
datasource:
url: "jdbc:mariadb://localhost:3306/AUTHSERVICE?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC"
username: biuea
password: '{cipher}AQCg2tdd47xRld2goCXFQHKuBCCeLtzhGfVejqfzYvJBVgARE1uKcATpYyyHIZ+RqI15PZIMApWJrC72mMNjnrk24l3rHZn5JaTa3LAcC7T67Mb0at77+DUMG09bXArz+dRZzwh45G7qJKwEYqPrr8bPgJuoz6p6SmiPcl7cBqmsXB3lkFB4FMgjyb3IMiTKPMDIPXbM9PKhYW/8o3j/KHFlbu+3wp4pAQMpvWqbxFspkp5AUwE1EqzlG+FlPBC86ABViGXWYNipFsWQnBnCpgqlK8zxQm6l1sxuLdOaQkpeMOcc/S7dHaoAxCGZSgVHh2hbNLTWFhw9bwxZxY7nnw3RfBuy5MvfHF2zODJBBmkJG6kX3fbELFQjmwHpG+cs2CQ='
driver-class-name: org.mariadb.jdbc.Driver
token:
exp_time: 43200000
secret: user_token
gateway:
ip: 127.0.0.1
http://localhost:8888/auth-service/default로 접속하고 값을 확인하면 다음과 같이 잘 복호화가 됨을 알 수 있습니다.
// 20210824104909
// http://localhost:8888/auth-service/default
{
"name": "auth-service",
"profiles": [
"default"
],
"label": null,
"version": "a192cd4681b7a784d3989048823c7242b41edf17",
"state": null,
"propertySources": [
{
"name": "file:///home/biuea/Desktop/MyRentalPlatform/git-local-repo/auth-service.yml",
"source": {
"datasource.url": "jdbc:mariadb://localhost:3306/AUTHSERVICE?useSSL=false&characterEncoding=UTF-8&serverTimezone=UTC",
"datasource.username": "biuea",
"datasource.driver-class-name": "org.mariadb.jdbc.Driver",
"token.exp_time": 43200000,
"token.secret": "user_token",
"gateway.ip": "127.0.0.1",
"datasource.password": "password"
}
},
{
"name": "file:///home/biuea/Desktop/MyRentalPlatform/git-local-repo/application.yml",
"source": {
"token.exp_time": 43200000,
"token.secret": "user_token",
"gateway.ip": "127.0.0.1"
}
}
]
}
이런 방식으로 토큰도 암호화를 진행해보도록 하겠습니다.
spring:
cloud:
config:
uri: http://localhost:8888
name: rental
이런 식으로 config-server의 rental.yml파일의 정보를 받아오겠다고 설정을 하고 local repository에 rental.yml파일을 작성하겠습니다.
token:
exp_time: 43200000
secret: '{cipher}AQCRrtVH5iNfNZwDY0M8KwYyJvV0pkuu8f5N2ZLcfkycZf9ug723tDDnPWIn1s6LfZ0RGluP9TvTodlDNxuCzKhIdNZwEbIXJTPZkSfmiq6LmOIBvQr2cAUuzHO0KVnfxS/env8LTZzDWBQW1H8wl8v6tuQ7ZCOEUjppzEJxvosUQv+n5cM4ywkUUFQovISib2xse53flx/gCIyCgWxFNyOD5KvgLqBuwKrnzpSVspf0/ohSVviWxTuLA57NulEt/DKrT5h6S3jFY6ssdvuiyDCHWdcr6n4KN1Aw2dpHbH9syF7MLKpQ0L9n7u3PB6GbzWnH5mVSIbGWVanJuBEgE5MCMphipu9Yrlp6JnK2M3wD7rEYOL2NkXhuufwDwfGTBNM='
gateway:
ip: 127.0.0.1
여기서 secret부분은 http://localhost:8888/encrypt에 user_token을 암호화한 값을 넣었습니다.
// 20210824110716
// http://localhost:8888/rental/default
{
"name": "rental",
"profiles": [
"default"
],
"label": null,
"version": "a192cd4681b7a784d3989048823c7242b41edf17",
"state": null,
"propertySources": [
{
"name": "file:///home/biuea/Desktop/MyRentalPlatform/git-local-repo/rental.yml",
"source": {
"token.exp_time": 43200000,
"gateway.ip": "127.0.0.1",
"token.secret": "user_token"
}
},
{
"name": "file:///home/biuea/Desktop/MyRentalPlatform/git-local-repo/application.yml",
"source": {
"token.exp_time": 43200000,
"token.secret": "user_token",
"gateway.ip": "127.0.0.1"
}
}
]
}
결과 처럼 rental.yml파일의 토큰에 대한 정보가 복호화가 잘 됨을 확인할 수 있습니다.
인프런: Spring Cloud로 개발하는 마이크로서비스 애플리케이션(MSA) - 이도원