코드에서 config 부분을 분리하기 (nodejs)

Singsoong·2022년 11월 30일
2

nodejs

목록 보기
2/3
post-thumbnail

📌 배경

  • 코드 내에서 DB 접속 정보, 그외 비밀번호 등 보안에 민감한 정보인 설정 정보들을 하드코딩하여 사용하는 것은 코드 관리, 배포, 운영을 모두 어렵게 만들고, 보안적으로도 이슈가 생길 수도 있다.

📌 해결 방안

  • APP_CONFIG_FILE 환경변수를 통해 YAML 기반 설정파일의 경로를 설정할 수 있다.
  • 서버 실행 시 변경될 수 있는 MySQL 호스트 정보들, Redis 연결 정보 등을 인터페이스로 노출한다.
  • config 폴더 내 index.js 를 통해 앱의 config 로딩 과정을 중앙 관리한다.
    • 각 옵션 별 환경변수 값이 설정되었는지를 확인한 후 환경변수가 정의되었다면 정의된 환경변수값을 사용한다.
    • 만약, 환경변수 값이 정의되지 않았다면 환경변수인 APP_CONFIG_FILE에 명시한 경로에 위치한 YAML 설정 파일으로부터 값이 있는지를 확인한 후 사용한다.
    • APP_CONFIG_FILE에 명시한 경로에 위치한 YAML 파일에 값이 정의되지 않았다면, config/default.yaml에 정의되어 있는 기본 값을 사용하게 된다.
  • dotenv 패키지를 사용하여 런타임 시 디렉토리 내에 .env 파일이 존재한다면 해당 파일에서 환경변수 값을 불러와 사용한다.

📌 구현

📄 config/index.js

  • 먼저, dotenv 패키지를 설치한다.
$ npm i dotenv
  • JS에서 yaml 파일을 읽어들이기 위해 js-yaml 패키지를 설치한다.
$ npm i js-yaml
  • index.js
const dotenv = require("dotenv");
const yaml = require("js-yaml");
const { readFileSync } = require("fs");
const { join } = require("path");

// .env 파일로부터 환경변수 값을 읽어와서 사용한다.
dotenv.config();

// APP_CONFIG_FILE 환경변수에 YAML 파일의 경로가 정의되어 있다면 경로를 불러온다. 
const yaml_config_filename = process.env.APP_CONFIG_FILE;
let yaml_config = {};
try {
  const custom_config = yaml_config_filename
    ? yaml.load(readFileSync(yaml_config_filename, "utf8"))
    : {};
  const default_config = yaml.load(
    readFileSync(join(__dirname, "default.yaml"), "utf8")
  );
  yaml_config = {
    ...default_config,
    ...custom_config,
  };
} catch (err) {
  throw new Error(e);
}

// config 우선순위 (환경변수 > APP_CONFIG_FILE 경로의 YAML > default)
const config = {
  mysql: {
    primary: {
      host: process.env.MYSQL_PRIMARY_HOST || yaml_config.mysql.primary.host,
      port: process.env.MYSQL_PRIMARY_PORT || yaml_config.mysql.primary.port,
      username:
        process.env.MYSQL_PRIMARY_USERNAME ||
        yaml_config.mysql.primary.username,
      password:
        process.env.MYSQL_PRIMARY_PASSWORD ||
        yaml_config.mysql.primary.password,
      database:
        process.env.MYSQL_PRIMARY_DATABASE ||
        yaml_config.mysql.primary.database,
    },
  },
};

module.exports = config;

📄 default.yaml

  • 환경변수를 등록하지도 않고, APP_CONFIG_FILE 환경변수의 경로에 등록된 YAML에도 없을 때 제일 후순위로 등록되는 config 정보를 정의한다.
mysql:
  primary:
    host: ""
    port: ""
    username: ""
    password: ""
    database: ""

📌 사용

📄 .env 파일 생성

  • 디렉토리 내에 .env 파일을 만들어 환경변수를 명시한다.
MYSQL_PRIMARY_HOST=""
MYSQL_PRIMARY_USERNAME=""
MYSQL_PRIMARY_PASSWORD=""
MYSQL_PRIMARY_DATABASE=""
PORT=""

📄 APP_CONFIG_FILE

  • 등록할 환경변수에 대한 정보를 yaml에 정의하고 yaml 파일의 경로를 APP_CONFIG_FILE 환경변수에 넣는다.

📄 코드 내에서 접근하기

const config = require("../config");

const options = {
	...config.mysql.primary,
}
// 혹은,
const options = {
  host: config.mysql.primary.host,
  password: config.mysql.primary.passowrd,
  ...
}

📌 참고한 사이트

https://12factor.net/config
https://github.com/motdotla/dotenv

profile
Web Developer

1개의 댓글

comment-user-thumbnail
2023년 7월 9일

잘 읽었습니다.

  1. APP_CONFIG_FILE (yaml) 과 .env 파일을 나눠서 설정정보를 업로드하시는 것 같은데
    둘의 용도를 어떤 기준으로 나누신 것인지요?

  2. default.yaml 파일은 공개된 파일이 아닌지요?
    default.yaml 은 이 코드를 사용하는 모든 사람에게 노출될 public 한 파일로 보입니다.
    민감정보를 .env 에서 관리하고 git에 노출하지 않는 전략(ex. gitignore 에 추가)을 사용한 것으로 보이는데 default.yaml 에서 "아무런 설정값이 없으면 비밀번호까지 이 값으로 설정한다."는 행위로 정의하신 것 같아 질문드립니다.

답글 달기