constructs#Construct TypeScript Examples

The following examples show how to use constructs#Construct. 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: main.ts    From bootcamp-devops-lemoncode with MIT License 6 votes vote down vote up
constructor(scope: Construct, id: string, props: ChartProps = {}) {
    super(scope, id, props);

    const label = { app: 'hello-k8s' };

    new KubeService(this, 'service', {
      spec: {
        type: 'LoadBalancer',
        ports: [{ port: 80, targetPort: IntOrString.fromNumber(8080) }]
      }
    });

    new KubeDeployment(this, 'deployment', {
      spec: {
        replicas: 2,
        selector: {
          matchLabels: label
        },
        template: {
          metadata: { labels: label },
          spec: {
            containers: [
              {
                name: 'hello-kubernetes',
                image: 'paulbower/hello-kubernetes:1.7',
                ports: [{ containerPort: 8080 }]
              }
            ]
          }
        }
      }
    });

  }
Example #2
Source File: go-lambda-stack.ts    From cdk-examples with MIT License 6 votes vote down vote up
constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
    new Function(this, 'goLambda', {
      runtime: Runtime.GO_1_X,
      handler: 'main',
      code: Code.fromAsset(`${__dirname}/../lambda-fns/hello-world/`, {
        bundling: {
          image: Runtime.GO_1_X.bundlingImage,
          user: 'root',
          command: [
            'bash', '-c', [
              'cd /asset-input',
              'go build -o main main.go',
              'mv /asset-input/main /asset-output/'
            ].join(' && ')
          ]
        }
      })
    })    
  }
Example #3
Source File: index.ts    From cloudstructs with Apache License 2.0 6 votes vote down vote up
constructor(scope: Construct, id: string, props: EcsServiceRollerProps) {
    super(scope, id);

    const rule = props.trigger?.rule ?? new events.Rule(this, 'Rule', {
      schedule: props.trigger?.schedule ?? events.Schedule.cron({
        minute: '0',
        hour: '0',
      }),
    });


    rule.addTarget(new targets.AwsApi({
      service: 'ECS',
      action: 'updateService',
      parameters: {
        service: props.service.serviceName,
        cluster: props.cluster.clusterName,
        forceNewDeployment: true,
      } as AWS.ECS.UpdateServiceRequest,
      // https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-supported-iam-actions-resources.html
      // arn:aws:ecs:<region>:<account>:service/<cluster-name>/<service-name>
      policyStatement: new iam.PolicyStatement({
        actions: ['ecs:UpdateService'],
        resources: [Stack.of(this).formatArn({
          service: 'ecs',
          resource: 'service',
          resourceName: `${props.cluster.clusterName}/${props.service.serviceName}`,
        })],
      }),
    }));
  }
Example #4
Source File: aurora-serverless.ts    From bastion-host-forward with Apache License 2.0 6 votes vote down vote up
constructor(scope: Construct, id: string, props: BastionHostAuroraServerlessForwardProps) {
    super(scope, id, {
      vpc: props.vpc,
      name: props.name,
      securityGroup: props.securityGroup,
      address: props.serverlessCluster.clusterEndpoint.hostname,
      port: Token.asString(props.serverlessCluster.clusterEndpoint.port),
      clientTimeout: props.clientTimeout,
      serverTimeout: props.serverTimeout,
    });

    if (props.iamUser !== undefined && props.resourceIdentifier !== undefined) {
      this.bastionHost.instance.addToRolePolicy(
        new iam.PolicyStatement({
          effect: iam.Effect.ALLOW,
          actions: ['rds-db:connect', 'rds:*'],
          resources: [
            this.genDbUserArnFromRdsArn(props.resourceIdentifier, props.iamUser),
            props.serverlessCluster.clusterArn,
          ],
        }),
      );
    }
  }
Example #5
Source File: spa-deploy-construct.ts    From CDK-SPA-Deploy with MIT License 6 votes vote down vote up
constructor(scope: Construct, id:string, config?:SPAGlobalConfig) {
      super(scope, id);

      if (typeof config !== 'undefined') {
        this.globalConfig = config;
      } else {
        this.globalConfig = {
          encryptBucket: false,
          ipFilter: false,
        };
      }
    }
Example #6
Source File: autoScalingGroup.ts    From aws-cdk-microservice with Apache License 2.0 6 votes vote down vote up
constructor(scope: Construct, id: string, props: AutoScalerProps) {
    super(scope, id);

    const launchTemplate = this.getLT(props.templateProps, props.asgName);
    this.loadBalancerProperties = this.getTG(props.networkProps, props.templateProps.vpc.vpcName, props.appName);

    new CfnAutoScalingGroup(this, props.asgName, {
      maxSize: props.maxSize,
      minSize: props.minSize,
      autoScalingGroupName: props.asgName,
      launchTemplate: {
        version: launchTemplate.versionNumber,
        launchTemplateId: launchTemplate.launchTemplateId,
        launchTemplateName: launchTemplate.launchTemplateName,
      },
      targetGroupArns: this.loadBalancerProperties.map( (lb) => { return lb.targetGroupArn; } ),
      tags: props.tags,
      availabilityZones: props.availabilityZones,
      vpcZoneIdentifier: props.subnets,
      healthCheckGracePeriod: 300,
    });
  }
Example #7
Source File: 001_UserPool.ts    From flect-chime-sdk-demo with Apache License 2.0 6 votes vote down vote up
createUserPool = (scope: Construct, id: string) => {
    const userPool = new cognito.UserPool(scope, `${id}_UserPool`, {
        userPoolName: `${id}_UserPool`,
        selfSignUpEnabled: true,
        autoVerify: {
            email: true,
        },
        passwordPolicy: {
            minLength: 6,
            requireSymbols: false,
        },
        signInAliases: {
            email: true,
        },
    });

    const userPoolClient = new cognito.UserPoolClient(scope, id + "_UserPool_Client", {
        userPoolClientName: `${id}_UserPoolClient`,
        userPool: userPool,
        accessTokenValidity: Duration.minutes(1440),
        idTokenValidity: Duration.minutes(1440),
        refreshTokenValidity: Duration.days(30),
    });

    return { userPool, userPoolClient }
}
Example #8
Source File: certificate-stack.ts    From minwiz with BSD 2-Clause "Simplified" License 6 votes vote down vote up
constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    this.hostedZone = HostedZone.fromHostedZoneAttributes(
      this,
      "HostedZoneWithAttrs",
      {
        hostedZoneId,
        zoneName: website_domain,
      }
    );

    this.websiteCert = new DnsValidatedCertificate(this, "MinWizSSL", {
      domainName: website_domain,
      subjectAlternativeNames: [`www.${website_domain}`],
      hostedZone: this.hostedZone,
    });

    new CfnOutput(this, "WebsiteCertArn", {
      value: this.websiteCert.certificateArn,
    });
  }
