diff --git a/packages/arc-auth/.env.schema b/packages/arc-auth/.env.schema new file mode 100644 index 0000000..1a98bc6 --- /dev/null +++ b/packages/arc-auth/.env.schema @@ -0,0 +1,15 @@ +NODE_ENV= +LOG_LEVEL= +DB_HOST= +DB_PORT= +DB_USER= +DB_PASSWORD= +DB_DATABASE= +DB_SCHEMA= +REDIS_HOST= +REDIS_PORT= +REDIS_URL= +REDIS_PASSWORD= +REDIS_DATABASE= +JWT_SECRET= +JWT_ISSUER= diff --git a/packages/arc-auth/cdk/src/common/stacks/lambda.stack.ts b/packages/arc-auth/cdk/src/common/stacks/lambda.stack.ts index 13b9807..e60149a 100644 --- a/packages/arc-auth/cdk/src/common/stacks/lambda.stack.ts +++ b/packages/arc-auth/cdk/src/common/stacks/lambda.stack.ts @@ -2,6 +2,7 @@ import * as random from '@cdktf/provider-random'; import {ILambdaWithApiGateway, LambdaWithApiGateway} from 'arc-cdk'; import {TerraformStack} from 'cdktf'; import {Construct} from 'constructs'; +import {getEnv, getSecurityGroup, getSubnetIds} from '../../env'; import {AwsProvider} from '../constructs/awsProvider'; import path = require('path'); @@ -9,7 +10,7 @@ export class LambdaStack extends TerraformStack { constructor( scope: Construct, id: string, - config: Omit, + config: Omit, ) { super(scope, id); @@ -20,7 +21,7 @@ export class LambdaStack extends TerraformStack { const pet = new random.pet.Pet(this, 'random-name', { length: 2, }); - + const env = getEnv(this); // overwrite codePath based on useImage as deploy via docker needs different codePath config.codePath = path.resolve( config.codePath, @@ -31,6 +32,29 @@ export class LambdaStack extends TerraformStack { // NOSONAR ...config, name: pet.id, + vpcConfig: { + securityGroupIds: getSecurityGroup(this), + subnetIds: getSubnetIds(this), + }, + envVars: { + DB_HOST: env.DB_HOST || '', + DB_PORT: env.DB_PORT || '', + DB_USER: env.DB_USER || '', + DB_PASSWORD: env.DB_PASSWORD || '', + DB_DATABASE: env.DB_DATABASE || '', + DB_SCHEMA: env.DB_SCHEMA || '', + JWT_SECRET: env.JWT_SECRET || '', + JWT_ISSUER: 'sourcefuse', + PORT: '3005', + LOG_LEVEL: 'info', + DB_CONNECTOR: 'postgresql', + }, + customDomainName: { + domainName: env.DOMAIN_NAME || '', + hostedZoneId: env.HOSTED_ZONE_ID || '', + }, + namespace: env.NAMESPACE || '', + environment: env.ENV || '', }); } } diff --git a/packages/arc-auth/cdk/src/common/stacks/migration.stack.ts b/packages/arc-auth/cdk/src/common/stacks/migration.stack.ts index 53ab1ca..bad2aee 100644 --- a/packages/arc-auth/cdk/src/common/stacks/migration.stack.ts +++ b/packages/arc-auth/cdk/src/common/stacks/migration.stack.ts @@ -1,11 +1,12 @@ import * as random from '@cdktf/provider-random'; +import {ILambda, Lambda} from 'arc-cdk'; import {TerraformStack} from 'cdktf'; import {Construct} from 'constructs'; -import {ILambda, Lambda} from 'arc-cdk'; +import {getEnv, getSecurityGroup, getSubnetIds} from '../../env'; import {AwsProvider} from '../constructs/awsProvider'; export class MigrationStack extends TerraformStack { - constructor(scope: Construct, id: string, config: Omit) { + constructor(scope: Construct, id: string, config: Omit) { super(scope, id); new AwsProvider(this, 'aws'); // NOSONAR @@ -15,11 +16,25 @@ export class MigrationStack extends TerraformStack { const pet = new random.pet.Pet(this, 'random-name', { length: 2, }); + const env = getEnv(this); new Lambda(this, 'lambda', { // NOSONAR ...config, name: pet.id, + vpcConfig: { + securityGroupIds: getSecurityGroup(this), + subnetIds: getSubnetIds(this), + }, + envVars: { + DB_HOST: env.DB_HOST || '', + DB_PORT: env.DB_PORT || '', + DB_USER: env.DB_USER || '', + DB_PASSWORD: env.DB_PASSWORD || '', + DB_DATABASE: env.DB_DATABASE || '', + }, + namespace: env.NAMESPACE || '', + environment: env.ENV || '', }); } } diff --git a/packages/arc-auth/cdk/src/common/stacks/redis.stack.ts b/packages/arc-auth/cdk/src/common/stacks/redis.stack.ts index 949f8b2..c90176e 100644 --- a/packages/arc-auth/cdk/src/common/stacks/redis.stack.ts +++ b/packages/arc-auth/cdk/src/common/stacks/redis.stack.ts @@ -2,6 +2,7 @@ import * as aws from '@cdktf/provider-aws'; import {Fn, TerraformIterator, TerraformStack} from 'cdktf'; import {Construct} from 'constructs'; import {Redis} from '../../.gen/modules/redis'; +import {getEnv} from '../../env'; import {AwsProvider} from '../constructs/awsProvider'; import {getResourceName} from '../utils/helper'; @@ -11,10 +12,16 @@ type Config = { }; export class RedisStack extends TerraformStack { - constructor(scope: Construct, id: string, config: Config) { + constructor(scope: Construct, id: string) { super(scope, id); new AwsProvider(this, 'aws'); // NOSONAR + const env = getEnv(this); + const config: Config = { + // NOSONAR + namespace: env.NAMESPACE || '', + environment: env.ENV || '', + } const name = getResourceName({ namespace: config.namespace, @@ -57,8 +64,8 @@ export class RedisStack extends TerraformStack { { name: 'tag:Name', values: [ - `${config.namespace}-${config.environment}-privatesubnet-private-${process.env.AWS_REGION}a`, - `${config.namespace}-${config.environment}-privatesubnet-private-${process.env.AWS_REGION}b`, + `${config.namespace}-${config.environment}-privatesubnet-private-${env.AWS_REGION}a`, + `${config.namespace}-${config.environment}-privatesubnet-private-${env.AWS_REGION}b`, ], }, { diff --git a/packages/arc-auth/cdk/src/env.ts b/packages/arc-auth/cdk/src/env.ts new file mode 100644 index 0000000..ffaf142 --- /dev/null +++ b/packages/arc-auth/cdk/src/env.ts @@ -0,0 +1,81 @@ +import {DataAwsSecurityGroup} from '@cdktf/provider-aws/lib/data-aws-security-group'; +import {DataAwsSsmParameter} from '@cdktf/provider-aws/lib/data-aws-ssm-parameter'; +import {DataAwsSubnets} from '@cdktf/provider-aws/lib/data-aws-subnets'; +import {TerraformStack} from 'cdktf'; +import {readFileSync} from 'fs'; + +export const env = { + AWS_REGION: "", + DB_HOST: "", + DB_PORT: 5432, + DB_USER: "", + DB_PASSWORD: "", + DB_DATABASE: "", + DB_SCHEMA: "", + JWT_SECRET: "", + ACM_CERTIFICATE_ARN: "", + HOSTED_ZONE_ID: "", + DOMAIN_NAME: "", + NAMESPACE: "", + ENV: "", + S3_BUCKET: "" +}; + +interface EnvVar { + [key: string]: string; +} + +export const getSubnetIds = (scope: TerraformStack) => { + const subnets = new DataAwsSubnets(scope, "private_subnets", { + filter: [ + { + name: "tag:Name", + values: ['demoTagName'], //Replace demoTagName by Name Tag of subnet id + }, + ], + }); + return subnets.ids; +} + +export const getSecurityGroup = (scope: TerraformStack) => { + const sgroup = new DataAwsSecurityGroup(scope, "security_group", { + filter: [ + { + name: "tag:Name", + values: ['demoTagName'], //Replace demoTagName by Name Tag of security group + }, + ], + }); + return [sgroup.id]; +}; + + +export const getEnv = (scope: TerraformStack) => { + let envVar: EnvVar = {}; + checkEnv(); + + for (const key in process.env) { + // Check if the property is directly defined on the object (not inherited) + if (process.env.hasOwnProperty(key)) { + //read value from ssm + const ssm = new DataAwsSsmParameter(scope, "db_admin_username_ssm_param", { + name: process.env[key] ?? '', + withDecryption: true + }); + // Copy the value from process.env to envVar + envVar[key] = ssm.value; + } + } + + return envVar; +} + + +export const checkEnv = () => { + let envToCheck = readFileSync('../.env.schema', "utf8").split(/[\n =]/).filter(Boolean); + envToCheck.forEach(key => { + if (!env.hasOwnProperty(key)) { + throw new Error(`env is missing- ${key}`); + } + }) +} diff --git a/packages/arc-auth/cdk/src/main.ts b/packages/arc-auth/cdk/src/main.ts index 1f4bf55..b85df85 100644 --- a/packages/arc-auth/cdk/src/main.ts +++ b/packages/arc-auth/cdk/src/main.ts @@ -13,47 +13,16 @@ dotenvExt.load({ const app = new App(); -const getSubnetIds = () => { - try { - const subnetIds = process.env?.SUBNET_IDS || ''; - return JSON.parse(subnetIds); - } catch (e) { - console.error(e); // NOSONAR - } - return []; -}; -const getSecurityGroup = () => { - try { - const securityGroup = process.env?.SECURITY_GROUPS || ''; - return JSON.parse(securityGroup); - } catch (e) { - console.error(e); // NOSONAR - } - return []; -}; new MigrationStack(app, 'migration', { // NOSONAR codePath: resolve(__dirname, '../../migration'), handler: 'lambda.handler', runtime: 'nodejs18.x', - vpcConfig: { - securityGroupIds: getSecurityGroup(), - subnetIds: getSubnetIds(), - }, memorySize: 256, invocationData: '{}', timeout: 60, - envVars: { - DB_HOST: process.env.DB_HOST || '', - DB_PORT: process.env.DB_PORT || '', - DB_USER: process.env.DB_USER || '', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || '', - }, - namespace: process.env.NAMESPACE || '', - environment: process.env.ENV || '', }); new LambdaStack(app, 'lambda', { @@ -63,38 +32,13 @@ new LambdaStack(app, 'lambda', { handler: 'lambda.handler', runtime: 'nodejs18.x', layerPath: resolve(__dirname, '../../layers'), - vpcConfig: { - securityGroupIds: getSecurityGroup(), - subnetIds: getSubnetIds(), - }, + memorySize: 256, timeout: 30, - envVars: { - DB_HOST: process.env.DB_HOST || '', - DB_PORT: process.env.DB_PORT || '', - DB_USER: process.env.DB_USER || '', - DB_PASSWORD: process.env.DB_PASSWORD || '', - DB_DATABASE: process.env.DB_DATABASE || '', - DB_SCHEMA: process.env.DB_SCHEMA || '', - JWT_SECRET: process.env.JWT_SECRET || '', - JWT_ISSUER: 'sourcefuse', - PORT: '3005', - LOG_LEVEL: 'info', - DB_CONNECTOR: 'postgresql', - }, - customDomainName: { - domainName: process.env.DOMAIN_NAME || '', - hostedZoneId: process.env.HOSTED_ZONE_ID || '', - }, - namespace: process.env.NAMESPACE || '', - environment: process.env.ENV || '', + useImage: true, }); -new RedisStack(app, 'redis', { - // NOSONAR - namespace: process.env.NAMESPACE || '', - environment: process.env.ENV || '', -}); +new RedisStack(app, 'redis'); app.synth();