@aws-cdk/core#Stack TypeScript Examples

The following examples show how to use @aws-cdk/core#Stack. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: seeder.ts    From aws-cdk-dynamodb-seeder with Apache License 2.0 6 votes vote down vote up
it('seeds a table from inline arrays', () => {
  const stack = new Stack();
  new Seeder(stack, 'Seeder', {
    table: new Table(stack, 'TestTable', {
      tableName: 'TestTable',
      partitionKey: { name: 'Id', type: AttributeType.STRING },
    }),
    setup: [
      {
        id: 'herewego...',
        this: 'is a test',
        testing: {
          testing: 123,
        },
      },
      {
        id: 'greatest show',
        this: 'is a the greatest show',
      },
    ],
    teardown: [
      {
        id: 'greatest show',
      },
    ],
    refreshOnUpdate: true,
  });

  expect(stack).toHaveResource('AWS::Lambda::Function');
  expect(stack).toHaveResource('AWS::S3::Bucket');
});
Example #2
Source File: stack.ts    From aws-boilerplate with MIT License 6 votes vote down vote up
protected createTaskRole(props: SshBastionStackProps): Role {
        const stack = Stack.of(this);
        const chamberServiceName = this.getChamberServiceName(props.envSettings);

        const taskRole = new Role(this, "MigrationsTaskRole", {
            assumedBy: new ServicePrincipal('ecs-tasks'),
        });

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["sqs:*", "cloudformation:DescribeStacks", "events:*"],
            resources: ["*"],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: [
                "kms:Get*",
                "kms:Describe*",
                "kms:List*",
                "kms:Decrypt",
            ],
            resources: [
                Fn.importValue(MainKmsKey.getMainKmsOutputExportName(props.envSettings)),
            ],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["ssm:DescribeParameters"],
            resources: ["*"],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["ssm:GetParameters*"],
            resources: [
                `arn:aws:ssm:${stack.region}:${stack.account}:parameter/${chamberServiceName}/*`,
            ],
        }));

        return taskRole;
    }
Example #3
Source File: integ.default.ts    From aws-cdk-for-k3scluster with MIT License 6 votes vote down vote up
constructor() {
    const app = new App();
    const env = {
      region: process.env.CDK_DEFAULT_REGION,
      account: process.env.CDK_DEFAULT_ACCOUNT,
    };

    const stack = new Stack(app, 'testing-stack', { env });

    const vpc = k3s.VpcProvider.getOrCreate(stack);

    const cluster = new k3s.Cluster(stack, 'Cluster', {
      vpc,
      spotWorkerNodes: true,
      workerMinCapacity: 1,
      workerInstanceType: new ec2.InstanceType('m6g.medium'),
      controlPlaneInstanceType: new ec2.InstanceType('m6g.medium'),
      bucketRemovalPolicy: RemovalPolicy.DESTROY,
    });

    new CfnOutput(stack, 'EndpointURI', { value: cluster.endpointUri });
    new CfnOutput(stack, 'Region', { value: Stack.of(stack).region });
    this.stack = [stack];
  }
Example #4
Source File: application-stack.ts    From aws-cross-account-cicd-pipeline with MIT No Attribution 6 votes vote down vote up
export class ApplicationStack extends Stack {
  public readonly lambdaCode: lambda.CfnParametersCode;

  constructor(app: App, id: string, props: ApplicationStackProps) {
    super(app, id, props);

    this.lambdaCode = lambda.Code.fromCfnParameters();

    const func = new lambda.Function(this, 'Lambda', {
      functionName: 'HelloLambda',
      code: this.lambdaCode,
      handler: 'index.handler',
      runtime: lambda.Runtime.NODEJS_12_X,
      environment: {
        STAGE_NAME: props.stageName
      }
    });

    new apigateway.LambdaRestApi(this, 'HelloLambdaRestApi', {
      handler: func,
      endpointExportName: 'HelloLambdaRestApiEmdpoint',
      deployOptions: {
        stageName: props.stageName
      }
    });

    const version = func.addVersion(new Date().toISOString());
    const alias = new lambda.Alias(this, 'LambdaAlias', {
      aliasName: props.stageName,
      version,
    });

    new codedeploy.LambdaDeploymentGroup(this, 'DeploymentGroup', {
      alias,
      deploymentConfig: codedeploy.LambdaDeploymentConfig.ALL_AT_ONCE,
    });

  }
}
Example #5
Source File: stack.ts    From keycloak-on-aws with Apache License 2.0 6 votes vote down vote up
export class SolutionStack extends Stack {
  private _paramGroup: { [grpname: string]: CfnParameter[]} = {}

  protected setDescription(description: string) { this.templateOptions.description = description; }
  protected makeParam(id: string, props?: CfnParameterProps): CfnParameter { return new CfnParameter(this, id, props); }
  protected addGroupParam(props: { [key: string]: CfnParameter[]}): void {
    for (const key of Object.keys(props)) {
      const params = props[key];
      this._paramGroup[key] = params.concat(this._paramGroup[key] ?? []);
    }
    this._setParamGroups();
  }
  private _setParamGroups(): void {
    if (!this.templateOptions.metadata) { this.templateOptions.metadata = {}; }
    const mkgrp = (label: string, params: CfnParameter[]) => {
      return {
        Label: { default: label },
        Parameters: params.map(p => {
          return p ? p.logicalId : '';
        }).filter(id => id),
      };
    };
    this.templateOptions.metadata['AWS::CloudFormation::Interface'] = {
      ParameterGroups: Object.keys(this._paramGroup).map(key => mkgrp(key, this._paramGroup[key]) ),
    };
  }
}
Example #6
Source File: seeder.ts    From aws-cdk-dynamodb-seeder with Apache License 2.0 6 votes vote down vote up
it('seeds a table from required json files', () => {
  const stack = new Stack();
  new Seeder(stack, 'Seeder', {
    table: new Table(stack, 'TestTable', {
      tableName: 'TestTable',
      partitionKey: { name: 'Id', type: AttributeType.STRING },
    }),
    setup: require('./put.json'),
    teardown: require('./delete.json'),
    refreshOnUpdate: true,
  });

  expect(stack).toHaveResource('AWS::Lambda::Function');
  expect(stack).toHaveResource('AWS::S3::Bucket');
});
Example #7
Source File: datadog-dashboard.test.ts    From cdk-datadog-resources with Apache License 2.0 6 votes vote down vote up
test('Snapshot test', () => {
  const stack = new Stack();

  const dashboardDefJson = fs.readFileSync(`${__dirname}/dashboard-def.json`).toString();

  new DatadogDashboard(stack, 'TestMonitor', {
    datadogCredentials: {
      apiKey: 'DATADOG_API_KEY',
      applicationKey: 'DATADOG_APP_KEY',
    },
    dashboardDefinition: dashboardDefJson,
  });

  expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot();
});
Example #8
Source File: certificates-stack.ts    From hasura-cdk with MIT License 6 votes vote down vote up
export class CertificatesStack extends Stack {