Example #9
Source File: cloudfront-http-api-stack.ts    From cdk-examples with MIT License 5 votes vote down vote up
constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
    ///////////////////////////////
    // Part 1
    const hostedZone = HostedZone.fromHostedZoneAttributes(this, 'hostedZoneWithAttributes', {
        hostedZoneId,
        zoneName: website_domain
    })
  
    const certificate = new DnsValidatedCertificate(this, 'ApiSSL', {
        domainName: website_domain,
        hostedZone
    })

    const api = new HttpApi(this, 'apiEndpoint', {
        apiName: 'exampleAPISameDomain',
    })
    
    new CfnOutput(this, 'apiID', {
        value: api.apiEndpoint
    })
    
    const signUpFn = new Function(this, 'signUpFn', {
        runtime: Runtime.NODEJS_16_X,
        code: Code.fromAsset(`${__dirname}/../lambda-fns/sign-up/deployment.zip`),
        handler: 'index.handler',
        memorySize: 512,
        architecture: Architecture.ARM_64
    })
    ///////////////////////////////
    
    ///////////////////////////////
    // Part 2
    api.addRoutes({
        path: '/api/sign-up',
        methods: [HttpMethod.POST],
        integration: new HttpLambdaIntegration('signUpFn', signUpFn)
    })
    
    const apiOriginPolicy = new OriginRequestPolicy(this, 'apiOriginPolicy', {
        cookieBehavior: OriginRequestCookieBehavior.all(),
        headerBehavior: OriginRequestHeaderBehavior.none(),
        queryStringBehavior: OriginRequestQueryStringBehavior.all()
    })
    
    const distribution = new Distribution(this, 'websiteAndAPIDistribution', {
        defaultBehavior: {
            origin: new HttpOrigin('origin-source-code.com'),
        },
        additionalBehaviors: {
            'api/*': {
                origin: new HttpOrigin(api.apiEndpoint.replace('https://', '')),
                allowedMethods: AllowedMethods.ALLOW_ALL,
                cachePolicy: CachePolicy.CACHING_DISABLED,
                compress: false,
                originRequestPolicy: apiOriginPolicy,
                viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS
            }
        },
        domainNames: [website_domain],
        certificate,
        minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2021,
        enableIpv6: true,
        enabled: true,
        httpVersion: HttpVersion.HTTP2,
        priceClass: PriceClass.PRICE_CLASS_ALL
    })
    ///////////////////////////////

    ///////////////////////////////
    // Part 3
    new ARecord(this, 'AliasForCloudfront', {
        target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
        zone: hostedZone,
        recordName: website_domain
    })
    ///////////////////////////////
  }
Example #10
Source File: aws-image-builder-stack.ts    From amazon-ec2-image-builder-samples with MIT No Attribution 5 votes vote down vote up
constructor(scope: Construct, id: string, props: StackProps) {
    super(scope, id, props);

    /**
     * S3 Bucket
     * Hosts the Image builder Installation files code.
     */
    this.imageBuilderToolsBucket = new AWSSecureBucket(
      this,
      "toolsBucket",
      {}
    ).bucket;

    const vpc = Vpc.fromLookup(this, "vpc", {
      isDefault: true,
    });

    /**
     * S3 Deploy
     * Uploads react built code to the S3 bucket and invalidates CloudFront
     */

    new BucketDeployment(this, "Deploy-components", {
      sources: [Source.asset("./image-builder-components")],
      destinationBucket: this.imageBuilderToolsBucket,
      memoryLimit: 3008,
      prune: false,
    });

    // ? Create a SG for a Image builder server
    const imageBuilderSG = new SecurityGroup(this, "image-server-sg", {
      vpc: vpc,
      allowAllOutbound: true,
      description: "security group for a image builder server",
    });
    // Choose the subnet Image builder server - ensure it has internet
    const imageBuilderSubnetId = vpc.selectSubnets({
      subnetType: SubnetType.PUBLIC,
    }).subnetIds[0];

    const imageBuilderPipelineConfigurations =
      this.validAndGetPipelineConfiguration();
    if (!imageBuilderPipelineConfigurations) {
      return;
    }

    for (const imageBuilderPipeline of imageBuilderPipelineConfigurations) {
      this.createImageBuilderByConfig(
        imageBuilderPipeline,
        imageBuilderSubnetId,
        imageBuilderSG,
        vpc
      );
    }
  }
Example #11
Source File: resource-handler.ts    From cdk-cognito-idp with MIT No Attribution 5 votes vote down vote up
constructor(
        private parent: Construct,
        private stackName: string,
        private envVars: any,
        private api: apigw.RestApi,
        private cfnAuthorizer: apigw.CfnAuthorizer, 
        private lambdaFunctionDirectory: string) { }
Example #12
Source File: index.ts    From cloudstructs with Apache License 2.0 5 votes vote down vote up
constructor(scope: Construct, id: string, props: CodeCommitMirrorProps) {
    super(scope, id);

    const destination = new codecommit.Repository(this, 'Repository', {
      repositoryName: props.repository.name,
      description: `Mirror of ${props.repository.name}`,
    });

    const taskDefinition = new ecs.FargateTaskDefinition(this, 'TaskDefinition');

    taskDefinition.addContainer('Container', {
      image: ecs.ContainerImage.fromAsset(path.join(__dirname, '..', '..', 'assets', 'codecommit-mirror', 'docker')),
      logging: new ecs.AwsLogDriver({
        streamPrefix: props.repository.name,
        logRetention: logs.RetentionDays.TWO_MONTHS,
      }),
      environment: {
        NAME: props.repository.name,
        DESTINATION: destination.repositoryCloneUrlGrc,
        ...props.repository.plainTextUrl
          ? { SOURCE: props.repository.plainTextUrl }
          : {},
      },
      secrets: props.repository.secretUrl
        ? { SOURCE: props.repository.secretUrl }
        : undefined,
    });

    taskDefinition.addToTaskRolePolicy(new iam.PolicyStatement({
      actions: ['codecommit:GitPush'],
      resources: [destination.repositoryArn],
    }));

    const rule = new events.Rule(this, 'Rule', {
      schedule: props.schedule ?? events.Schedule.cron({
        minute: '0',
        hour: '0',
      }),
    });

    rule.addTarget(new targets.EcsTask({
      cluster: props.cluster,
      taskDefinition,
      subnetSelection: props.subnetSelection ?? { subnetType: ec2.SubnetType.PUBLIC },
    }));
  }
Example #13
Source File: bastion-host-forward.ts    From bastion-host-forward with Apache License 2.0 5 votes vote down vote up
export class BastionHostForward extends Construct {
  /**
   * @returns the id of the bastion host, which can be used by the session
   * manager connect command afterwards
   */
  public instanceId?: string;

  /**
   * @returns the security group attached to the bastion host
   */
  public securityGroup?: ISecurityGroup;

  /**
   * @returns The BastionHost Instance
   */
  protected readonly bastionHost: BastionHostLinux;

