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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
/**
* 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 |
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 |
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 |
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 |
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 |
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 |
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 |
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;
}