    readonly certificates: Certificates;

    constructor(scope: Construct, id: string, props: CertificatesStackProps) {
        super(scope, id, props);

        const hostedZone = PublicHostedZone.fromHostedZoneAttributes(this, 'HasuraHostedZone', {
            hostedZoneId: props.hostedZoneId,
            zoneName: props.hostedZoneName,
        });

        const hasura = new DnsValidatedCertificate(this, 'HasuraCertificate', {
            hostedZone,
            domainName: props.hasuraHostname,
        });

        const actions = new DnsValidatedCertificate(this, 'ActionsCertificate', {
            hostedZone,
            domainName: props.actionsHostname,
        });


        this.certificates = {
            hasura,
            actions,
        };

    }
}
Example #9
Source File: TestStack.ts    From aws-cdk-webpack-lambda-function with MIT License 6 votes vote down vote up
export class TestStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // test1
    new WebpackFunction(this, "WebpackFunction", {
      entry: "test/lambda/testFunction.ts",
      config: "test/lambda/webpack.config.js",
    });

    // test2
    new WebpackSingletonFunction(this, "WebpackSingletonFunction", {
      uuid: "be82c13f-a959-4837-91d7-1a3aabb2626a",
      entry: "test/lambda/testFunction.ts",
      config: "test/lambda/webpack.config.js",
    });
  }
}
Example #10
Source File: infra-stack.test.ts    From aws-power-tuner-ui with Apache License 2.0 6 votes vote down vote up
test('should create the an API Gateway with associated properties', () => {
  const stack = new Stack();
  const infraStack = new PowerTunerStack(stack, 'infraStack');
  expect(infraStack).toHaveResourceLike('AWS::ApiGateway::RestApi', {
    Name: 'power-tuner-gateway',
    EndpointConfiguration: {
      Types: ['REGIONAL']
    }
  });
  expect(infraStack).toHaveResourceLike('AWS::ApiGateway::Deployment', {});
  expect(infraStack).toHaveResourceLike('AWS::ApiGateway::Stage', {
    StageName: 'development'
  });
});
Example #11
Source File: stack.ts    From aws-boilerplate with MIT License 6 votes vote down vote up
protected createTaskRole(props: MigrationsStackProps): Role {
        const stack = Stack.of(this);
        const chamberServiceName = this.getChamberServiceName(props.envSettings);

        const taskRole = new Role(this, "ApiTaskRole", {
            assumedBy: new ServicePrincipal('ecs-tasks'),
        });

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["sqs:*", "cloudformation:DescribeStacks", "events:*"],
            resources: ["*"],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: [
                "kms:Get*",
                "kms:Describe*",
                "kms:List*",
                "kms:Decrypt",
            ],
            resources: [
                Fn.importValue(MainKmsKey.getMainKmsOutputExportName(props.envSettings)),
            ],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["ssm:DescribeParameters"],
            resources: ["*"],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["ssm:GetParameters*"],
            resources: [
                `arn:aws:ssm:${stack.region}:${stack.account}:parameter/${chamberServiceName}/*`,
            ],
        }));

        return taskRole;
    }
Example #12
Source File: datadog-integration.test.ts    From cdk-datadog-resources with Apache License 2.0 6 votes vote down vote up
test('Snapshot test', () => {
  const stack = new Stack();

  new DatadogIntegrationAWS(stack, 'TestIntegration', {
    datadogCredentials: {
      apiKey: 'DATADOG_API_KEY',
      applicationKey: 'DATADOG_APP_KEY',
    },
    accountId: '123456',
    roleName: 'DatadogAWSAcctRoleName',
  });

  expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot();
});
Example #13
Source File: fargateServiceResources.ts    From aws-boilerplate with MIT License 6 votes vote down vote up
private retrieveMainVpc() {
        const stack = Stack.of(this);

        return Vpc.fromVpcAttributes(this, "EC2MainVpc", {
            vpcId: Fn.importValue(MainVpc.getVpcArnOutputExportName(this.envSettings)),
            publicSubnetIds: [
                Fn.importValue(MainVpc.getPublicSubnetOneIdOutputExportName(this.envSettings)),
                Fn.importValue(MainVpc.getPublicSubnetTwoIdOutputExportName(this.envSettings)),
            ],
            availabilityZones: [
                stack.availabilityZones[0],
                stack.availabilityZones[1],
            ],
        });
    }