  protected constructor(scope: Construct, id: string, props: BastionHostForwardProps) {
    super(scope, id);
    this.securityGroup =
      props.securityGroup ??
      new SecurityGroup(this, 'BastionHostSecurityGroup', {
        vpc: props.vpc,
        allowAllOutbound: true,
      });

    this.bastionHost = new BastionHostLinux(this, 'BastionHost', {
      instanceName: props.name ?? 'BastionHost',
      vpc: props.vpc,
      securityGroup: this.securityGroup,
    });

    const cfnBastionHost = this.bastionHost.instance.node.defaultChild as CfnInstance;
    const shellCommands = generateEc2UserData({
      address: props.address,
      port: props.port,
      clientTimeout: props.clientTimeout ?? 1,
      serverTimeout: props.serverTimeout ?? 1,
    });
    cfnBastionHost.userData = Fn.base64(shellCommands.render());

    this.instanceId = this.bastionHost.instance.instanceId;
  }
}
Example #14
Source File: dns-validated-domain-identity.ts    From aws-cdk-ses-domain-identity with MIT License 5 votes vote down vote up
public constructor(scope: Construct, id: string, props: DnsValidatedDomainIdentityProps) {
    super(scope, id);

    const stack = Stack.of(this);

    const region = props.region ?? stack.region;
    const accountId = stack.account;

    this.domainName = props.domainName;
    this.dkim = props.dkim ?? false;
    this.identityArn = `arn:aws:ses:${region}:${accountId}:identity/${this.domainName}`;
    this.normalizedZoneName = props.hostedZone.zoneName;
    // Remove trailing `.` from zone name
    if (this.normalizedZoneName.endsWith(".")) {
      this.normalizedZoneName = this.normalizedZoneName.substring(0, this.normalizedZoneName.length - 1);
    }

    // Remove any `/hostedzone/` prefix from the Hosted Zone ID
    this.hostedZoneId = props.hostedZone.hostedZoneId.replace(/^\/hostedzone\//, "");

    const requestorFunction = new lambda.Function(this, "DomainIdentityRequestorFunction", {
      code: lambda.Code.fromAsset(path.resolve(__dirname, "..", "lambda-packages", "dns-validated-domain-identity-handler", "dist")),
      handler: "index.identityRequestHandler",
      runtime: lambda.Runtime.NODEJS_14_X,
      memorySize: 128,
      timeout: Duration.minutes(15),
      role: props.customResourceRole,
    });
    requestorFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: [
        "ses:GetIdentityVerificationAttributes",
        "ses:GetIdentityDkimAttributes",
        "ses:SetIdentityDkimEnabled",
        "ses:VerifyDomainIdentity",
        "ses:VerifyDomainDkim",
        "ses:ListIdentities",
        "ses:DeleteIdentity",
      ],
      resources: ["*"],
    }));
    requestorFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: ["route53:GetChange"],
      resources: ["*"],
    }));
    requestorFunction.addToRolePolicy(new iam.PolicyStatement({
      actions: [
          "route53:changeResourceRecordSets",
          "route53:ListResourceRecordSets",
      ],
      resources: [`arn:${Stack.of(requestorFunction).partition}:route53:::hostedzone/${this.hostedZoneId}`],
    }));

    const identity = new CustomResource(this, "IdentityRequestorResource", {
      serviceToken: requestorFunction.functionArn,
      properties: {
        DomainName: this.domainName,
        HostedZoneId: this.hostedZoneId,
        Region: region,
        DKIM: props.dkim,
      },
    });

    this.node.addValidation({
      validate: (): string[] => {
        const errors: string[] = [];
        // Ensure the zone name is a parent zone of the certificate domain name
        if (!Token.isUnresolved(this.normalizedZoneName) &&
          this.domainName !== this.normalizedZoneName &&
          !this.domainName.endsWith("." + this.normalizedZoneName)) {
          errors.push(`DNS zone ${this.normalizedZoneName} is not authoritative for SES identity domain name ${this.domainName}`);
        }

        return errors;
      },
    });
  }
Example #15
Source File: index.ts    From cdk-aurora-globaldatabase with Apache License 2.0 5 votes vote down vote up
public addRegionalCluster(scope: Construct, id: string, options: RegionalOptions) {
    const stack = cdk.Stack.of(scope);
    // custom resource policy
    const CustomResourcePolicy = new iam.PolicyStatement({
      resources: ['*'],
      actions: [
        'rds:CreateGlobalCluster', 'rds:DeleteGlobalCluster', 'rds:RemoveFromGlobalCluster', 'rds:ModifyGlobalCluster',
        'rds:CreateDBCluster', 'rds:CreateDBInstance', 'rds:DeleteDBCluster', 'rds:DeleteDBInstance', 'rds:DescribeDBInstances',
        'rds:DescribeGlobalClusters',
      ],
    });
    // Upgrade database to Global.
    const onEvent = new lambda.Function(scope, `${id}-addRegionalonEvent`, {
      runtime: lambda.Runtime.PYTHON_3_8,
      code: lambda.Code.fromAsset(path.join(__dirname, '../custom-resource-handler')),
      handler: 'add_region_index.on_event',
      timeout: cdk.Duration.minutes(10),
    });

    const isComplete = new lambda.Function(scope, `${id}-IsComplete`, {
      code: lambda.Code.fromAsset(path.join(__dirname, '../custom-resource-handler')),
      handler: 'add_region_index.is_complete',
      runtime: lambda.Runtime.PYTHON_3_8,
      timeout: cdk.Duration.minutes(10),
      role: onEvent.role,
    });

    const addRegionalProvider = new cr.Provider(scope, `${id}-addRegionalProvider`, {
      onEventHandler: onEvent,
      isCompleteHandler: isComplete,
      logRetention: logs.RetentionDays.ONE_DAY,
    });

    const CRSecondRDSProvider = new cdk.CustomResource(scope, `${id}-addRegionalCustomResource`, {
      resourceType: 'Custom::addRegionalClusterProvider',
      serviceToken: addRegionalProvider.serviceToken,
      properties: {
        SourceDBClusterIdentifier: this.rdsClusterarn,
        GlobalClusterIdentifier: this.globalClusterIdentifier,
        REGION: options.region,
        DBSubnetGroupName: options.dbSubnetGroupName,
        Engine: this.engine,
        EngineVersion: this.clusterEngineVersion,
        ClusterIdentifier: `${stack.stackName.toLowerCase()}-${options.region}`,
        InstanceType: this.rdsInstanceType,
        rdsIsPublic: this.rdsIsPublic,
        secondRDSClusterArn: `arn:aws:rds:${options.region}:${stack.account}:cluster:${stack.stackName.toLowerCase()}-${options.region}`,
        seconddbInstanceIdentifier: `${stack.stackName.toLowerCase()}-${options.region}-1`,
      },
    });
    CRSecondRDSProvider.node.addDependency(this.crGlobalRDSProvider);
    onEvent.role?.addToPrincipalPolicy(CustomResourcePolicy);

    new cdk.CfnOutput(scope, 'secondRDSClusterArn', {
      value: cdk.Token.asString(CRSecondRDSProvider.getAtt('secondRDSClusterArn')),
    });

    new cdk.CfnOutput(scope, 'seconddbInstanceIdentifier', {
      value: cdk.Token.asString(CRSecondRDSProvider.getAtt('seconddbInstanceIdentifier')),
    });
  }
