[Spring Cloud] cloud config에 대한 설명 및 구현

Doccimann·2022년 5월 13일
3

MSA

목록 보기
1/1
post-thumbnail
post-custom-banner

🔥 Spring cloud config를 살펴보기 전에, 배경부터 알아봅시다

일단 Spring cloud config를 논하기 이전에 예전에 작성하였던 Dynamo DB와 연결하는 예제를 보겠습니다.

SpringBoot와 DynamoDB 연동 예제(Kotlin)

저희는 이 예제에서 DynamoDB를 연동하기 위해서 두 가지의 정보를 DynamoDBConfig.kt에 작성을 해주었습니다

  • DynamoDB의 IAM에 대한 AccessKey
  • DynamoDB의 IAM에 대한 SecretKey

그런데 위와 같은 방법은 큰 위험성을 가지고 있습니다. 위험한 이유는 다음과 같습니다.

IAM의 FullAccess 권한을 가진 AccessKey와 SecretKey가 외부로 유출되면 본인의 AWS 계정에 대한 액세스 권한을 탈취당하는 것과 같다. 이는 매우 위험한 행위이다.

이처럼 서버 어플리케이션이 직접 저러한 권한 정보를 들고있다면, 보안 취약점이 저기에서 발생하게됩니다.

그 외에도 여러가지 이유가 존재하는데, 사용하고자 하는 시스템의 환경 설정 값이 자주 바뀌는 경우가 있을 수도 있습니다. 그 때마다 서버 어플리케이션은 변경된 환경 설정값을 갱신하여 다시 빌드, 배포를 진행해줘야하는데, 이는 매우 귀찮고 까다로운 일이 될겁니다.

따라서, 보안적인 측면에서나, 혹은 서버의 운영 측면에서 보게되면 서버의 환경 설정 정보는 중앙에서 관리를 하고, 각 서버 어플리케이션에서 관리를 해주는 것이 매우 좋을겁니다.

위의 기능을 지원하는 스프링 프레임워크의 기능 중 하나가 Spring cloud config 입니다.


🤔 Spring cloud config가 무엇일까요?

Spring 공식 문서에 나와있는 Spring cloud config의 정의는 다음과 같습니다.

대충 해석을 해드리자면, 분산된 환경의 서버에서 환경 설정 정보를 중앙에서 모아 관리를 하는데 도움을 주는 라이브러리이다 라는 것입니다.

사실 이게 Spring cloud config의 처음이자 끝입니다. 설명은 끝났으니 구현을 해보도록 하겠습니다.

구현 순서는 Spring cloud config server -> Spring cloud config client -> config 값의 암호화 -> config를 저장한 repository를 private로 돌리고 config server에서 ssh를 통해서 repository와 연결하기 입니다.

천천히 따라오시면 됩니다!


🔨 우선 Spring cloud config server를 구현해보겠습니다.

IntelliJ IDEA에서 Spring Initializer로 Spring cloud config -> config server를 체크하시고 프로젝트를 하나 생성합니다.

생성이 되었다면, build.gradle.kts에 아래의 의존성을 추가해줍니다.

implementation("org.springframework.boot:spring-boot-starter-actuator")

그리고 resources에 application.properties를 삭제해주시고, application.yml을 생성합니다.

그리고 application.yml에 다음과 같이 작성해줍시다.

server:
  port: 8081

spring:
  cloud:
    config:
      server:

        git:
          uri: https://github.com/BrianDYKim/config-test
          default-label: main 

# actuator 설정
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    shutdown:
      enabled: true

각 설정 값이 의미하는 바는 아래와 같습니다.

  • server.port: 8081 -> 서버의 포트를 8081로 맞춰준다
  • spring.cloud.config.server.git.uri: https://github.com/BrianDYKim/config-test -> config server가 참조할 yml 파일들을 모아둔 repository의 주소
  • spring.cloud.config.server.git.default-label: main -> config server가 참조할 repository의 branch 이름은 main이다
  • management 아래의 설정들 -> actuator의 설정 정보들. 설정 파일의 정보가 변경된 경우에 refresh를 통해서 새로운 설정 정보를 가져올 수 있다

단, 여기서 주의할 점은 두 가지입니다.

  • yml 파일을 모아둔 github repository가 존재해야한다
  • yml 파일을 모아둔 github repository는 public 상태에 있어야한다

이제 main 함수에 @EnableConfigServer 어노테이션을 달아주고 실행을 시켜주면 끝입니다.

@EnableConfigServer
@SpringBootApplication
class ConfigServerTestApplication

fun main(args: Array<String>) {
    runApplication<ConfigServerTestApplication>(*args)
}

저는 client-test.yml 파일을 github의 repository에 올려둔 상태인데요, client-test.yml의 파일 내부는 아래와 같이 생겼습니다.

spring:
  datasource:
    uri: myEnvironment
    username: root
    password: password