Example #14
Source File: datadog-user.test.ts    From cdk-datadog-resources with Apache License 2.0 6 votes vote down vote up
test('Snapshot test', () => {
  const stack = new Stack();

  new DatadogIAMUser(stack, 'TestUser', {
  	datadogCredentials: {
      apiKey: 'DATADOG_API_KEY',
      applicationKey: 'DATADOG_APP_KEY',
    },
    email: '[email protected]',
    name: 'name_example',
    handle: 'title_example',
    disabled: false,
  });
  expect(SynthUtils.toCloudFormation(stack)).toMatchSnapshot();
});
Example #15
Source File: stack.ts    From aws-boilerplate with MIT License 6 votes vote down vote up
protected createTaskRole(props: MigrationsStackProps): Role {
        const stack = Stack.of(this);
        const chamberServiceName = this.getChamberServiceName(props.envSettings);

        const taskRole = new Role(this, "MigrationsTaskRole", {
            assumedBy: new ServicePrincipal('ecs-tasks'),
        });

        taskRole.addToPolicy(new PolicyStatement({
            actions: [
                "kms:Get*",
                "kms:Describe*",
                "kms:List*",
                "kms:Decrypt",
            ],
            resources: [
                Fn.importValue(MainKmsKey.getMainKmsOutputExportName(props.envSettings)),
            ],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["ssm:DescribeParameters"],
            resources: ["*"],
        }));

        taskRole.addToPolicy(new PolicyStatement({
            actions: ["ssm:GetParameters*"],
            resources: [
                `arn:aws:ssm:${stack.region}:${stack.account}:parameter/${chamberServiceName}/*`,
            ],
        }));

        return taskRole;
    }
Example #16
Source File: lambda-stack.test.ts    From aws-power-tuner-ui with Apache License 2.0 5 votes vote down vote up
test('should create the sample lambda function with correct handler', () => {
  const stack = new Stack();
  const lambdaStack = new PowerTunerLambdaStack(stack, 'lambdaStack');
  expect(lambdaStack).toHaveResourceLike('AWS::Lambda::Function', {
    Handler: 'hello.handler',
    Runtime: 'nodejs10.x'
  });
});
Example #17
Source File: ciBackend.ts    From aws-boilerplate with MIT License 5 votes vote down vote up
private createMigrationsDeployProject(props: BackendCiConfigProps) {
        const stack = Stack.of(this);
        const project = new Project(this, "MigrationsDeployProject", {
            projectName: `${props.envSettings.projectEnvName}-deploy-migrations`,
            buildSpec: BuildSpec.fromObject({
                version: '0.2',
                phases: {
                    pre_build: {commands: ['make -C services/backend install-deploy']},
                    build: {commands: ['make -C services/backend deploy-migrations']},
                },
                cache: {
                    paths: [...this.defaultCachePaths],
                },
            }),
            environmentVariables: {...this.defaultEnvVariables},
            cache: Cache.local(LocalCacheMode.CUSTOM),
        });

        project.addToRolePolicy(new PolicyStatement({
            effect: Effect.ALLOW,
            actions: [
                'cloudformation:*',
            ],
            resources: [
                `arn:aws:cloudformation:${stack.region}:${stack.account}:stack/CDKToolkit/*`,
                `arn:aws:cloudformation:${stack.region}:${stack.account}:stack/${props.envSettings.projectEnvName}-MigrationsStack/*`,
            ],
        }));

        project.addToRolePolicy(new PolicyStatement({
            effect: Effect.ALLOW,
            actions: [
                'iam:*',
                'ec2:*',
                'ecs:*',
                'states:*',
                'lambda:*',
                'logs:*',
                'route53:*',
            ],
            resources: ['*'],
        }));

        return project;
    }
Example #18
Source File: actions-stack.ts    From hasura-cdk with MIT License 5 votes vote down vote up
export class ActionsStack extends Stack {


    constructor(scope: Construct, id: string, props: ActionsStackProps) {
        super(scope, id, props);

        const hostedZone = PublicHostedZone.fromHostedZoneAttributes(this, 'HasuraHostedZone', {
            hostedZoneId: props.hostedZoneId,
            zoneName: props.hostedZoneName,
        });

        const api = new RestApi(this, 'ActionsApi', {
            domainName: {
                domainName: props.actionsHostname,
                certificate: props.certificates.actions,
            },
            restApiName: 'Actions',
            description: 'Endpoint For Hasura Actions',
            deployOptions: {
                loggingLevel: MethodLoggingLevel.INFO,
                dataTraceEnabled: true,
            },
        });

        // API DNS record
        new ARecord(this, 'ActionsApiAliasRecord', {
            zone: hostedZone,
            recordName: props.actionsHostname,
            target: AddressRecordTarget.fromAlias(new route53_targets.ApiGateway(api)),
        });

        // Create a lambda layer to contain node_modules
        const handlerDependenciesLayer = new RetainedLambdaLayerVersion(this, 'ActionHandlerDependencies', {
            contentLocation: 'actions/dependencies-layer',
            description: 'Dependencies layer',
            compatibleRuntimes: [Runtime.NODEJS_12_X],
        });

        const actionHandler = new Function(this, 'ActionHandler', {
            functionName: `${props.appName}-ActionHandler`,
            handler: 'handler.handler',
            memorySize: 1024,
            runtime: Runtime.NODEJS_12_X,
            code: Code.fromAsset(path.join(__dirname, '../../actions/dist/')),
            timeout: Duration.seconds(4),
            layers: [handlerDependenciesLayer],
        });

        const handlerResource = api.root.addResource('handler');
        const actionHandlerIntegration = new LambdaIntegration(actionHandler);

        handlerResource.addMethod('POST', actionHandlerIntegration);
        handlerResource.addMethod('GET', actionHandlerIntegration);

    }


}
Example #19
Source File: ciComponents.ts    From aws-boilerplate with MIT License 5 votes vote down vote up
private createDeployProject(props: ComponentsCiConfigProps) {
        const stack = Stack.of(this);
        const project = new Project(this, "ComponentsDeployProject", {
            projectName: `${props.envSettings.projectEnvName}-deploy-components`,
            buildSpec: BuildSpec.fromObject({
                version: '0.2',
                phases: {
                    pre_build: {commands: ['make -C infra/cdk install']},
                    build: {commands: ['make -C infra/cdk deploy-components']}
                },
                cache: {
                    paths: [...this.defaultCachePaths],
                },
            }),
            environmentVariables: {...this.defaultEnvVariables},
            cache: Cache.local(LocalCacheMode.CUSTOM),
        });

        project.addToRolePolicy(new PolicyStatement({
            effect: Effect.ALLOW,
            actions: [
                'cloudformation:*',
            ],
            resources: [
                `arn:aws:cloudformation:${stack.region}:${stack.account}:stack/CDKToolkit/*`,
                `arn:aws:cloudformation:${stack.region}:${stack.account}:stack/${props.envSettings.projectEnvName}-ComponentsStack/*`,
            ],
        }));

        project.addToRolePolicy(new PolicyStatement({
            effect: Effect.ALLOW,
            actions: [
                'iam:*',
                'logs:*',
                's3:*',
                'sqs:*',
                'events:*',
            ],
            resources: ['*'],
        }));

        return project;
    }