Example #16
Source File: network.ts    From aws-cdk-microservice with Apache License 2.0 5 votes vote down vote up
constructor(scope: Construct, id: string, props: LoadBalancerProps) {
    super(scope, id);
    const listeners = this.getLoadBalancerListener(props.lbArn, props.sslEnabled, props.appName);
    if (props.sslEnabled) {
      new CfnListenerRule(this, props.appName + '-https-rule', {
        listenerArn: listeners[0],
        actions: [
          {
            type: 'forward',
            targetGroupArn: props.targetGroupArn,
          },
        ],
        conditions: [
          {
            field: 'host-header',
            hostHeaderConfig: {
              values: [props.hostHeader],
            },
          },
        ],
        priority: Math.floor(Math.random() * (1000 - 200 + 1)) + 200, // this line is a flipping leap of faith
      });
    } else {
      new CfnListenerRule(this, props.appName + '-http-rule', {
        listenerArn: listeners[0],
        actions: [
          {
            type: 'forward',
            targetGroupArn: props.targetGroupArn,
          },
        ],
        conditions: [
          {
            field: 'host-header',
            hostHeaderConfig: {
              values: [props.hostHeader],
            },
          },
        ],
        priority: Math.floor(Math.random() * (1000 - 200 + 1)) + 200, // this line is a flipping leap of faith
      });
    }
    this.createRoute53Entry(props);
  }
Example #17
Source File: test-stack.ts    From cdk-ec2-key-pair with Apache License 2.0 5 votes vote down vote up
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    cdk.Tags.of(scope).add('Hello', 'World');

    const keyPair = new KeyPair(this, 'Test-Key-Pair', {
      name: 'test-key-pair',
      description: 'A test Key Pair',
      removeKeySecretsAfterDays: 0,
      storePublicKey: false,
      exposePublicKey: true,
    });

    cdk.Tags.of(keyPair).add('a', 'b');
    cdk.Tags.of(keyPair).add('c', 'd');

    new cdk.CfnOutput(this, 'Test-Public-Key', {
      exportName: 'TestPublicKey',
      value: keyPair.publicKeyValue,
    });

    // import public key

    const keyPairImport = new KeyPair(this, 'Test-Key-Pair-Import', {
      name: 'test-key-pair-import',
      description: 'A test Key Pair, imported via public key',
      removeKeySecretsAfterDays: 0,
      storePublicKey: false,
      exposePublicKey: true,
      publicKey: keyPair.publicKeyValue,
    });

    new cdk.CfnOutput(this, 'Test-Public-Key-Import', {
      exportName: 'TestPublicKeyImport',
      value: keyPairImport.publicKeyValue,
    });

    // PEM && CloudFront

    const keyPairPem = new KeyPair(this, 'Test-Key-Pair-PEM', {
      name: 'CFN-signing-key',
      exposePublicKey: true,
      storePublicKey: true,
      publicKeyFormat: PublicKeyFormat.PEM,
    });

    new cdk.CfnOutput(this, 'Test-Public-Key-PEM', {
      exportName: 'TestPublicKeyPEM',
      value: keyPairPem.publicKeyValue,
    });

    const pubKey = new cloudfront.PublicKey(this, 'Signing-Public-Key', {
      encodedKey: keyPairPem.publicKeyValue,
    });

    new cloudfront.KeyGroup(this, 'Signing-Key-Group', {
      items: [pubKey],
    });
  }
Example #18
Source File: index.ts    From cdk-ssm-document with Apache License 2.0 5 votes vote down vote up
/**
   * Defines a new SSM document
   */
  constructor(scope: Construct, id: string, props: DocumentProps) {
    super(scope, id);

    this.tags = new TagManager(TagType.MAP, 'Custom::SSM-Document');
    this.tags.setTag(createdByTag, ID);

    const stack = Stack.of(this).stackName;
    this.lambda = this.ensureLambda();
    const name = this.fixDocumentName(props.name);

    if (name.length < 3 || name.length > 128) {
      Annotations.of(this).addError(
        `SSM Document name ${name} is invalid. The name must be between 3 and 128 characters.`
      );
      return;
    }

    let content = props.content;

    if (typeof content === 'string') {
      content = yaml.safeLoad(content) as DocumentContent;
    }

    const document = new CustomResource(this, `SSM-Document-${name}`, {
      serviceToken: this.lambda.functionArn,
      resourceType: resourceType,
      properties: {
        updateDefaultVersion: props.updateDefaultVersion || true,
        name: name,
        content: content,
        documentType: props.documentType || 'Command',
        targetType: props.targetType || '/',
        attachments: props.attachments,
        versionName: props.versionName,
        StackName: stack,
        tags: Lazy.any({
          produce: () => this.tags.renderTags(),
        }),
      },
      pascalCaseProperties: true,
    });

    this.name = document.getAttString('Name');
  }
Example #19
Source File: 001_FrontendBucket.ts    From flect-chime-sdk-demo with Apache License 2.0 5 votes vote down vote up
createFrontendS3 = (scope: Construct, id: string, USE_CDN: boolean) => {
    const frontendBucket = new s3.Bucket(scope, "StaticSiteBucket", {
        bucketName: `${id}-Bucket`.toLowerCase(),
        removalPolicy: RemovalPolicy.DESTROY,
        publicReadAccess: true,
    });


    let frontendCdn: cloudfront.CloudFrontWebDistribution | null = null;
    if (USE_CDN) {
        const oai = new cloudfront.OriginAccessIdentity(scope, "my-oai");

        const myBucketPolicy = new iam.PolicyStatement({
            effect: iam.Effect.ALLOW,
            actions: ["s3:GetObject"],
            principals: [new iam.CanonicalUserPrincipal(oai.cloudFrontOriginAccessIdentityS3CanonicalUserId)],
            resources: [frontendBucket.bucketArn + "/*"],
        });
        frontendBucket.addToResourcePolicy(myBucketPolicy);

        // Create CloudFront WebDistribution
        frontendCdn = new cloudfront.CloudFrontWebDistribution(scope, "WebsiteDistribution", {
            viewerCertificate: {
                aliases: [],
                props: {
                    cloudFrontDefaultCertificate: true,
                },
            },
            priceClass: cloudfront.PriceClass.PRICE_CLASS_ALL,
            originConfigs: [
                {
                    s3OriginSource: {
                        s3BucketSource: frontendBucket,
                        originAccessIdentity: oai,
                    },
                    behaviors: [
                        {
                            isDefaultBehavior: true,
                            minTtl: Duration.seconds(0),
                            maxTtl: Duration.days(365),
                            defaultTtl: Duration.days(1),
                            pathPattern: "my-contents/*",
                        },
                    ],
                },
            ],
            errorConfigurations: [
                {
                    errorCode: 403,
                    responsePagePath: "/index.html",
                    responseCode: 200,
                    errorCachingMinTtl: 0,
                },
                {
                    errorCode: 404,
                    responsePagePath: "/index.html",
                    responseCode: 200,
                    errorCachingMinTtl: 0,
                },
            ],
        });
    }
    return { frontendBucket, frontendCdn }
}
Example #20
Source File: cloudfront.ts    From minwiz with BSD 2-Clause "Simplified" License 5 votes vote down vote up
constructor(scope: Construct, id: string, props: CloudfrontStackProps) {
    super(scope, id, props);

    this.websiteBucket = new Bucket(this, "websiteBucket", {
      removalPolicy: RemovalPolicy.DESTROY,
      bucketName: website_domain,
      autoDeleteObjects: true,
    });

    new CfnOutput(this, "websiteBucketArn", {
      value: this.websiteBucket.bucketArn,
    });

    const cachePolicy = new CachePolicy(this, "MinWizPolicy", {
      defaultTtl: Duration.hours(24),
      minTtl: Duration.hours(24),
      maxTtl: Duration.hours(24),
      enableAcceptEncodingGzip: true,
      enableAcceptEncodingBrotli: true,
    });

    const distribution = new Distribution(this, "MinWizDistribution", {
      defaultBehavior: {
        origin: new S3Origin(this.websiteBucket),
        allowedMethods: AllowedMethods.ALLOW_GET_HEAD_OPTIONS,
        cachePolicy,
        compress: true,
        viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
      },
      domainNames: [website_domain /*, `www.${website_domain}`*/],
      certificate: props.websiteCert,
      minimumProtocolVersion: SecurityPolicyProtocol.TLS_V1_2_2019,
      defaultRootObject: "index.html",
      enableIpv6: true,
      enabled: true,
      httpVersion: HttpVersion.HTTP2,
      priceClass: PriceClass.PRICE_CLASS_ALL,
    });

    new ARecord(this, "aliasForCloudfront", {
      target: RecordTarget.fromAlias(new CloudFrontTarget(distribution)),
      zone: props.hostedZone,
      recordName: website_domain,
    });

    new HttpsRedirect(this, "wwwToNonWww", {
      recordNames: [`www.${website_domain}`],
      targetDomain: website_domain,
      zone: props.hostedZone,
    });
  }
