๐คทโ๏ธ ๋ณธ๋ก ์ ์์
์ด์ ๊ธ์์ AWS Parameter Store ์์ฑํ๊ณ ๋งค๊ฐ๋ณ์, ๋ฌธ์์ด ์ํธํ ํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ดค์ต๋๋ค.
์ด๋ฒ๊ธ์์๋ AWS-SDK๋ฅผ ์ฌ์ฉํด์ Nest.js ํ๋ก์ ํธ์ Parameter Store ์ ๊ทผํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ฒ ์ต๋๋ค.
[NestJS] AWS Parameter Store AWS-SDK ํ๋ก์ ํธ 2ํ
2024.09.05 - [Nest.js] - [NestJS] AWS Parameter Store ํ๋ก์ ํธ 2ํ
[NestJS] AWS Parameter Store AWS-SDK ํ๋ก์ ํธ 1ํ
2024.09.04 - [Nest.js] - [NestJS] AWS Parameter Store ํ๋ก์ ํธ 1ํ
๐คทโ๏ธ AWS-SDK ์ธํ ๋ฐ Parameter Store ์ ๊ทผ ๋ฐฉ๋ฒ
Nest.js ํ๋ก์ ํธ์์ ์ฝ๋๋ก Parameter Store ์ ๊ทผํ๊ธฐ ์ํด์๋ ๋จผ์ AWS-SDK๋ฅผ ์ค์นํด์ผํฉ๋๋ค.
1. AWS SDK ์ค์น
npm install --save @aws-sdk/client-ssm
2. Nest.js config ๊ตฌ์กฐ ์ธํ
config.module.ts ์์ฑ
ConfigModule๋ฅผ ์ ์ญ์์ ์ฌ์ฉํ ์ ์๋๋ก ์๋น์ค์ ๋ฑ๋กํฉ๋๋ค.
// config.module.ts
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import EnvConfig from './env.config';
@Module({
imports: [
ConfigModule.forRoot({
isGlobal: true,
envFilePath: `.env`,
load: [EnvConfig],
}),
],
})
export class AppConfigModule {}
env.config.ts ์์ฑ
import { AwsConfigService } from './aws-config.service';
export default async () => {
const awsConfigService = new AwsConfigService();
await awsConfigService.loadConfig();
return awsConfigService.getConfig();
};
export default async () => {}๋ ์ต๋ช ํจ์๋ฅผ ์ ์ธํ๊ณ ๋ค๋ฅธ ํ์ผ์์ ํจ์๋ฅผ import ์ ๋ฐ๋ก ํจ์๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ์คํ๋๋๋ก ํฉ๋๋ค.
ConfigModule์ load ์ต์ ์์ env.config.ts ํจ์๊ฐ ๋น๋๊ธฐ์ ์ผ๋ก ์ฆ์ ์คํํด์ ์ค์ ๊ฐ์ ์ธํ ํด์ฃผ๋ ๋ก์ง์ ๋๋ค.
aws-config.service.ts ์์ฑ
import { GetParametersByPathCommand, SSMClient } from '@aws-sdk/client-ssm';
import { Logger } from '@nestjs/common';
export class AwsConfigService {
private readonly ssmClient: SSMClient;
private config: Record<string, string> = {};
private logger = new Logger(AwsConfigService.name);
constructor() {
this.ssmClient = new SSMClient({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ENV_ACCESS_KEY,
secretAccessKey: process.env.AWS_ENV_SECRET_ACCESS_KEY,
},
});
}
// ๋ก์ปฌ ENV / AWS ๋ฐ์ดํฐ ๊ฐ์ ธ์ฌ ์ ์๋๋ก ๊ตฌ์ฑ
public async loadConfig() {
try {
const env = process.env.NODE_ENV || 'development';
const path = `/YOUR PATH/${env}/`;
const getAllParameters = async (path: string) => {
let parameters = [];
let nextToken: string | undefined;
do {
const command = new GetParametersByPathCommand({
Path: path,
Recursive: true,
WithDecryption: true,
NextToken: nextToken, // NextToken์ ์ฌ์ฉํ์ฌ ํ์ด์ง๋ค์ด์
์ฒ๋ฆฌ
});
const response = await this.ssmClient.send(command);
if (response.Parameters) {
parameters = parameters.concat(response.Parameters);
}
nextToken = response.NextToken; // ๋ค์ ํ์ด์ง๊ฐ ์์ผ๋ฉด NextToken์ด ์ค์ ๋จ
} while (nextToken);
return parameters;
};
const result = await getAllParameters(path);
if (result) {
for (const param of result) {
if (param.Name && param.Value) {
const key = param.Name.replace(path, '');
this.config[key] = param.Value.replace(/\\\\n/g, '\\n');
}
}
}
} catch (error) {
this.logger.error('AWS SSM ์ ๊ทผ ์คํจ', error);
}
}
get(key: string): string {
// ๋ก์ปฌ์์ ์คํํ ๊ฒฝ์ฐ
if (process.env.ENV_LOCAL === 'true') {
return process.env[key] || '';
}
return this.config[key] || process.env[key] || '';
}
getConfig() {
return {
redis: {
url: `redis://${this.get('REDIS_URL')}:${this.get('REDIS_PORT')}`,
},
AWS_REGION: this.get('AWS_REGION'),
AWS_S3_ACCESS_KEY: this.get('S3_ACCESS_KEY_ID'),
AWS_S3_SECRET_ACCESS_KEY: this.get('S3_SECRET_ACCESS_KEY'),
AWS_S3_BUCKET_NAME: this.get('AWS_S3_BUCKET_NAME'),
NICE_API_KEY: this.get('NICE_API_KEY'),
firebase: {
type: this.get('FIREBASE_TYPE'),
project_id: this.get('FIREBASE_PROJECT_ID'),
private_key_id: this.get('FIREBASE_PRIVATE_KEY_ID'),
private_key: this.get('FIREBASE_PRIVATE_KEY'),
client_email: this.get('FIREBASE_CLIENT_EMAIL'),
client_id: this.get('FIREBASE_CLIENT_ID'),
auth_uri: this.get('FIREBASE_AUTH_URI'),
token_uri: this.get('FIREBASE_TOKEN_URI'),
auth_provider_x509_cert_url: this.get('FIREBASE_AUTH_PROVIDER_X509_CERT_URL'),
client_x509_cert_url: this.get('FIREBASE_CLIENT_x509_CERT_URL'),
universe_domain: this.get('FIREBASE_UNIVERSE_DOMAIN'),
},
};
}
}
SSMClient ์ด๊ธฐ ์ ํ
constructor() {
this.ssmClient = new SSMClient({
region: process.env.AWS_REGION,
credentials: {
accessKeyId: process.env.AWS_ENV_ACCESS_KEY,
secretAccessKey: process.env.AWS_ENV_SECRET_ACCESS_KEY,
},
});
}
- SSMClient ์ธ์คํด์ค๋ฅผ ์ค์ ํฉ๋๋ค.
- ์๋น์ค ์์ฑ์ง์ญ region๊ณผ ๋ฐ๊ธ๋ฐ์ accessKeyId, secretAccessKey๋ฅผ ์์ฑํฉ๋๋ค.
- accessKeyId, secretAccessKey ํ๋ก์ ํธ .env ํ์ผ์ ์ถ๊ฐํฉ๋๋ค.
GetParametersByPathCommand API ํ์ฉ
const command = new GetParametersByPathCommand({
Path: path,
Recursive: true,
WithDecryption: true, //์ํธํ๋ ํ๋ผ๋ฏธํฐ์ธ ๊ฒฝ์ฐ true๋ก ์ค์
NextToken: nextToken, // NextToken์ ์ฌ์ฉํ์ฌ ํ์ด์ง๋ค์ด์
์ฒ๋ฆฌ
});
- GetParametersByPathCommand API ํ์ฉํด์ Parameter Store์ ๊ฐ๋ค์ ๋ถ๋ฌ์ต๋๋ค.
- GetParameterCommand ๋ง๊ณ GetParametersByPathCommand ์ฌ์ฉํ ์ด์ ๋ Path ๋ณ๋ก Parameter Store ๊ฐ๋ค์ ์ ๊ทผํ๊ธฐ ์ํด์์ ๋๋ค.
- IAM ๊ถํ์ ๋ฐ๋ผ์ Parameter Store ์ ๊ทผ API ์ฌ์ฉ์ด ๊ฐ๋ฅํฉ๋๋ค.
GetParametersByPath ์ค๋ฌด์์ ์ฌ์ฉ๋ฒ
const getAllParameters = async (path: string) => {
let parameters = [];
let nextToken: string | undefined;
do {
const command = new GetParametersByPathCommand({
Path: path,
Recursive: true,
WithDecryption: true,
NextToken: nextToken, // NextToken์ ์ฌ์ฉํ์ฌ ํ์ด์ง๋ค์ด์
์ฒ๋ฆฌ
});
const response = await this.ssmClient.send(command);
if (response.Parameters) {
parameters = parameters.concat(response.Parameters);
}
nextToken = response.NextToken; // ๋ค์ ํ์ด์ง๊ฐ ์์ผ๋ฉด NextToken์ด ์ค์ ๋จ
} while (nextToken);
return parameters;
};
GetParametersByPath API ์ฌ์ฉ ์ ์ ์์ฌํญ
- ๋ฐํํ ํ๊ฒฝ๋ณ์ ํญ๋ชฉ ์: ์ด API๋ ํ ๋ฒ์ ์์ฒญ์ผ๋ก ์ต๋ 10๊ฐ์ ํ๊ฒฝ๋ณ์ ํญ๋ชฉ์ ๋ฐํํฉ๋๋ค. (์ต์ 1๊ฐ, ์ต๋ 10๊ฐ)
- NextToken ํ์ฉ: ๋ง์ฝ ์์ฒญ ๊ฒฝ๋ก์ 10๊ฐ ์ด์์ ํ๊ฒฝ๋ณ์๊ฐ ์กด์ฌํ๋ ๊ฒฝ์ฐ, ๋ฐํ๋ ์๋ต์ NextToken์ด ํฌํจ๋ฉ๋๋ค. ์ด NextToken์ ์ด์ฉํด ์ถ๊ฐ ์์ฒญ์ ๋ณด๋ด๋ฉด, 10๊ฐ ์ด์์ ํ๊ฒฝ๋ณ์๋ฅผ ์์ฐจ์ ์ผ๋ก ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
GetParametersByPathCommand ๊ณต์๋ฌธ์
๐คทโ๏ธ ๋ง์ง๋ง์ผ๋ก
ํ๊ฒฝ ๋ณ์๋ฅผ ์ค์์์ ๊ด๋ฆฌํ๋ ๊ณผ์ ๊ณผ AWS์ Parameter Store ๊ธฐ๋ฅ, AWS SDK ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋ํด ๋ค๋ค์ต๋๋ค.
.env ํ์ผ ๊ด๋ฆฌ์ ์ค์ ์ง์ค์ ํ๊ฒฝ ๋ณ์ ๊ด๋ฆฌ ์ค ์ด๋ ๊ฒ์ด ๋ ์ข์์ง๋ ์ ๋ต์ด ์์ต๋๋ค.
๊ฐ๊ฐ์ ๋ฐฉ๋ฒ์๋ ์ฅ๋จ์ ์ด ์์ผ๋ฉฐ, ํ ๋ฌธํ์ ํ๋ก์ ํธ ์ด์ ๋ฐฉ์์ ๋ง์ถฐ ์ ํํ๋ ๊ฒ์ด ์ต์ ์ ๋๋ค.
์ ๋ Parameter Store์ ์์ ์ฑ, ์ค์ ๊ด๋ฆฌ, ์๋ํ ๊ฐ๋ฅ์ฑ์ ๋ํด ๊ธ์ ์ ์ผ๋ก ํ๊ฐํ๋ฉฐ ์์ผ๋ก๋ ํ๋ก์ ํธ์ ์ ๊ทน ํ์ฉํ ๊ณํ์ ๋๋ค.
์ฌ๋ฐ๋ ์ค๋์ ๋ ๋ณ ์ด์ธ ๋ณด๊ณ ๊ฐ์ธ์!
https://cometruedream.tistory.com/247
https://cometruedream.tistory.com/243
https://cometruedream.tistory.com/242
https://cometruedream.tistory.com/241
https://cometruedream.tistory.com/244
'Nest.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[NestJS] AWS Parameter Store ํ๋ก์ ํธ 2ํ (0) | 2024.09.05 |
---|---|
[NestJS] AWS Parameter Store ํ๋ก์ ํธ 1ํ (2) | 2024.09.04 |
NestJS Lifecycle (์๋ช ์ฃผ๊ธฐ) ๊ฐ๋ (1) | 2024.05.07 |
Nest.js - ํํ ์ค ์ข ํฉ์๋์ธ API ํ์ฑ (25) | 2023.05.15 |
Nest.js Middleware logger (15) | 2022.12.05 |