Example #20
Source File: cdk-app.ts    From cdk-datadog-resources with Apache License 2.0 5 votes vote down vote up
stack = new Stack(app, 'CdkDatadogResourcesTestStack')
Example #21
Source File: stack.ts    From aws-boilerplate with MIT License 5 votes vote down vote up
export class EnvDbStack extends Stack {
    mainDatabase: MainDatabase;

    constructor(scope: App, id: string, props: EnvDbStackProps) {
        super(scope, id, props);

        const {envSettings} = props;

        const mainVpc = this.retrieveMainVpc(props);


        this.mainDatabase = new MainDatabase(this, "MainDatabase", {
            envSettings,
            vpc: mainVpc,
            fargateContainerSecurityGroup: this.retrieveFargateContainerSecurityGroup(props),
            lambdaSecurityGroup: this.retrieveLambdaSecurityGroup(props),
        });
    }

    private retrieveMainVpc(props: EnvDbStackProps) {
        const stack = Stack.of(this);

        return Vpc.fromVpcAttributes(this, "EC2MainVpc", {
            vpcId: Fn.importValue(MainVpc.getVpcArnOutputExportName(props.envSettings)),
            publicSubnetIds: [
                Fn.importValue(MainVpc.getPublicSubnetOneIdOutputExportName(props.envSettings)),
                Fn.importValue(MainVpc.getPublicSubnetTwoIdOutputExportName(props.envSettings)),
            ],
            availabilityZones: [
                stack.availabilityZones[0],
                stack.availabilityZones[1],
            ],
        });
    }

    private retrieveFargateContainerSecurityGroup(props: EnvDbStackProps) {
        return SecurityGroup.fromSecurityGroupId(this, "FargateContainerSecurityGroup",
            Fn.importValue(MainECSCluster.getFargateContainerSecurityGroupIdOutputExportName(props.envSettings)));
    }

    private retrieveLambdaSecurityGroup(props: EnvDbStackProps) {
        return SecurityGroup.fromSecurityGroupId(this, "LambdaSecurityGroup",
            Fn.importValue(MainLambdaConfig.getLambdaSecurityGroupIdOutputExportName(props.envSettings)));
    }
}
Example #22
Source File: cluster.test.ts    From aws-cdk-for-k3scluster with MIT License 5 votes vote down vote up
test('add s3 removalPolicy', () => {
  const app = new App();
  const stack = new Stack(app, 'testing-stack');
  new k3s.Cluster(stack, 'Cluster-s3-removalPolicy', {
    bucketRemovalPolicy: RemovalPolicy.DESTROY,
  });
  expect(stack).toHaveResource('AWS::S3::Bucket');
});
Example #23
Source File: amazon-efs-integrations-stack.ts    From amazon-efs-integrations with MIT No Attribution 5 votes vote down vote up
export class AmazonEfsIntegrationsStack extends Stack {
  constructor(scope: Construct, id: string, props: AmazonEfsIntegrationsStackProps) {
    if (props.createEfsAccessPoints && !props.createEfsFilesystem) {
      throw new Error('`createEfsFileSystem` must be set to true if `createEfsAccessPoints` is true');
    }

    super(scope, id, props);

    const vpc = new Vpc(this, 'EfsIntegrationDemo', {maxAzs: 2});
    const efsSecurityGroup = new SecurityGroup(this, 'EfsSecurityGroup', {securityGroupName: 'efs-demo-fs', vpc});

    let fileSystem;
    let efsAccessPoints;

    if (props.createEfsFilesystem) {
      /* tslint:disable-next-line:no-unused-expression */
      fileSystem = new FileSystem(this, 'EfsIntegrationDemoFileSystem', {
        encrypted: true,
        fileSystemName: 'efs-demo-fs',
        securityGroup: efsSecurityGroup,
        vpc,
      });

      if (props.createEfsAccessPoints) {
        efsAccessPoints = new EfsAccessPoints(
          fileSystem,
          props.createEcsOnEc2Service,
          props.createEcsOnFargateService,
        );
      }
    }

    if (props.createEcsOnEc2Service || props.createEcsOnFargateService) {
      const cluster = new Cluster(this, 'EcsCluster', {vpc});
      let ecsOnEc2Service;
      let ecsOnFargateService;

      if (props.createEcsOnEc2Service) {
        cluster.addCapacity('DefaultAutoScalingGroup', {
          instanceType: new InstanceType('t2.large'),
          maxCapacity: 2,
          minCapacity: 2,
        });

        ecsOnEc2Service = EcsEfsIntegrationService.create(
          ServiceType.EC2,
          cluster,
          fileSystem,
          efsAccessPoints
        ) as ApplicationLoadBalancedEc2Service;
        efsSecurityGroup.connections.allowFrom(ecsOnEc2Service.service, Port.tcp(2049));
      }

      if (props.createEcsOnFargateService) {
        ecsOnFargateService = EcsEfsIntegrationService.create(
          ServiceType.FARGATE,
          cluster,
          fileSystem,
          efsAccessPoints
        ) as ApplicationLoadBalancedFargateService;
        efsSecurityGroup.connections.allowFrom(ecsOnFargateService.service, Port.tcp(2049));
      }

      if (props.createEfsAccessPoints && fileSystem && efsAccessPoints) {
        // tslint:disable-next-line: no-unused-expression
        new EfsFileSystemPolicy(
          fileSystem,
          efsAccessPoints,
          ecsOnEc2Service,
          ecsOnFargateService,
        );
      }
    }
  }
}
Example #24
Source File: vpc-stack.ts    From awsmug-serverless-graphql-api with MIT License 5 votes vote down vote up
export class VpcStack extends Stack {
  readonly vpc: Vpc;
  readonly ingressSecurityGroup: SecurityGroup;
  readonly egressSecurityGroup: SecurityGroup;