Example #21
Source File: dynamodb-crud-stack.ts    From cdk-examples with MIT License 4 votes vote down vote up
constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // The code that defines your stack goes here
    const todoTable = new Table(this, 'todoTable', {
      partitionKey: {
        name: 'id',
        type: AttributeType.STRING
      },
      billingMode: BillingMode.PAY_PER_REQUEST,
      removalPolicy: RemovalPolicy.DESTROY
    })

    todoTable.addGlobalSecondaryIndex({
      indexName: 'ownerIndex',
      partitionKey: {
        name: 'owner',
        type: AttributeType.STRING
      }
    })

    new CfnOutput(this, 'todoTableName', {
      value: todoTable.tableName
    })

    const createTodoFn = new NodejsFunction(this, 'createTodoFn', {
      runtime: Runtime.NODEJS_16_X,
      entry: `${__dirname}/../lambda-fns/create/index.ts`,
      handler: 'createTodo',
      architecture: Architecture.ARM_64,
      environment: {
        TODO_TABLE_NAME: todoTableName
      }
    })

    todoTable.grantReadWriteData(createTodoFn)

    const getAllTodoFn = new NodejsFunction(this, 'getAllTodoFn', {
      runtime: Runtime.NODEJS_16_X,
      entry: `${__dirname}/../lambda-fns/getAll/index.ts`,
      handler: 'getAll',
      architecture: Architecture.ARM_64,
      environment: {
        TODO_TABLE_NAME: todoTableName
      }
    })

    todoTable.grantReadData(getAllTodoFn)

    const getOneTodoFn = new NodejsFunction(this, 'getOneTodoFn', {
      runtime: Runtime.NODEJS_16_X,
      entry: `${__dirname}/../lambda-fns/getOne/index.ts`,
      handler: 'getOne',
      architecture: Architecture.ARM_64,
      environment: {
        TODO_TABLE_NAME: todoTableName
      }
    })

    todoTable.grantReadData(getOneTodoFn)

    const updateTodoFn = new NodejsFunction(this, 'updateTodoFn', {
      runtime: Runtime.NODEJS_16_X,
      entry: `${__dirname}/../lambda-fns/update/index.ts`,
      handler: 'update',
      architecture: Architecture.ARM_64,
      environment: {
        TODO_TABLE_NAME: todoTableName
      }
    })

    todoTable.grantReadWriteData(updateTodoFn)

    const deleteTodoFn = new NodejsFunction(this, 'deleteTodoFn', {
      runtime: Runtime.NODEJS_16_X,
      entry: `${__dirname}/../lambda-fns/delete/index.ts`,
      handler: 'deleteTodo',
      architecture: Architecture.ARM_64,
      environment: {
        TODO_TABLE_NAME: todoTableName
      }
    })

    todoTable.grantReadWriteData(deleteTodoFn)

    const tableWithIndex = Table.fromTableAttributes(this, 'tableWithIndex', {
      tableName: todoTableName,
      globalIndexes: ['ownerIndex']
    })

    const queryTodoFn = new NodejsFunction(this, 'queryTodoFn', {
      runtime: Runtime.NODEJS_16_X,
      entry: `${__dirname}/../lambda-fns/query/index.ts`,
      handler: 'queryTodo',
      architecture: Architecture.ARM_64,
      environment: {
        TODO_TABLE_NAME: todoTableName
      }
    })

    tableWithIndex.grantReadData(queryTodoFn)
  }