config server를 실행시키고 http://localhost:8081/client/test 주소로 요청을 보내시면, 아래와 같은 응답이 돌아옵니다.

{
"name": "client",
"profiles":[
	"test"
],
"label": null,
"version": "91428f2dfb5e0e4b497596aefaa8c792765202af",
"state": null,
"propertySources":[
	{
		"name": "git@github.com:BrianDYKim/config-test.git/client-test.yml",
		"source":{
			"spring.datasource.uri": "myEnvironment",
			"spring.datasource.username": "root",
			"spring.datasource.password": "password"
			}
		}
	]
}

그러면, 위와 같은 응답을 받아서 설정 정보를 저장하는 config client를 이제부터 작성하겠습니다.


🔨 다음으로 Spring cloud config client를 작성하겠습니다.

새로 프로젝트를 생성하겠습니다.

저는 Spring cloud config server로부터 설정 정보를 잘 받아오고 있는지를 검증하고 싶기 때문에 Spring Web을 체크하고, Spring cloud config client를 체크해서 프로젝트를 생성하였습니다.

생성이 완료되었다면, resources의 application.properties를 삭제하시고, application.yml을 생성하여, 다음과 같이 작성해줍니다.

server:
  port: 8082

spring:
  config:
    import: "optional:configserver:http://localhost:8081/"
  cloud:
    config:
      name: client
      profile: test

위의 설정 정보가 의미하는 바는 아래와 같습니다.

  • server.port: 8082 -> client server의 포트를 8082번으로 맞춘다
  • spring.config.import: "optional:configserver:http://localhost:8081/" -> config server의 uri
  • spring.config.cloud.config.name: client -> 참조하고자 하는 yml 파일의 앞부분
  • spring.config.cloud.config.profile: test -> 참조하고자 하는 yml 파일의 뒷부분

저는 이번 config client에서는 github repository의 client-test.yml의 설정 정보를 가져오고 싶기 때문에, name은 client로, profile은 test로 맞춰두었습니다.

다음으로, 설정 정보를 가져오고 있는지 체크하기 위해서 get method를 하나 작성하도록 하겠습니다.

ConfigController.kt

@RestController
class ConfigController {

    @Value("\${spring.datasource.uri}")
    private lateinit var dbUri: String

    @GetMapping("/config")
    fun config(): String = dbUri
}

위의 클래스를 설명을 해드리도록 하겠습니다.

dbUri: String 의 경우에는 나중에 설정 값을 받아와서 초기화를 해야하기 때문에 private lateinit var 키워드를 붙여주고, 어노테이션으로는 설정 정보값을 받아오겠다는 어노테이션인 @Value를 사용하여 어플리케이션이 컴파일되는 시점에 값을 받아오도록 하겠습니다.

그리고 이렇게 받아온 dbUri 정보는 config() 함수를 통해서 얻어오도록 하겠습니다.

이렇게 작성을 마치셨다면 config client또한 실행을 시켜서 http://localhost:8082/config 를 통해서 값을 호출해옵니다.

그러면 아래와 같은 결과를 얻을 수 있습니다.

myEnvironment


🔨 이제 데이터를 암호화시킵시다

그런데 아직 뭔가 모자랍니다. 설정 정보는 분명히 민감한 정보인데, 정보를 주고받을 때 설정 정보를 모두 plain text로 보내고있습니다.

따라서 저희는 이를 암호화 시키고싶습니다.

설정 정보들을 암호화 시키는 것은 매우 간단합니다. 우선 config server의 application.yml를 아래와 같이 수정합니다.

server:
  port: 8081

spring:
  cloud:
    config:
      server:

        git:
          uri: https://github.com/BrianDYKim/config-test
          default-label: main 
        encrypt:
          enabled: false  

# actuator 설정
management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    shutdown:
      enabled: true
  
encrypt:
  key: key-brian

위에서 추가시킨 부분은, encrypt.enabled: false 부분과, encrypt.key: key-brian 부분입니다. 단 주의점은, encrypt.enabled: false 부분은 위의 git이라는 키워드와 인덴트를 맞춰야한다는 것입니다.

이제 각각의 추가된 설정 정보들을 설명드리겠습니다.

  • encrypt.enabled: false -> 모든 설정정보를 암호화 시키겠다는 의미
  • encrypt.key: key-brian -> 암호화를 시키는데 사용되는 key값

이제 config-server를 다시 실행시키고, 암호화를 진행하겠습니다.

postman을 켜시고, http://localhost:8081/encrypt 주소에 POST 요청으로, 암호화시키고 싶은 평문을 보내면됩니다.

POST 요청으로 얻어낸 값을 복사 붙여넣기를 하셔서, git repository의 client-test.yml을 아래와 같이 수정을 해주시면됩니다.