  constructor(scope: Construct, id: string) {
    super(scope, id);

    this.vpc = new Vpc(this, "CustomVPC", {
      cidr: "10.0.0.0/16",
      maxAzs: 2,
      subnetConfiguration: [
        {
          cidrMask: 26,
          name: "private-data",
          subnetType: SubnetType.ISOLATED,
        },
      ],
      natGateways: 0,
    });

    this.ingressSecurityGroup = new SecurityGroup(
      this,
      "ingress-security-group",
      {
        vpc: this.vpc,
        allowAllOutbound: false,
        securityGroupName: "IngressSecurityGroup",
      }
    );
    this.ingressSecurityGroup.addIngressRule(
      Peer.ipv4("10.0.0.0/16"),
      Port.tcp(5432)
    );

    this.ingressSecurityGroup.addEgressRule(
      Peer.ipv4("10.0.0.0/16"),
      Port.tcp(5432)
    );

    this.egressSecurityGroup = new SecurityGroup(
      this,
      "egress-security-group",
      {
        vpc: this.vpc,
        allowAllOutbound: false,
        securityGroupName: "EgressSecurityGroup",
      }
    );
    this.egressSecurityGroup.addEgressRule(Peer.anyIpv4(), Port.tcp(80));
  }
}
Example #25
Source File: cicd-stack.ts    From MDDL with MIT License 5 votes vote down vote up
/**
   * Create a CDK app from a pipeline config by dynamically adding stacks to it
   * @param props The pipeline config which determines stacks that are in the app
   * @param app The CDK app to use (optional - will create a new one if not provided)
   */
  public static buildApp(props: Props, app = new App()) {
    // read out configuration
    const { developStageConfiguration, prodStageConfiguration } = props
    const cityStacksProps = CiCdStack.getCityStacksProps(props)
    const createdStacks: { name: string; stack: Stack }[] = []
    const integratedConfigs = [developStageConfiguration]
    if (prodStageConfiguration) {
      integratedConfigs.push(prodStageConfiguration)
    }

    for (const integratedConfig of integratedConfigs) {
      const { authStackProps, dataStoreStackProps } = integratedConfig

      // add auth stack
      if (authStackProps) {
        const authStack = new AuthStack(
          app,
          authStackProps.name,
          authStackProps.props,
        )
        createdStacks.push({ name: authStackProps.name, stack: authStack })
      }

      // add data store stack
      const dataStoreStack = new DataStoreStack(
        app,
        dataStoreStackProps.name,
        dataStoreStackProps.props,
      )
      createdStacks.push({
        name: dataStoreStackProps.name,
        stack: dataStoreStack,
      })
    }

    // add all city stacks
    cityStacksProps.map((stackProps) => {
      const { name, props } = stackProps

      // find auth stack, if any
      const authStack = props.authStackName
        ? (createdStacks.find((cs) => cs.name == props.authStackName)
            ?.stack as AuthStack)
        : undefined

      // find data store stack
      const dataStoreStack = createdStacks.find(
        (cs) => cs.name == props.dataStoreStackName,
      )?.stack as DataStoreStack

      // add stack
      const stack = new CityStack(app, name, {
        ...props,
        authStack,
        dataStoreStack,
      })
      createdStacks.push({ name, stack })
    })

    return { app, createdStacks }
  }
Example #26
Source File: api-stack.ts    From awsmug-serverless-graphql-api with MIT License 5 votes vote down vote up
export class GraphqlApiStack extends Stack {
  readonly handler: any;
  readonly rdsPassword: ISecret;
  readonly api: RestApi;
  readonly apiPathOutput: CfnOutput;
  readonly graphql: ResourceBase;

  constructor(scope: Construct, id: string, props: LambdaStackProps) {
    super(scope, id, props);

    this.rdsPassword = Secret.fromSecretNameV2(
      this,
      "rdsPassword",
      "rdsPassword"
    );

    this.handler = new Function(this, "graphql", {
      runtime: Runtime.NODEJS_14_X,
      code: Code.fromAsset("app"),
      handler: "build/src/graphql.handler",
      vpc: props.vpc,
      vpcSubnets: {
        subnetType: SubnetType.ISOLATED,
      },
      securityGroup: SecurityGroup.fromSecurityGroupId(
        this,
        "inboundDbAccessSecurityGroup" + "rdsLambda",
        props.inboundDbAccessSecurityGroup
      ),

      environment: {
        TYPEORM_URL: `postgres://${
          props.rdsDbUser
        }:${this.rdsPassword.secretValue.toString()}@${props.rdsEndpoint}:${
          props.rdsPort
        }/${props.rdsDbName}`,
        TYPEORM_SYNCHRONIZE: "true",
        TYPEORM_LOGGING: "true",
        TYPEORM_ENTITIES: "./build/src/entity/*.entity.js",
      },
    });

    this.api = new LambdaRestApi(this, "graphql-api", {
      handler: this.handler,
      proxy: false,
    });

    this.graphql = this.api.root.addResource("graphql");
    this.graphql.addMethod("ANY");

    this.apiPathOutput = new CfnOutput(this, "apiPath", {
      value: this.api.root.path,
      description: "Path of the API",
    });
  }
}
Example #27
Source File: auth-stack.ts    From MDDL with MIT License 4 votes vote down vote up
export class AuthStack extends Stack {
  /**
   * The ID of the User Pool
   */
  public userPoolId: string