Example #22
Source File: aws-image-builder.ts    From amazon-ec2-image-builder-samples with MIT No Attribution 4 votes vote down vote up
constructor(scope: Construct, id: string, props: AWSImageBuilderProps) {
    super(scope, id);

    //creates a role for Imagebuilder to build EC2 image
    const imageBuilderRole = new Role(this, `ImageBuilderRole${props.name}`, {
      assumedBy: new ServicePrincipal("ec2.amazonaws.com"),
      path: "/executionServiceEC2Role/",
    });

    const amiTable = new CfnMapping(this, "ami-table", {
      mapping: props.parentImage,
    });

    const parentImageID: string = amiTable.findInMap(
      Stack.of(this).region,
      "amiID"
    );

    //creates a the necessary policy for Imagebuilder to build EC2 image
    imageBuilderRole.addToPolicy(
      new PolicyStatement({
        resources: ["*"],
        actions: ["s3:PutObject"],
      })
    );

    //Adds SSM  Managed policy to role
    imageBuilderRole.addManagedPolicy(
      ManagedPolicy.fromAwsManagedPolicyName("AmazonSSMManagedInstanceCore")
    );
    //Adds EC2InstanceProfileForImageBuilder policy to role
    imageBuilderRole.addManagedPolicy(
      ManagedPolicy.fromAwsManagedPolicyName(
        "EC2InstanceProfileForImageBuilder"
      )
    );
    //Builds the instance Profile to be attached to EC2 instance created during image building
    const instanceProfile = new CfnInstanceProfile(
      this,
      `imageBuilderProfile${props.name}`,
      {
        roles: [imageBuilderRole.roleName],
        instanceProfileName: `${props.instanceProfileName}-${Aws.REGION}`,
      }
    );
    const notificationTopic = new Topic(
      this,
      "ImgBuilderNotificationTopic",
      {}
    );

    //Manage Infrastructure configurations
    const cfnInfrastructureConfiguration = new CfnInfrastructureConfiguration(
      this,
      `cfnInfrastructureConfiguration${props.name}`,
      {
        name: "infraConfiguration",
        instanceProfileName: `${props.instanceProfileName}-${Aws.REGION}`,
        instanceTypes: instanceTypes,
        subnetId: props.subnetId,
        securityGroupIds: [props.imageBuilderSG.securityGroupId],
        snsTopicArn: notificationTopic.topicArn,
      }
    );

    const componentArn = props.imageBuilderComponentList.map(
      (componentList) => ({
        componentArn: new CfnComponent(this, `${componentList.name}`, {
          name: `${componentList.name}`,
          platform: os_types.LINUX,
          version: props.version,
          data: `${componentList.data}`,
        }).attrArn,
      })
    );

    const cfnImageRecipe = new CfnImageRecipe(
      this,
      `cfnImageRecipe${props.name}`,
      {
        name: props.cfnImageRecipeName,
        version: props.version,
        parentImage: parentImageID,
        components: componentArn,
      }
    );

    const cfnImageBuilderPipeline = new CfnImagePipeline(
      this,
      `imageBuilderPipeline${props.name}`,
      {
        name: `imageBuilderPipeline${props.name}`,
        infrastructureConfigurationArn: cfnInfrastructureConfiguration.attrArn,
        imageRecipeArn: cfnImageRecipe.attrArn,
      }
    );
    const imagebuilderCr = new PythonFunction(this, "imagebuilderCr", {
      entry: "lib/lambda/imagebuilder",
      runtime: Runtime.PYTHON_3_8,
      index: "app.py",
      handler: "lambda_handler",
      environment: {
        IMAGE_SSM_NAME: props.amiIdLocation.parameterName,
      },
      timeout: Duration.seconds(45),
      initialPolicy: [
        new PolicyStatement({
          effect: Effect.ALLOW,
          actions: ["imagebuilder:StartImagePipelineExecution"],
          resources: [
            `arn:aws:imagebuilder:${Stack.of(this).region}:${
              Stack.of(this).account
            }:image/*`,
            `arn:aws:imagebuilder:${Stack.of(this).region}:${
              Stack.of(this).account
            }:image-pipeline/*`,
          ],
        }),
      ],
    });

    imagebuilderCr.node.addDependency(cfnImageBuilderPipeline);

    const pipelineTriggerCrProvider = new cr.Provider(
      this,
      "pipelineTriggerCrProvider",
      {
        onEventHandler: imagebuilderCr,
        logRetention: RetentionDays.ONE_DAY,
      }
    );

    new CustomResource(this, id, {
      serviceToken: pipelineTriggerCrProvider.serviceToken,
      properties: {
        PIIPELINE_ARN: `arn:aws:imagebuilder:${Stack.of(this).region}:${
          Stack.of(this).account
        }:image-pipeline/${cfnImageBuilderPipeline.name.toLowerCase()}`,
      },
    });
    const amiIdRecorder = new PythonFunction(this, "imageRecorder", {
      entry: "lib/lambda/recorder",
      runtime: Runtime.PYTHON_3_8,
      index: "app.py",
      handler: "lambda_handler",
      environment: {
        IMAGE_SSM_NAME: props.amiIdLocation.parameterName,
      },
    });

    props.amiIdLocation.grantRead(amiIdRecorder);
    props.amiIdLocation.grantWrite(amiIdRecorder);

    notificationTopic.addSubscription(new LambdaSubscription(amiIdRecorder));
    this.subscribeEmails(notificationTopic);

    cfnInfrastructureConfiguration.addDependsOn(instanceProfile);
    cfnImageBuilderPipeline.addDependsOn(cfnInfrastructureConfiguration);
  }