spring:
  datasource:
    uri: "{cipher}21cc3963f8f28de0e35db968af03a854028e90ddc68163940bdd0b0510c37262f3f1cd032945a90bf09a460b5f88b1a5"
    username: "{cipher}a89ca2204c4c49d0a24faf91e6c75ecc256319002501d9ce82da121a455225da"
    password: "{cipher}ffd5797d7a40785f07745b56eb55a9c5e5973896fdbc6dc004630a5b8a0bac11"

여기서 중요한 점은, 암호화된 정보는 모두 ""로 묶어서 앞에 {cipher} 라는 키워드를 달아주셔야한다는 것입니다.

그 다음에 config server를 다시 동작시키신 다음, config client의 application.yml 에도 encrypt key를 똑같이 추가시키고 다시 동작시킵니다.

다음에 http://localhost:8082/config 주소로 GET 요청을 보내시면, myNewEnvironment 라는 결과를 얻으실 수 있을겁니다.


🔨 이제는 git repository를 private로 돌리고, config server는 ssh 요청을 통해서 git repository를 참조하도록 바꿔보겠습니다.

이전까지의 실습은 모두 github repository가 Public인 상태 에서 진행을 하였습니다. 그런데 실무에서는 절대로 설정 정보가 담긴 repository를 public으로 열어두고 사용하지는 않을겁니다. 따라서 저희는 github repository를 일단 private로 설정을 하겠습니다.

그런데 문제는, github repository를 private로 돌리게되면, 당장에 config server는 github repository를 참조하지 못하기 때문에 오류를 뱉어냅니다. 이를 수정하겠습니다.

아래의 내용부터는 mac 기준으로 설명을 드릴 예정입니다. 윈도우에서는 git bash를 이용해서 실습을 따라오시면 되겠습니다

Terminal을 실행시키고, git에 접근하기 위한 공개키와 비밀키를 생성하겠습니다.

terminal에 아래와 같이 명령어를 입력합니다

$ ssh-keygen -m PEM -t ecdsa -b 256 -C "Github 계정" -f 키파일명

저 커맨드를 입력하고 실행하시면, 공개키와 비밀키가 생성이 되는데, 이 때 생성 과정에서 비밀번호는 입력하지 않도록합니다! 비밀번호를 입력하게 되면 config server가 오류를 뱉어냅니다.

공개키와 비밀키가 생성이 완료가 되었다면, 아래의 커맨드를 통해서 비밀키를 얻어옵니다

$ cd .ssh
$ cat 키파일명.pub

그리고 github 게정의 settings에 ssh 키를 추가해줍니다

그 다음에, terminal에서 개인키를 복사해옵니다.

$ cat 키파일명

그리고, host-key와 host-key-algorithm을 알아내기 위해 아래의 커맨드를 입력합니다

$ ssh-keyscan -t ecdsa github.com

그다음에, config server의 application.yml을 아래와 같이 수정합니다

server:
  port: 8081

spring:
  cloud:
    config:
      server:
        git:
          uri: git@github.com:BrianDYKim/config-test.git
          default-label: main
          ignore-local-ssh-settings: true
          private-key: |
            -----BEGIN EC PRIVATE KEY-----
            비밀키는 소중해요
			비밀키는 소중해요
            비밀키는 소중해요
            -----END EC PRIVATE KEY-----
          host-key: AAAA........
          host-key-algorithm: ecdsa-sha2-nistp256
        # 설정 정보 암호화 활성
        encrypt:
          enabled: false

encrypt:
  key: key-brian

management:
  endpoints:
    web:
      exposure:
        include: "*"
  endpoint:
    shutdown:
      enabled: true

private-key를 입력하실 때, |를 반드시 입력을 하시고, 다음 라인부터 인덴트에 맞춰서 반드시 작성을 해주셔야합니다.

github repository가 private이고, 이제부터는 ssh 요청을 통해서 설정 정보들을 가져오기 때문에 git uri 또한 Https가 아닌 SSH 주소로 수정을 해주셔야합니다!

그 다음에 config server를 재 실행하고, http://localhost:8082/config 를 통해서 uri 정보를 가져와보시면, 잘 가져와지는 것을 확인할 수 있으실겁니다.


🌲 글을 마치며

이것으로 spring cloud config에 대한 설명과 예제에 관한 글을 마쳤습니다.

이제 이것을 위드마켓 프로젝트에 녹여서 적용을 해보도록하겠습니다.

다음 포스트에서 뵙겠습니다. 감사합니다!

profile
Hi There 🤗! I'm college student majoring Mathematics, and double majoring CSE. I'm just enjoying studying about good architectures of back-end system(applications) and how to operate the servers efficiently! 🔥
post-custom-banner

2개의 댓글

comment-user-thumbnail
2022년 8월 27일

맨위 이미지 제가 그린 이미지인데요.
그냥 출처도 없이 함부로 가져다 쓰시네요.

1개의 답글