  /**
   * The URL of the hosted authentication pages
   */
  public authUrl: string

  /**
   * The Cognito Custom Domain takes a few minutes to apply.
   * To work around this, deploy first with this flag set to false.
   */
  private deployUiCustomization = true
  constructor(scope: Construct, id: string, props: Props) {
    super(scope, id, props)
    const { userPoolName, emailSender, customDomain } = props

    // create the user pool
    const { userPool, uiCustomization } = this.addUserPool(
      userPoolName,
      emailSender,
    )
    this.userPoolId = userPool.userPoolId

    // attach the custom domain
    if (customDomain) {
      this.addCustomDomain(userPool, customDomain, uiCustomization)
      this.authUrl = `https://${customDomain.domain}`
    } else {
      this.authUrl = userPool.userPoolProviderUrl
    }

    this.addTriggers(userPool)

    // SNS Topics for SES Bounce Event
    new Topic(this, 'SesBounceTopic', {
      displayName: 'Bounce notifications topic',
    })

    // SNS Topics for SES Complaint Event
    new Topic(this, 'SesComplaintsTopic', {
      displayName: 'Complaints notifications topic',
    })

    // SNS Topics for SES Delivery Event
    new Topic(this, 'SesDeliveryTopic', {
      displayName: 'Delivery Notifications topic',
    })
  }

  /**
   * Configure and add the user pool resource
   * @param userPoolName The name of the user pool
   * @param emailSender Details on how to send emails (optional)
   */
  private addUserPool(userPoolName: string, emailSender?: EmailSender) {
    const userPool = new UserPool(this, 'UserPool', {
      accountRecovery: AccountRecovery.EMAIL_ONLY,
      signInAliases: {
        email: true,
      },
      emailSettings: emailSender
        ? {
            from: `${emailSender.name} <${emailSender.address}>`,
          }
        : undefined,
      userVerification: {
        emailStyle: VerificationEmailStyle.LINK,
        emailSubject: 'Please verify your email address',
      },
      selfSignUpEnabled: true,
      passwordPolicy: {
        minLength: 6,
        requireDigits: true,
        requireLowercase: false,
        requireUppercase: true,
        requireSymbols: true,
      },
      standardAttributes: {
        email: {
          mutable: true,
          required: true,
        },
        givenName: {
          mutable: true,
          required: true,
        },
        familyName: {
          mutable: true,
          required: true,
        },
        locale: {
          mutable: true,
          required: false,
        },
        timezone: {
          mutable: true,
          required: false,
        },
      },
      customAttributes: {
        features: new StringAttribute({
          maxLen: 255,
          mutable: true,
          minLen: 0,
        }),
      },
      signInCaseSensitive: false,
      userPoolName,
    })

    // manual override to retain the user pool
    const cfnUserPool = userPool.node.defaultChild as CfnUserPool
    cfnUserPool.applyRemovalPolicy(RemovalPolicy.RETAIN)

    // manual overrides to set the config to use a specific identity for sending emails
    if (emailSender) {
      const { address } = emailSender
      cfnUserPool.addPropertyOverride(
        'EmailConfiguration.EmailSendingAccount',
        'DEVELOPER',
      )
      cfnUserPool.addPropertyOverride(
        'EmailConfiguration.SourceArn',
        `arn:aws:ses:${this.region}:${this.account}:identity/${address}`,
      )
    }

    // CSS for hosted login
    const uiCustomization = this.deployUiCustomization
      ? new CfnUserPoolUICustomizationAttachment(
          this,
          'UserPoolUICustomizationAttachment',
          {
            clientId: 'ALL',
            userPoolId: userPool.userPoolId,
            css: getCognitoHostedLoginCss(),
          },
        )
      : undefined

    return {
      userPool,
      uiCustomization,
    }
  }

  /**
   * Set the Hosted UI custom domain for a user pool
   * @param userPool The user pool to configure
   * @param customDomain Details on the custom domain to configure
   */
  private addCustomDomain(
    userPool: UserPool,
    customDomain: CustomHostedDomain,
    uiCustomization?: CfnUserPoolUICustomizationAttachment,
  ) {
    // read out configuration
    const {
      domain,
      certificateArn,
      shouldCreateRootARecord,
      hostedZoneAttributes,
    } = customDomain
    const dependencies: IDependable[] = []

    // create reference to hosted zone
    const hostedZone = HostedZone.fromHostedZoneAttributes(
      this,
      `HostedZone`,
      hostedZoneAttributes,
    )

    // add root A record if needed
    if (shouldCreateRootARecord) {
      const rootDomain = domain.split('.', 1)[1]
      const rootDomainBucket = new Bucket(this, 'RootHostingBucket', {
        bucketName: rootDomain,
        publicReadAccess: true,
        websiteRedirect: {
          hostName: domain,
          protocol: RedirectProtocol.HTTPS,
        },
      })
      const rootAliasRecord = new ARecord(this, `RootAliasRecord`, {
        zone: hostedZone,
        recordName: rootDomain,
        target: RecordTarget.fromAlias(
          new BucketWebsiteTarget(rootDomainBucket),
        ),
      })
      rootAliasRecord.node.addDependency(rootDomainBucket)
      dependencies.push(rootAliasRecord)
    }

    // get reference to cerificate
    const certificate = Certificate.fromCertificateArn(
      this,
      `UserPoolCertificate`,
      certificateArn,
    )

    // add domain to user pool
    const userPoolDomain = userPool.addDomain('HostedDomain', {
      customDomain: {
        certificate,
        domainName: domain,
      },
    })
    userPoolDomain.node.addDependency(...dependencies)

    // create A record for custom domain
    const aRecord = new ARecord(this, `CustomDomainAliasRecord`, {
      zone: hostedZone,
      recordName: domain,
      target: RecordTarget.fromAlias(
        new MinimalCloudFrontTarget(this, userPoolDomain.cloudFrontDomainName),
      ),
    })

    if (uiCustomization) {
      uiCustomization.addDependsOn(aRecord.node.defaultChild as CfnRecordSet)
    }
  }

