Spring 코드를 작성하다가 JWT 토큰 혹은 암호화 키 값 등과 같이 코드 내에 중요 설정 값을 하드코딩되어 있는 것을 보고 보안 상 취약할 거 같아 관련 레퍼런스들을 찾아보니, AWS Parameter Store
를 통해 키/값을 저장하고 코드 내에서 키를 통해 불러올 수 있는 것을 알아냈다.
하지만, 현재 필자는 Spring boot 2.7.0 버전을 사용하고 있는데 2.4.0 버전 이상부터 application 리소스 설정하는 방식이 바뀌어서 기존에 나와 있는 레퍼런스를 그대로 참고해서는 제대로 동작을 안 했다. 그래서 이번 기회에 최신 버전으로 동작하는 코드를 정리해보려고 한다.
추가로, 이번 기회에 Spring boot 2.4.0 이전 버전에서 파라미터 스토어를 사용하다가 2.4.0 버전 이상으로 마이그레이션 하는 분들이 보면 도움이 될 것 같다. 이번 2.4.0 버전 이상부터는 .properties
혹은 .yml
파일과 같은 애플리케이션 설정 파일 이름을 커스터마이징하면 불러오지 않는데, 기존 방식에서는 bootstrap.yml
파일에 파라미터 스토어 키/값을 정의하기 때문에 반영이 되지 않는다. 물론 예외로 처리할 수 있는 방식(use-legacy-processing
설정)은 있지만.. 기본적으로 권장하는 방식을 사용하고자 한다.
실습 환경
- AWS
- System Manager > Parameter Store
- IAM
- CLI
- java 17 (corretto)
- Gradle 7.4.1
- Spring boot 2.7.0
코드 작성
의존성 추가
...
dependencyManagement {
imports {
mavenBom "io.awspring.cloud:spring-cloud-aws-dependencies:2.4.2"
}
}
...
dependencies {
...
// https://mvnrepository.com/artifact/io.awspring.cloud/spring-cloud-starter-aws-parameter-store-config
implementation group: 'io.awspring.cloud', name: 'spring-cloud-starter-aws-parameter-store-config', version: '2.4.2'
...
}
application.yml 설정
spring:
config:
activate:
on-profile: local
import: 'aws-parameterstore:'
aws:
paramstore:
enabled: true
prefix: /southouse
name: common-parameter
profileSeparator: _
참고 사이트 부분에 property 설정에 대한 설명이 있지만, 지금 사용하는 것에 대해서 간략하게 설명하자면,
aws.paramstore.enabled
= 사용 여부 설정aws.paramstore.prefix
= 파라미터 스토어 키 이름 중 가장 앞, 첫번째에 위치aws.paramstore.name
= 파라미터 스토어 키 이름 중 두번째에 위치aws.paramstore.profileSeparator
= 파라미터 스토어 키 이름 중 name 부분에서 profile 구분자 역할
위의 설정에 따르면 파라미터 스토어의 키 이름은 다음과 같은 구조가 된다.
/southouse/common-parameter_{SPRING_PROFILES_ACTIVE}
만약 profile을 local
, dev
, prod
로 구분한다면,
/southouse/common-parameter_local
/southouse/common-parameter_dev
/southouse/common-parameter_prod
로 구성을 해놓으면 알아서 profile에 따라 해당 파라미터 스토어 값을 찾게 된다.
클래스 생성
@Getter
@NoArgsConstructor
@Configuration
public class ParameterStoreProperties {
@Value("${jwt.secretkey}")
private String jwtSecretKey;
}
properties 파일에 설정된 파라미터 스토어 값을 불러오는 클래스이다.
기존처럼 properties 값을 불러오는 @Value
어노테이션을 사용하여 불러온다.
단, Value 어노테이션 값이 위의 /southouse/common-parameter_{SPRING_PROFILES_ACTIVE}/{VALUE_NAME}
구조 세번째에 위치하는 가장 마지막 값이 된다.
따라서, 파라미터 스토어에 다음과 같은 이름을 가진 키를 정의하면 된다.
/southouse/common-parameter_local/jwt.secretkey
/southouse/common-parameter_dev/jwt.secretkey
/southouse/common-parameter_prod/jwt.secretkey
이제 AWS에서 파라미터 스토어 키/값을 설정해보도록 하자.
AWS 설정
파라미터 스토어에 키/값 설정
파라미터 이름은 위에 애플리케이션 코드에서 지정한 이름 규칙대로 설정하면 되고, 유형은 중요한 값이기 때문에 보안 문자열을 선택하도록 하자.
이제, 애플리케이션에서 실제로 사용을 해보기 위해서는 AWS SSM 파라미터 스토어를 읽을 수 있는 권한을 가진 IAM 액세스 키 발급이 필요하다. 해당 포스팅에서는 IAM 발급에 대해서 자세하게 다루진 않겠다.
IAM 계정 발급
IAM 액세스 키를 사용할 예정이기 때문에, '액세스 키 - 프로그래밍 방식 액세스' 를 체크하여 다음으로 넘어간다.
❯ aws configure
AWS Access Key ID [None]: 액세스 키 입력
AWS Secret Access Key [None]: 시크릿 키 입력
Default region name [None]: ap-northeast-2
Default output format [None]: json
생성한 IAM 계정의 액세스 키와 비밀 액세스 키를 aws-cli
를 이용하여 현재 PC에 등록한다.
참고로 지금은 IAM 계정을 발급 받아 사용하지만, 나중에 애플리케이션을 EC2 혹은 ECS와 같은 AWS 컴퓨팅 리소스에 배포하게 된다면 보안 상 액세스 키를 발급 받아 사용하기 보단 IAM 역할
을 등록하여 사용하는 편이 좋다.
테스트 코드 작성
@ExtendWith(SpringExtension.class)
@ActiveProfiles("local")
@SpringBootTest
public class ParameterStorePropertiesTest {
@Autowired
private ParameterStoreProperties properties;
@Test
void local_파라미터를_가져온다() throws Exception {
assertEquals(properties.getJwtSecretKey(), "southouse");
}
}
마지막으로 다시 코드로 넘어와서, 테스트 코드를 작성하여 테스트 해보면 된다!
추가로, 파라미터 스토어로 설정하는 파라미터는 동적으로 값이 할당이 안 된다고 한다.
예를 들면, 애플리케이션을 실행한 뒤에 파라미터 스토어에서 값을 바꾸게 되더라도 불러오는 값은 예전 값으로 계속 불러온다고 하니까 사용할 때 주의를 해야한다. 자세한 내용은 아래에 나와 있는 참고 사이트 중 향로님 블로그를 참고하면 된다.
참고 사이트