in source/cdk-infrastructure/lib/back-end/external-integrations/external-integrations-construct.ts [32:164]
constructor(scope: Construct, id: string, props: ExternalIntegrationsProps) {
super(scope, id);
const sourceCodeBucket = Bucket.fromBucketName(this, 'sourceCodeBucket', props.sourceCodeBucketName);
this.anomalyDetectionBucketParameter = new CfnParameter(this, 'AnomalyDetectionBucketParameter', {
description: '(Optional) The name of the Amazon S3 bucket which will contain anomaly detection files',
default: '',
maxLength: 63,
allowedPattern: '^[a-z0-9.-]*$'
});
this.anomalyDetectionBucketParameter.overrideLogicalId('AnomalyDetectionBucketParameter');
const anomalyDetectionBucketCondition = new CfnCondition(this, 'AnomalyDetectionBucketCondition', {
expression: Fn.conditionNot(Fn.conditionEquals(this.anomalyDetectionBucketParameter.valueAsString, ''))
});
const anomalyDetectionBucket = Bucket.fromBucketName(this, 'anomalyDetectionBucket', this.anomalyDetectionBucketParameter.valueAsString);
const externalIntegrationsFnRole = new Role(this, 'ExternalIntegrationsLambdaRole', {
assumedBy: new ServicePrincipal('lambda.amazonaws.com'),
path: '/',
inlinePolicies: {
'DynamoDbPolicy': new PolicyDocument({
statements: [
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['dynamodb:GetItem'],
resources: [props.dataHierarchyTable.tableArn]
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['dynamodb:Query'],
resources: [`${props.dataHierarchyTable.tableArn}/index/ByTypeAndParent-index`]
}),
new PolicyStatement({
effect: Effect.ALLOW,
actions: ['dynamodb:Query'],
resources: [`${props.issuesTable.tableArn}/index/ByDeviceEvent-index`]
})
]
}),
'CloudWatchLogsPolicy': new PolicyDocument({
statements: [new PolicyStatement({
effect: Effect.ALLOW,
actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
resources: [Stack.of(this).formatArn({ service: 'logs', resource: 'log-group', resourceName: '/aws/lambda/*', arnFormat: ArnFormat.COLON_RESOURCE_NAME })]
})]
}),
'IotPolicy': new PolicyDocument({
statements: [new PolicyStatement({
effect: Effect.ALLOW,
actions: ['iot:Publish'],
resources: [Stack.of(this).formatArn({ service: 'iot', resource: 'topic', resourceName: IotConstants.ISSUES_TOPIC, arnFormat: ArnFormat.SLASH_RESOURCE_NAME })]
})]
})
}
});
(new Policy(this, 'AnomalyDetectionBucketPolicy', {
document: new PolicyDocument({
statements: [new PolicyStatement({
effect: Effect.ALLOW,
actions: ['s3:GetObject'],
resources: [anomalyDetectionBucket.arnForObjects('*')]
})]
}),
roles: [externalIntegrationsFnRole]
}).node.defaultChild as CfnResource).cfnOptions.condition = anomalyDetectionBucketCondition;
const externalIntegrationsIotToLambda = new IotToLambda(this, 'ExternalIntegrationsIotToLambda', {
iotTopicRuleProps: {
topicRulePayload: {
description: 'Messages from devices are sent to this topic for processing',
sql: `SELECT * FROM '${IotConstants.DEVICES_TOPIC}'`,
actions: []
}
},
lambdaFunctionProps: {
runtime: Runtime.NODEJS_14_X,
handler: 'external-integrations-handler/index.handler',
timeout: Duration.seconds(60),
description: `${props.solutionDisplayName} (${props.solutionVersion}): Handles issues created by external integrations`,
code: Code.fromBucket(sourceCodeBucket, [props.sourceCodeKeyPrefix, 'external-integrations-handler.zip'].join('/')),
role: externalIntegrationsFnRole,
environment: {
LOGGING_LEVEL: props.loggingLevel,
DATA_HIERARCHY_TABLE: props.dataHierarchyTable.tableName,
ISSUES_TABLE: props.issuesTable.tableName,
IOT_ENDPOINT_ADDRESS: props.iotEndpointAddress,
SOLUTION_ID: props.solutionId,
SOLUTION_VERSION: props.solutionVersion,
ISSUES_TOPIC: IotConstants.ISSUES_TOPIC,
IOT_MESSAGE_NAME_DELIMITER: '/'
}
}
});
new LambdaPermission(this, 'ExternalIntegrationsLambdaPermission', {
action: 'lambda:InvokeFunction',
principal: 's3.amazonaws.com',
sourceArn: anomalyDetectionBucket.bucketArn,
sourceAccount: Aws.ACCOUNT_ID,
functionName: externalIntegrationsIotToLambda.lambdaFunction.functionName
}).cfnOptions.condition = anomalyDetectionBucketCondition;
const solutionHelperPutBucketNotificationPolicy = new Policy(this, 'SolutionHelperPutBucketNotificationPolicy', {
document: new PolicyDocument({
statements: [new PolicyStatement({
actions: ['s3:GetBucketNotification', 's3:PutBucketNotification'],
effect: Effect.ALLOW,
resources: [anomalyDetectionBucket.bucketArn]
})]
}),
roles: [props.solutionHelperLambda.role!]
});
(solutionHelperPutBucketNotificationPolicy.node.defaultChild as CfnResource).cfnOptions.condition = anomalyDetectionBucketCondition;
const configureDetectedAnomaliesBucketNotificationCustomResourceProps: IConfigureBucketNotificationRequestProps = {
Action: CustomResourceActions.CONFIGURE_BUCKET_NOTIFICATION,
BucketName: anomalyDetectionBucket.bucketName,
FunctionArn: externalIntegrationsIotToLambda.lambdaFunction.functionArn
};
const configureBucketNotificationCustomResource = new CustomResource(this, 'ConfigureBucketNotificationCustomResource', {
serviceToken: props.solutionHelperLambda.functionArn,
properties: configureDetectedAnomaliesBucketNotificationCustomResourceProps
});
(configureBucketNotificationCustomResource.node.defaultChild as CfnResource).addDependsOn(solutionHelperPutBucketNotificationPolicy.node.defaultChild as CfnResource);
(configureBucketNotificationCustomResource.node.defaultChild as CfnResource).addDependsOn(externalIntegrationsIotToLambda.lambdaFunction.node.defaultChild as CfnResource);
(configureBucketNotificationCustomResource.node.defaultChild as CfnResource).cfnOptions.condition = anomalyDetectionBucketCondition;
}