  private addTriggers(userPool: UserPool) {
    const parameterPath = `/${this.stackName}/clientWebApps`
    const customMessageHandler = new Function(this, 'CustomMessageHandler', {
      code: Code.fromAsset(
        pathToApiServiceLambda('emails/cognitoCustomMessageHandler'),
      ),
      environment: {
        CLIENT_WEB_APP_PARAMETER_PATH: parameterPath,
      },
      handler: 'index.handler',
      memorySize: 256,
      timeout: Duration.seconds(10),
      runtime: Runtime.NODEJS_12_X,
    })
    customMessageHandler.addToRolePolicy(
      new PolicyStatement({
        actions: ['ssm:GetParameter'],
        resources: [
          `arn:${this.partition}:ssm:${this.region}:${this.account}:parameter${parameterPath}/*`,
        ],
      }),
    )

    userPool.addTrigger(UserPoolOperation.CUSTOM_MESSAGE, customMessageHandler)
  }
}
Example #28
Source File: hasura-stack.ts    From hasura-cdk with MIT License 4 votes vote down vote up
export class HasuraStack extends Stack {
    constructor(scope: Construct, id: string, props: HasuraStackProps) {
        super(scope, id, props);

        const hostedZone = PublicHostedZone.fromHostedZoneAttributes(this, 'HasuraHostedZone', {
            hostedZoneId: props.hostedZoneId,
            zoneName: props.hostedZoneName,
        });


        const hasuraDatabaseName = props.appName;

        const hasuraDatabase = new DatabaseInstance(this, 'HasuraDatabase', {
            instanceIdentifier: props.appName,
            databaseName: hasuraDatabaseName,
            engine: DatabaseInstanceEngine.POSTGRES,
            instanceType: InstanceType.of(InstanceClass.BURSTABLE3, InstanceSize.MICRO),
            masterUsername: 'syscdk',
            storageEncrypted: true,
            allocatedStorage: 20,
            maxAllocatedStorage: 100,
            vpc: props.vpc,
            deletionProtection: false,
            multiAz: props.multiAz,
            removalPolicy: RemovalPolicy.DESTROY,
        });

        const hasuraUsername = 'hasura';

        const hasuraUserSecret = new DatabaseSecret(this, 'HasuraDatabaseUser', {
            username: hasuraUsername,
            masterSecret: hasuraDatabase.secret,

        });
        hasuraUserSecret.attach(hasuraDatabase); // Adds DB connections information in the secret

        // Output the Endpoint Address so it can be used in post-deploy
        new CfnOutput(this, 'HasuraDatabaseUserSecretArn', {
            value: hasuraUserSecret.secretArn,
        });

        new CfnOutput(this, 'HasuraDatabaseMasterSecretArn', {
            // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
            value: hasuraDatabase.secret!.secretArn,
        });

        const hasuraDatabaseUrlSecret = new Secret(this, 'HasuraDatabaseUrlSecret', {
            secretName: `${props.appName}-HasuraDatabaseUrl`,
        });


        new CfnOutput(this, 'HasuraDatabaseUrlSecretArn', {
            value: hasuraDatabaseUrlSecret.secretArn,
        });

        const hasuraAdminSecret = new Secret(this, 'HasuraAdminSecret', {
            secretName: `${props.appName}-HasuraAdminSecret`,
        });

        new CfnOutput(this, 'HasuraAdminSecretArn', {
            value: hasuraAdminSecret.secretArn,
        });

        const hasuraJwtSecret = new Secret(this, 'HasuraJwtSecret', {
            secretName: `${props.appName}-HasuraJWTSecret`,
        });

        new CfnOutput(this, 'HasuraJwtSecretArn', {
            value: hasuraJwtSecret.secretArn,
        });


        // Create a load-balanced Fargate service and make it public
        const fargate = new ApplicationLoadBalancedFargateService(this, 'HasuraFargateService', {
            serviceName: props.appName,
            vpc: props.vpc,
            cpu: 256,
            desiredCount: props.multiAz ? 2 : 1,
            taskImageOptions: {
                image: ContainerImage.fromRegistry('hasura/graphql-engine:v1.2.1'),
                containerPort: 8080,
                enableLogging: true,
                environment: {
                    HASURA_GRAPHQL_ENABLE_CONSOLE: 'true',
                    HASURA_GRAPHQL_PG_CONNECTIONS: '100',
                    HASURA_GRAPHQL_LOG_LEVEL: 'debug',
                },
                secrets: {
                    HASURA_GRAPHQL_DATABASE_URL: ECSSecret.fromSecretsManager(hasuraDatabaseUrlSecret),
                    HASURA_GRAPHQL_ADMIN_SECRET: ECSSecret.fromSecretsManager(hasuraAdminSecret),
                    HASURA_GRAPHQL_JWT_SECRET: ECSSecret.fromSecretsManager(hasuraJwtSecret),
                },
            },
            memoryLimitMiB: 512,
            publicLoadBalancer: true, // Default is false
            certificate: props.certificates.hasura,
            domainName: props.hasuraHostname,
            domainZone: hostedZone,
            assignPublicIp: true,
        });

        fargate.targetGroup.configureHealthCheck({
            enabled: true,
            path: '/healthz',
            healthyHttpCodes: '200',
        });

        hasuraDatabase.connections.allowFrom(fargate.service, new Port({
            protocol: Protocol.TCP,
            stringRepresentation: 'Postgres Port',
            fromPort: 5432,
            toPort: 5432,
        }));
    }


}
Example #29
Source File: pipeline-stack.ts    From aws-cross-account-cicd-pipeline with MIT No Attribution 4 votes vote down vote up
export class PipelineStack extends Stack {