Example #23
Source File: cognito-idp-stack.ts    From cdk-cognito-idp with MIT No Attribution 4 votes vote down vote up
constructor(scope: Construct, id: string, props: CognitoIdpStackProps) {
        super(scope, id, props);

        if (!props.env) {
            throw Error('props.env is required');
        }

        if (!props.env.region) {
            throw Error('props.env.region is required');
        }

        if (!props.env.account) {
            throw Error('props.env.account is required');
        }

        const region = props.env.region;
        const accountId = props.env.account;

        // Users Table - Store basic user details we get from Cognito
        const userTable = new dynamodb.Table(this, 'UsersTable', {
            partitionKey: { name: 'id', type: dynamodb.AttributeType.STRING },
            billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
            pointInTimeRecovery: true,
            removalPolicy: cdk.RemovalPolicy.RETAIN
        });

        // Index on username
        userTable.addGlobalSecondaryIndex({
            indexName: 'username-index',
            partitionKey: {
                name: 'username',
                type: dynamodb.AttributeType.STRING
            },
            projectionType: dynamodb.ProjectionType.ALL
        });

        // Output the name of the user table
        const userTableOut = new cdk.CfnOutput(this, 'UserTableName', {
            value: userTable.tableName,
            exportName: 'CognitoIdpUserTableName',
        });

        // Cognito User Pool
        const userPool = new cognito.UserPool(this, 'CognitoIDPUserPool', {
            selfSignUpEnabled: false,
            signInAliases: {
                email: true,
                username: true
            },
            standardAttributes: {
                email: {
                    mutable: true,
                    required: true
                },
                givenName: {
                    mutable: true,
                    required: true
                },
                familyName: {
                    mutable: true,
                    required: true
                }
            }
        });

        // Output the User Pool ID
        const userPoolOut = new cdk.CfnOutput(this, 'CognitoIDPUserPoolOut', {
            value: userPool.userPoolId,
            exportName: 'CognitoIDPUserPoolId'
        });

        // Set up an admin group in the user pool
        const adminsGroup = new cognito.CfnUserPoolGroup(this, "AdminsGroup", {
            userPoolId: userPool.userPoolId
        });

        // We will ask the IDP to redirect back to our domain's index page
        const redirectUri = `https://${props.webDomainName}`;

        // Amazon Federate Client Secret
        const secret = secrets.Secret.fromSecretAttributes(this, 'FederateSecret', {
            secretCompleteArn: props.facebookSecretArn,
        });

        // Facebook IDP
        const idp = new cognito.UserPoolIdentityProviderFacebook(this, 'FacebookIDP', {
            clientId: props.facebookAppId,
            clientSecret: secret.secretValue.toString(),
            scopes: ['email'],
            userPool,
            attributeMapping: {
                email: cognito.ProviderAttribute.FACEBOOK_EMAIL,
                familyName: cognito.ProviderAttribute.FACEBOOK_LAST_NAME,
                givenName: cognito.ProviderAttribute.FACEBOOK_FIRST_NAME
            }
        });

        // Configure the user pool client application 
        const userPoolClient = new cognito.UserPoolClient(this, 'CognitoAppClient', {
            userPool,
            authFlows: {
                userPassword: true
            },
            oAuth: {
                flows: {
                    authorizationCodeGrant: true
                },
                scopes: [
                    cognito.OAuthScope.PHONE,
                    cognito.OAuthScope.EMAIL,
                    cognito.OAuthScope.PROFILE,
                    cognito.OAuthScope.OPENID
                ],
                callbackUrls: [redirectUri]
                // TODO - What about logoutUrls?
            },
            generateSecret: false,
            userPoolClientName: 'Web',
            supportedIdentityProviders: [cognito.UserPoolClientIdentityProvider.FACEBOOK]
        });

        // Output the User Pool App Client ID
        const userPoolClientOut = new cdk.CfnOutput(this, 'CognitoIDPUserPoolClientOut', {
            value: userPoolClient.userPoolClientId,
            exportName: 'CognitoIDPUserPoolClientId'
        });

        // Make sure the user pool client is created after the IDP
        userPoolClient.node.addDependency(idp);

        // Our cognito domain name
        const cognitoDomainPrefix =
            `${props.webDomainName}`.toLowerCase().replace(/[.]/g, "-");

        // Add the domain to the user pool
        userPool.addDomain('CognitoDomain', {
            cognitoDomain: {
                domainPrefix: cognitoDomainPrefix,
            },
        });

        // Configure the lambda functions and REST API

        /**
         * This function grants access to resources to our lambda functions.
         */
        const g = (f: lambda.Function) => {

            // someBucket.grantReadWrite(f);

            const tables = [userTable];

            for (const table of tables) {
                table.grantReadWriteData(f);

                // Give permissions to indexes manually
                f.role?.addToPrincipalPolicy(new iam.PolicyStatement({
                    actions: ['dynamodb:*'],
                    resources: [`${table.tableArn}/index/*`],
                }));
            }
        };

        // Auth
        const handlers: ResourceHandlerProps[] = [];
        handlers.push(new ResourceHandlerProps('decode-verify-jwt', 'get', false, g));

        // Users
        handlers.push(new ResourceHandlerProps('users', 'get', true, g));
        handlers.push(new ResourceHandlerProps('user/{userId}', 'get', true, g));
        handlers.push(new ResourceHandlerProps('user/{userId}', 'delete', true, g));
        handlers.push(new ResourceHandlerProps('user', 'post', true, g));
        handlers.push(new ResourceHandlerProps('userbyusername/{username}', 'get', true, g));

        // The resource handler can't currently handle something like this:
        //
        // thing/{thingId}/otherThing/{otherId}
        //
        // If you need that, do:
        //
        // thing/{thingId}?otherThing=otherId

        // Create the REST API with an L3 construct included in this example repo.
        // (See cognito-rest-api.ts)
        const api = new CognitoRestApi(this, this.stackName, {
            domainName: props.apiDomainName,
            certificateArn: props.apiCertificateArn,
            lambdaFunctionDirectory: './dist/lambda',
            userPool,
            cognitoRedirectUri: `https://${props.webDomainName}`,
            cognitoDomainPrefix,
            cognitoAppClientId: userPoolClient.userPoolClientId,
            cognitoRegion: region,
            additionalEnvVars: {
                "USER_TABLE": userTable.tableName
            },
            resourceHandlers: handlers,
            hostedZoneId: props.apiHostedZoneId
        });

        // Static web site created by an L3 construct included in this example repo
        // (See static-site.ts)
        const site = new StaticSite(this, 'StaticSite', {
            domainName: props.webDomainName,
            certificateArn: props.webCertificateArn,
            contentPath: './dist/web',
            hostedZoneId: props.hostedZoneId
        });

        // Create a custom resource that writes out the config file for the web site.
        // (The web site needs deploy-time values, so this fixes some of the chicken 
        // and egg problems with the .env file)
        const onEvent = new lambda.Function(this, 'CreateConfigHandler', {
            runtime: lambda.Runtime.NODEJS_12_X,
            code: lambda.Code.fromAsset('./dist/lambda'),
            handler: `create-config.handler`,
            memorySize: 1536,
            timeout: cdk.Duration.minutes(5),
            description: `${this.stackName} Static Site Config`,
            environment: {
                'S3_BUCKET_NAME': site.getBucketName(),
                'API_DOMAIN': props.apiDomainName,
                'COGNITO_DOMAIN_PREFIX': cognitoDomainPrefix,
                'COGNITO_REGION': region,
                'COGNITO_APP_CLIENT_ID': userPoolClient.userPoolClientId,
                'COGNITO_REDIRECT_URI': props.cognitoRedirectUri,
                'FACEBOOK_APP_ID': props.facebookAppId,
                'FACEBOOK_VERSION': props.facebookApiVersion
            }
        });

        site.grantAccessTo(onEvent);

        // Create a provider
        const provider = new cr.Provider(this, 'ConfigFileProvider', {
            onEventHandler: onEvent
        });

        // Create the custom resource
        const customResource = new cdk.CustomResource(this, 'ConfigFileResource', {
            serviceToken: provider.serviceToken,
            properties: {
                'FORCE_UPDATE': new Date().toISOString()
            }
        });

        // FORCE_UPDATE forces the custom resource to update the config file on each deploy

        // TODO - Can we set the logical id of the custom resource every time the deployment changes?

        customResource.node.addDependency(site.getDeployment());

    }
