spring boot 3.2에서 aws parameter store 적용하기

Denia·2024년 1월 1일
1

TroubleShooting

목록 보기
10/25

최근에 사이드 프로젝트를 하나 진행하고 있다.
배포도 생각중이라 DB 정보를 어떻게 관리해야 하나 고민을 하던 와중에 우연치 않게 aws parameter store에 대해서 듣게 되었다.

가격도 공짜에 사이드 프로젝트에 적용하기에 너무 괜찮은 옵션이라 바로 사용해보기로 했다.

우선 aws parameter store 검색을 해보니 대부분 spring boot 2.X 버전에 대해서만 게시글들이 많았고, 3.X 버전에 대해서는 게시글이 적었다.

그래서 나도 누군가에게 도움이 되었으면 하는 바람으로 spring boot 3.2에 aws parameter store를 적용한 후기에 관해서 기록을 남겨본다.


우선 참고한 블로그는 여러가지가 많지만 제일 큰 도움을 받은 블로그는 해당 블로그들이다.


1. aws parameter store 관련 의존성 추가

Spring Cloud AWS 3.1.0 Reference Docs 2.1. Bill of Materials 항목을 보면 maven이랑 gradle에 의존성을 추가하는 방법에 대해서 나와있다.

gradle에 의존성 추가하는 방법

dependencies {
  implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:${springCloudAwsVersion}")
  // Replace the following with the starter dependencies of specific modules you wish to use
  implementation 'io.awspring.cloud:spring-cloud-aws-starter-sqs'
}

이걸 parameter store 모듈을 사용하면서, spring boot 3.2 버전에 맞추도록 코드를 수정하면 다음과 같다.

    //AWS Parameter Store
    implementation platform("io.awspring.cloud:spring-cloud-aws-dependencies:3.1.0")
    implementation 'io.awspring.cloud:spring-cloud-aws-starter-parameter-store'

spring-cloud-aws Github을 보면 spring boot 3.2.x 버전은 spring cloud aws 3.1.x 버전을 쓰라고 나와있다.

2. paramter를 받아올 수 있도록 properties 파일에 spring.config.import 추가하기

(※ 저는 yaml 파일을 더 선호해서 properties 파일 대신에 yaml을 사용했습니다.)

spring.config.import를 추가할 때 기존 2.X 버전이랑 많이 달라져서 고생을 조금 했습니다.

위에 참고한 블로그 글이랑 Loading External Configuration을 살펴보면 spring.config.import을 추가할 때 Key를 같이 추가해줘야 합니다.

#properties
spring.config.import=aws-parameterstore:/config/spring
#yaml
spring:
  config:
    import: aws-parameterstore:/config/spring

그리고 저는 이렇게 세팅해서 사용하고 있습니다.

config:
  type: aws-parameterstore:/config/example/

spring:
  config:
    activate:
      on-profile: prod
    import: ${config.type}

  datasource:
    url: ${jdbc.url}
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: ${jdbc.username}
    password: ${jdbc.password}

여기에 약간 특이한 점은 /config/example 가 아니라 /config/example/를 사용하고 있다는 것인데 해당 내용에 관해서는 아래에서 설명하겠습니다.

※ import 추가할 때 발생한 이슈

2.X 버전에서 사용했던 것처럼 Key를 추가하지 않은 상태로 import를 하게 되면 에러가 발생합니다.

# 2.X 버전에서 하던 것 처럼 사용해봄

# yaml
spring:
  config:
    import: 'aws-parameterstore:'
aws:
  paramstore:
    enabled: true
    prefix: /config
    profile-separator: _
    name: spring

Could not import properties from AWS Parameter Store: No Parameter Store keys provided in spring.config.import=aws-parameterstore: configuration.

03:41:54.228 [main] ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter -- 

***************************
APPLICATION FAILED TO START
***************************

Description:

Could not import properties from AWS Parameter Store: No Parameter Store keys provided in `spring.config.import=aws-parameterstore:` configuration.

Action:

Consider providing keys, for example `spring.config.import=aws-parameterstore:/config/app`

3. aws parameter store 세팅하기

aws 사이트에 접속 후 검색 창에 Systems Manager를 치면 서비스가 뜬다.

왼쪽을 보면 사용 가능한 서비스들이 있는데 거기서 파라미터 스토어를 찾아서 클릭

파라미터 생성을 클릭 후 이름과 필요한 내용을 기입 후 파라미터를 생성하면 된다.
그리고 이름을 제일 신경써서 작성하도록 하자.

이름으로는 아까 yaml에서 import 할 때 사용한 key변수명을 조합한 값을 사용한다.

key : /config/example/
변수명 (${ }안의 값) : jdbc.url


특징으로는 값 변경은 가능하지만, 이름 변경은 불가능하다.

3-1. IAM 역할 생성