  constructor(app: App, id: string, props: PipelineStackProps) {

    super(app, id, props);

    const repository = codecommit.Repository.fromRepositoryName(this, 'CodeCommitRepo', `repo-${this.account}`);

    const prodDeploymentRole = iam.Role.fromRoleArn(this, 'ProdDeploymentRole', `arn:aws:iam::${props.prodAccountId}:role/CloudFormationDeploymentRole`, {
      mutable: false
    });
    const prodCrossAccountRole = iam.Role.fromRoleArn(this, 'ProdCrossAccountRole', `arn:aws:iam::${props.prodAccountId}:role/CodePipelineCrossAccountRole`, {
      mutable: false
    });

    const prodAccountRootPrincipal = new iam.AccountPrincipal(props.prodAccountId);

    const key = new kms.Key(this, 'ArtifactKey', {
      alias: 'key/artifact-key',
    });
    key.grantDecrypt(prodAccountRootPrincipal);
    key.grantDecrypt(prodCrossAccountRole);

    const artifactBucket = new s3.Bucket(this, 'ArtifactBucket', {
      bucketName: `artifact-bucket-${this.account}`,
      removalPolicy: RemovalPolicy.DESTROY,
      encryption: s3.BucketEncryption.KMS,
      encryptionKey: key
    });
    artifactBucket.grantPut(prodAccountRootPrincipal);
    artifactBucket.grantRead(prodAccountRootPrincipal);

    const cdkBuild = new codebuild.PipelineProject(this, 'CdkBuild', {
      buildSpec: codebuild.BuildSpec.fromObject({
        version: '0.2',
        phases: {
          install: {
            commands: [
              'npm install'
            ],
          },
          build: {
            commands: [
              'npm run build',
              'npm run cdk synth -- -o dist'
            ],
          },
        },
        artifacts: {
          'base-directory': 'dist',
          files: [
            '*ApplicationStack.template.json',
          ],
        },
      }),
      environment: {
        buildImage: codebuild.LinuxBuildImage.UBUNTU_14_04_NODEJS_10_14_1,
      },
      encryptionKey: key
    });
    const lambdaBuild = new codebuild.PipelineProject(this, 'LambdaBuild', {
      buildSpec: codebuild.BuildSpec.fromObject({
        version: '0.2',
        phases: {
          install: {
            commands: [
              'cd app',
              'npm install',
            ],
          },
          build: {
            commands: 'npm run build',
          },
        },
        artifacts: {
          'base-directory': 'app',
          files: [
            'index.js',
            'node_modules/**/*',
          ],
        },
      }),
      environment: {
        buildImage: codebuild.LinuxBuildImage.UBUNTU_14_04_NODEJS_10_14_1,
      },
      encryptionKey: key
    });

    const sourceOutput = new codepipeline.Artifact();
    const cdkBuildOutput = new codepipeline.Artifact('CdkBuildOutput');
    const lambdaBuildOutput = new codepipeline.Artifact('LambdaBuildOutput');

    const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
      pipelineName: 'CrossAccountPipeline',
      artifactBucket: artifactBucket,
      stages: [
        {
          stageName: 'Source',
          actions: [
            new codepipeline_actions.CodeCommitSourceAction({
              actionName: 'CodeCommit_Source',
              repository: repository,
              output: sourceOutput,
            }),
          ],
        },
        {
          stageName: 'Build',
          actions: [
            new codepipeline_actions.CodeBuildAction({
              actionName: 'Application_Build',
              project: lambdaBuild,
              input: sourceOutput,
              outputs: [lambdaBuildOutput],
            }),
            new codepipeline_actions.CodeBuildAction({
              actionName: 'CDK_Synth',
              project: cdkBuild,
              input: sourceOutput,
              outputs: [cdkBuildOutput],
            }),
          ],
        },
        {
          stageName: 'Deploy_Dev',
          actions: [
            new codepipeline_actions.CloudFormationCreateUpdateStackAction({
              actionName: 'Deploy',
              templatePath: cdkBuildOutput.atPath('DevApplicationStack.template.json'),
              stackName: 'DevApplicationDeploymentStack',
              adminPermissions: true,
              parameterOverrides: {
                ...props.devApplicationStack.lambdaCode.assign(lambdaBuildOutput.s3Location),
              },
              extraInputs: [lambdaBuildOutput],
            })
          ],
        },
        {
          stageName: 'Deploy_Prod',
          actions: [
            new codepipeline_actions.CloudFormationCreateUpdateStackAction({
              actionName: 'Deploy',
              templatePath: cdkBuildOutput.atPath('ProdApplicationStack.template.json'),
              stackName: 'ProdApplicationDeploymentStack',
              adminPermissions: true,
              parameterOverrides: {
                ...props.prodApplicationStack.lambdaCode.assign(lambdaBuildOutput.s3Location),
              },
              deploymentRole: prodDeploymentRole,
              capabilities: [cloudformation.CloudFormationCapabilities.ANONYMOUS_IAM],
              extraInputs: [lambdaBuildOutput],
              role: prodCrossAccountRole,
            }),
          ],
        },
      ],
    });

    pipeline.addToRolePolicy(new iam.PolicyStatement({
      actions: ['sts:AssumeRole'],
      resources: [`arn:aws:iam::${props.prodAccountId}:role/*`]
    }));

    new CfnOutput(this, 'ArtifactBucketEncryptionKeyArn', {
      value: key.keyArn,
      exportName: 'ArtifactBucketEncryptionKey'
    });

  }
}