Example #24
Source File: ServerSideWebsite.ts    From lift with MIT License 4 votes vote down vote up
constructor(
        scope: Construct,
        private readonly id: string,
        readonly configuration: Configuration,
        private readonly provider: AwsProvider
    ) {
        super(scope, id);

        if (configuration.domain !== undefined && configuration.certificate === undefined) {
            throw new ServerlessError(
                `Invalid configuration in 'constructs.${id}.certificate': if a domain is configured, then a certificate ARN must be configured as well.`,
                "LIFT_INVALID_CONSTRUCT_CONFIGURATION"
            );
        }
        if (configuration.errorPage !== undefined && !configuration.errorPage.endsWith(".html")) {
            throw new ServerlessError(
                `Invalid configuration in 'constructs.${id}.errorPage': the custom error page must be a static HTML file. '${configuration.errorPage}' does not end with '.html'.`,
                "LIFT_INVALID_CONSTRUCT_CONFIGURATION"
            );
        }

        const bucket = new Bucket(this, "Assets", {
            // Assets are compiled artifacts, we can clear them on serverless remove
            removalPolicy: RemovalPolicy.DESTROY,
        });

        /**
         * We create custom "Origin Policy" and "Cache Policy" for the backend.
         * "All URL query strings, HTTP headers, and cookies that you include in the cache key (using a cache policy) are automatically included in origin requests. Use the origin request policy to specify the information that you want to include in origin requests, but not include in the cache key."
         * https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/controlling-origin-requests.html
         */
        const backendOriginPolicy = new OriginRequestPolicy(this, "BackendOriginPolicy", {
            originRequestPolicyName: `${this.provider.stackName}-${id}`,
            comment: `Origin request policy for the ${id} website.`,
            cookieBehavior: OriginRequestCookieBehavior.all(),
            queryStringBehavior: OriginRequestQueryStringBehavior.all(),
            headerBehavior: this.headersToForward(),
        });
        const backendCachePolicy = new CachePolicy(this, "BackendCachePolicy", {
            cachePolicyName: `${this.provider.stackName}-${id}`,
            comment: `Cache policy for the ${id} website.`,
            // For the backend we disable all caching by default
            defaultTtl: Duration.seconds(0),
            // Authorization is an exception and must be whitelisted in the Cache Policy
            // This is the reason why we don't use the managed `CachePolicy.CACHING_DISABLED`
            headerBehavior: CacheHeaderBehavior.allowList("Authorization"),
        });

        const apiId =
            configuration.apiGateway === "rest"
                ? this.provider.naming.getRestApiLogicalId()
                : this.provider.naming.getHttpApiLogicalId();
        const apiGatewayDomain = Fn.join(".", [Fn.ref(apiId), `execute-api.${this.provider.region}.amazonaws.com`]);

        // Cast the domains to an array
        this.domains = configuration.domain !== undefined ? flatten([configuration.domain]) : undefined;
        const certificate =
            configuration.certificate !== undefined
                ? acm.Certificate.fromCertificateArn(this, "Certificate", configuration.certificate)
                : undefined;

        this.distribution = new Distribution(this, "CDN", {
            comment: `${provider.stackName} ${id} website CDN`,
            defaultBehavior: {
                // Origins are where CloudFront fetches content
                origin: new HttpOrigin(apiGatewayDomain, {
                    // API Gateway only supports HTTPS
                    protocolPolicy: OriginProtocolPolicy.HTTPS_ONLY,
                }),
                // For a backend app we all all methods
                allowedMethods: AllowedMethods.ALLOW_ALL,
                cachePolicy: backendCachePolicy,
                viewerProtocolPolicy: ViewerProtocolPolicy.REDIRECT_TO_HTTPS,
                // Forward all values (query strings, headers, and cookies) to the backend app
                // See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/using-managed-origin-request-policies.html#managed-origin-request-policies-list
                originRequestPolicy: backendOriginPolicy,
                functionAssociations: [
                    {
                        function: this.createRequestFunction(),
                        eventType: FunctionEventType.VIEWER_REQUEST,
                    },
                ],
            },
            // All the assets paths are created in there
            additionalBehaviors: this.createCacheBehaviors(bucket),
            errorResponses: this.createErrorResponses(),
            // Enable http2 transfer for better performances
            httpVersion: HttpVersion.HTTP2,
            certificate: certificate,
            domainNames: this.domains,
        });

        // CloudFormation outputs
        this.bucketNameOutput = new CfnOutput(this, "AssetsBucketName", {
            description: "Name of the bucket that stores the website assets.",
            value: bucket.bucketName,
        });
        let websiteDomain = this.getMainCustomDomain();
        if (websiteDomain === undefined) {
            // Fallback on the CloudFront domain
            websiteDomain = this.distribution.distributionDomainName;
        }
        this.domainOutput = new CfnOutput(this, "Domain", {
            description: "Website domain name.",
            value: websiteDomain,
        });
        this.cnameOutput = new CfnOutput(this, "CloudFrontCName", {
            description: "CloudFront CNAME.",
            value: this.distribution.distributionDomainName,
        });
        this.distributionIdOutput = new CfnOutput(this, "DistributionId", {
            description: "ID of the CloudFront distribution.",
            value: this.distribution.distributionId,
        });
    }
Example #25
Source File: index.ts    From cloudstructs with Apache License 2.0 4 votes vote down vote up
constructor(scope: Construct, id: string, props: StateMachineCustomResourceProviderProps) {
    super(scope, id);

    const cfnResponseSuccessFn = this.createCfnResponseFn('Success');
    const cfnResponseFailedFn = this.createCfnResponseFn('Failed');

    const role = new iam.Role(this, 'Role', {
      assumedBy: new iam.ServicePrincipal('states.amazonaws.com'),
    });
    role.addToPolicy(new iam.PolicyStatement({
      actions: ['lambda:InvokeFunction'],
      resources: [cfnResponseSuccessFn.functionArn, cfnResponseFailedFn.functionArn],
    }));
    // https://docs.aws.amazon.com/step-functions/latest/dg/stepfunctions-iam.html
    // https://docs.aws.amazon.com/step-functions/latest/dg/concept-create-iam-advanced.html#concept-create-iam-advanced-execution
    role.addToPolicy(new iam.PolicyStatement({
      actions: ['states:StartExecution'],
      resources: [props.stateMachine.stateMachineArn],
    }));
    role.addToPolicy(new iam.PolicyStatement({
      actions: ['states:DescribeExecution', 'states:StopExecution'],
      resources: [Stack.of(this).formatArn({
        service: 'states',
        resource: 'execution',
        arnFormat: ArnFormat.COLON_RESOURCE_NAME,
        resourceName: `${Stack.of(this).splitArn(props.stateMachine.stateMachineArn, ArnFormat.COLON_RESOURCE_NAME).resourceName}*`,
      })],
    }));
    role.addToPolicy(new iam.PolicyStatement({
      actions: ['events:PutTargets', 'events:PutRule', 'events:DescribeRule'],
      resources: [Stack.of(this).formatArn({
        service: 'events',
        resource: 'rule',
        resourceName: 'StepFunctionsGetEventsForStepFunctionsExecutionRule',
      })],
    }));

    const definition = Stack.of(this).toJsonString({
      StartAt: 'StartExecution',
      States: {
        StartExecution: {
          Type: 'Task',
          Resource: 'arn:aws:states:::states:startExecution.sync:2', // with sync:2 the Output is JSON parsed
          Parameters: {
            'Input.$': '$',
            'StateMachineArn': props.stateMachine.stateMachineArn,
          },
          TimeoutSeconds: (props.timeout ?? Duration.minutes(30)).toSeconds(),
          Next: 'CfnResponseSuccess',
          Catch: [{
            ErrorEquals: ['States.ALL'],
            Next: 'CfnResponseFailed',
          }],
        },
        CfnResponseSuccess: {
          Type: 'Task',
          Resource: cfnResponseSuccessFn.functionArn,
          End: true,
        },
        CfnResponseFailed: {
          Type: 'Task',
          Resource: cfnResponseFailedFn.functionArn,
          End: true,
        },
      },
    });

    const stateMachine = new CfnResource(this, 'StateMachine', {
      type: 'AWS::StepFunctions::StateMachine',
      properties: {
        DefinitionString: definition,
        RoleArn: role.roleArn,
      },
    });
    stateMachine.node.addDependency(role);

    const startExecution = new lambda.Function(this, 'StartExecution', {
      code: lambda.Code.fromAsset(path.join(__dirname, 'runtime')),
      handler: 'index.startExecution',
      runtime: lambda.Runtime.NODEJS_14_X,
    });
    startExecution.addToRolePolicy(new iam.PolicyStatement({
      actions: ['states:StartExecution'],
      resources: [stateMachine.ref],
    }));
    startExecution.addEnvironment('STATE_MACHINE_ARN', stateMachine.ref);

    this.serviceToken = startExecution.functionArn;
  }