군붕이의 메모장

[Nest.js] AWS Parameter Store를 통해 환경변수 관리하기 본문

웹 개발/백엔드

[Nest.js] AWS Parameter Store를 통해 환경변수 관리하기

초보군붕이 2023. 7. 8. 15:24
반응형

여러명이서 프로젝트를 진행하다보면 환경변수 관리가 불편해진다.

 

이 때 도입할수 있는 방식이 AWS에서 제공하는 Parameter Store 이다.

 

Parameter Store를 사용하면 환경변수를 관리를 중앙화 할 수 있다.

 

 

● AWS Parameter Store

우선 AWS 공식문서에 따르면 아래와 같은 서비스로 소개하고있다.

AWS Systems Manager의 기능인 Parameter Store는 구성 데이터 관리 및 암호 관리를 위한 안전한 계층적 스토리지를 제공합니다.

이러한 서비스를 통해서 중요한 데이터를 중앙화하여 관리가 가능하다.

https://docs.aws.amazon.com/ko_kr/systems-manager/latest/userguide/systems-manager-parameter-store.html

 

AWS Systems Manager Parameter Store - AWS Systems Manager

SecureString 파라미터의 값만 암호화됩니다. 파라미터 이름, 설명 및 기타 속성은 암호화되지 않습니다.

docs.aws.amazon.com

 

 

● 기존 환경변수 관리방식

환경변수

 

노드 프로젝트의 경우 환경변수를 .env 파일을 통해서 관리하게 된다.

하지만 환경변수가 추가/삭제/변경되면 해당 내용을 다른 개발자에게 공유하고 최신화를 해야한다.

자동화를 좋아하는 사람으로써 이러한 작업은 매우 귀찮다..

 

 

● 변경된 환경변수 관리방식

파라미터 스토어

사진에서 보는 방식 그대로 Parameter Store를 통해서 환경변수를 관리할 수 있다.

환경변수 등록과정과 해당 데이터를 가져오는 모듈을 따로 만들어야되지만 기존 과정보다는 편할것으로 예상된다.

 

 

● Parameter Store에 환경변수 저장하기

우선 Parameter Store로 이동한다.

아래 경로의 Region은 서울로 되어있지만 다른곳에서 관리하고 싶을경우 다른 Region으로 이동하면 된다.

https://ap-northeast-2.console.aws.amazon.com/systems-manager/parameters/?region=ap-northeast-2&tab=Table 

 

https://ap-northeast-2.console.aws.amazon.com/systems-manager/parameters/?region=ap-northeast-2&tab=Table

 

ap-northeast-2.console.aws.amazon.com

 

Parameter Store

파라미터 생성 버튼을 클릭해서 새로운 값을 등록할 수 있다.

 

 

Parameter Store 값 등록화면

우선 파라미터 스토어에는 일반 문자열로 저장하거나 JSON 형식으로 저장하거나 원하는 형식으로 저장이 가능하다.

나의 경우 /my_app/development/database로 지정하고 JSON 형식의 데이터를 저장해줬다.

 

/my_app/development/database/host 형식으로 단순 문자열도 저장이 가능한데, 이는 취향대로 하면 될것같다.

 

 

● AWS-SDK를 통한 Parameter Store 접근

우선 nodejs에서 AWS에서 제공하는 서비스를 코드 상에서 접근하기 위해서는 AWS-SDK를 사용해야 한다.

npm install --save @aws-sdk/client-ssm

 

나의 경우 Parameter Store에 접근하기 위한 모듈(MyConfigModule)을 따로 작성했다.

my-config 모듈

 

 

 

먼저 my-config.module.ts 내용이다. 이는 별건없다.

import { Module } from '@nestjs/common';
import MyConfigService from './my-config.service';

@Module({
  providers: [MyConfigService],
  exports: [MyConfigService],
})
export default class MyConfigModule {}

 

다음은 my-config.service.ts 내용이다. 

import { Injectable, InternalServerErrorException } from '@nestjs/common';
import {
  GetParameterCommand,
  SSMClient,
  SSMClientConfig,
} from '@aws-sdk/client-ssm';
import { DatabaseConfig } from './interfaces/my-config.interface';

@Injectable()
export default class MyConfigService {
  private readonly ssmClient: SSMClient;
  private readonly ssmClientConfig: SSMClientConfig;

  constructor() {
    this.ssmClientConfig = {
      region: process.env.IAM_REGION,
      credentials: {
        accessKeyId: process.env.IAM_ACCESS_KEY_ID,
        secretAccessKey: process.env.IAM_SECRET_ACCESS_KEY,
      },
    };

    this.ssmClient = new SSMClient(this.ssmClientConfig);
  }

  // Example of How to get JSON Format Data to Object
  async getDatabaseConfig(): Promise<DatabaseConfig> {
    const name = 'database';

    try {
      const value = await this.getValue(name);
      const databaseConfig: DatabaseConfig = JSON.parse(value);

      return databaseConfig;
    } catch (err: any) {
      throw new InternalServerErrorException();
    }
  }

  // Example of How to get String Format Data to String
  async getAdminId(): Promise<string> {
    const name = 'admin/id';

    try {
      const value = await this.getValue(name);
      return value;
    } catch (err: any) {
      throw new InternalServerErrorException();
    }
  }

  private async getValue(name: string): Promise<string> {
    const command = new GetParameterCommand({
      Name: `/my_app/${process.env.NODE_ENV}/${name}`,
      WithDecryption: true,
    });
    const response = await this.ssmClient.send(command);
    const value = response.Parameter.Value;
    return value;
  }
}
  • MyConfigService → constuctor() {}
    • SSMClient에 제공할 config 내용을 정의해준다.
    • region, credentials(accessKeyId, secretAccesskey)를 작성해준다. 이는 미리 .env에 넣어두자
  • JSON 데이터를 객체로 변환해서 반환하기
    • 하단에 정의한 private getValue 메소드에서 parameter store의 값을 가져온다.
    • 그 후 JSON.parse()를 통해서 객체 형식의 데이터를 반환해준다
  • 일반 텍스트 데이터를 반환하기
    • 위와 동일하게 private getValue 메소드에서 parameter store의 값을 가져온다.
    • 그 후 해당 값을 반환한다.

 

위 방식으로 환경변수를 처리하면 아무래도 기존 configService 방식보다는 코드의 양과 따로 작업해야할게 늘어나긴한다.

 

하지만 .env로 관리하면서 매번 최신화 해주는것보단 나은것같다.

 

 

 

● 고민거리?

MyConfigService에서는 특정 데이터에 대해서 가져오도록 메소드명을 설정했다.

 

하지만 이렇게 되면 데이터를 가져올때마다 메소드가 하나씩 추가된다.

 

이를 해결하는 방법은 get@@@ 메소드에 인자로 name값을 받는것이다.

 

하지만 parameter store의 key 값이 바뀐다면 모든 파일에서 다 바꿔줘야된다. 상당히 귀찮다.

 

어떤게 더 좋은 방법인지는 조금더 고민이 필요할듯하다.

반응형