EC2에서 parameter store를 사용하기 위해서는 EC2에게 parameter store에 접근할 수 있도록 권한을 부여해야 한다.

EC2에 IAM을 설정해주기 전에 EC2가 parameter store를 볼 수 있도록 IAM 역할을 하나 새롭게 생성하자.

IAM 서비스에 들어가, 역할을 새롭게 하나 생성한다.

  1. 엔터티 유형으로는 AWS 서비스 선택, 사용 사례는 EC2 선택
  2. 추가할 권한은 AmazonSSMReadOnlyAccess 정책이다.
  3. 역할 이름은 내가 잘 기억할수 있도록 설정하자. Ex) ec2-readOnly-parameter-store

3-2. EC2에 IAM 역할 부여

IAM을 생성했으므로 EC2에 IAM 역할을 부여하자.

EC2 서비스에 들어간 후, 인스턴스 탭을 누른다.
parameter store를 사용할 EC2에 대고 마우스 우클릭을 누르면 여러 옵션이 뜨는데
거기서 보안 -> IAM 역할수정 을 연달아서 클릭

위에서 생성한 IAM 역할을 부여하자.

4. spring boot 빌드 후 EC2에서 jar 파일을 실행시켜 보자.

실행시켜 보면 해당 문구가 뜨면서 parameter store에서 parameter들을 읽어 온다는 것을 알 수 있다.

2024-01-01T16:30:40.258Z  INFO 60395 --- [           main] .a.c.a.c.p.ParameterStorePropertySources : Loading property from AWS Parameter Store with name: /config/example/, optional: false

※ /config/example 대신 /config/example/ 사용한 이유

해당 블로그 글에서도 있는 내용인데 ParameterStorePropertySourcegetParameters(GetParametersByPathRequest paramsRequest)를 실행하면서 가져올 parameter의 이름을 추출하게 된다.

	//전체 코드
    private void getParameters(GetParametersByPathRequest paramsRequest) {
        GetParametersByPathResponse paramsResult = ((SsmClient)this.source).getParametersByPath(paramsRequest);
        Iterator var3 = paramsResult.parameters().iterator();

        while(var3.hasNext()) {
            Parameter parameter = (Parameter)var3.next();
            String key = parameter.name().replace(this.parameterPath, "").replace('/', '.').replaceAll("_(\\d)_", "[$1]");
            LOG.debug("Populating property retrieved from AWS Parameter Store: " + key);
            String propertyKey = this.prefix != null ? this.prefix + key : key;
            this.properties.put(propertyKey, parameter.value());
        }

        if (paramsResult.nextToken() != null) {
            this.getParameters((GetParametersByPathRequest)paramsRequest.toBuilder().nextToken(paramsResult.nextToken()).build());
        }

    }

이때 메서드를 진행하면서 this.parameterPath""로 그리고 /값을 .로 변경시키는데 이 부분 때문에 조금 귀찮은 일이 발생한다.

//주의해서 볼 부분
String key = parameter.name().replace(this.parameterPath, "").replace('/', '.').replaceAll("_(\\d)_", "[$1]");

여기서 this.parameterPath는 우리가 import 할 때 추가한 key 값이다.
/config/example/ <<< 이 부분

ParameterStorePropertySource 클래스가 parameter store에서 parameter들을 다 가져오고, 이름을 key로 추출한 다음, 해당 하는 property에 key, value 값을 넣어준다.


우리가 aws parameter store에 등록한 parameter 이름은/config/example/jdbc.url이므로 이걸로 이름이 key로 변하는 예시를 들어보면

  1. /config/example/jdbc.url에서 /config/example/을 없애면 jdbc.url가 된다.
  2. / 가 없으므로 jdbc.urlkey 값으로 해서 해당하는 value를 property에 넣는다.
  3. 우리가 사용하는 변수명으로 jdbc.url가 있으므로 정상적으로 값이 주입된다.

우리가 만약에 import 할 때 /config/examplekey 값으로 썼으면 어떻게 됐을까?

  1. /config/example/jdbc.url에서 /config/example을 없애면 /jdbc.url가 된다.
  2. / 가 있으므로 .로 변환하면, .jdbc.urlkey 값으로 해서 해당하는 value를 property에 넣는다.
  3. 우리가 사용하는 변수명은 jdbc.url인데, 주입된 key.jdbc.url이므로 정상적으로 값 주입이 되지 않아서 값을 읽어오지 못한다.
  4. parameter 이름은 변경이 불가능하므로, 새롭게 /config/examplejdbc.url로 parameter를 만들던가, 사용하는 변수명으로 ${jdbc.url} 대신에 ${.jdbc.url}를 사용해야한다.

개인적으로 ${jdbc.url}가 조금 더 가독성이 좋은 것 같아서 import 할 때 key 값을 /config/example/로 사용했다.

profile
HW -> FW -> Web

0개의 댓글