@aws-amplify/amplify-category-predictions
Version:
amplify-cli predictions plugin
834 lines • 34.9 kB
JavaScript
const generateStorageCFNForLambda = (storageCFNFile, functionName, prefixForAdminTrigger) => {
storageCFNFile.Parameters[`function${functionName}Arn`] = {
Type: 'String',
Default: `function${functionName}Arn`,
};
storageCFNFile.Parameters[`function${functionName}Name`] = {
Type: 'String',
Default: `function${functionName}Name`,
};
storageCFNFile.Parameters[`function${functionName}LambdaExecutionRole`] = {
Type: 'String',
Default: `function${functionName}LambdaExecutionRole`,
};
storageCFNFile.Parameters.triggerFunction = {
Type: 'String',
};
storageCFNFile.Parameters.adminTriggerFunction = {
Type: 'String',
};
storageCFNFile.Resources.S3Bucket.DependsOn = ['AdminTriggerPermissions'];
storageCFNFile.Resources.S3Bucket.Properties.NotificationConfiguration = {
LambdaConfigurations: [
{
Event: 's3:ObjectCreated:*',
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: prefixForAdminTrigger,
},
],
},
},
Function: {
Ref: `function${functionName}Arn`,
},
},
{
Event: 's3:ObjectRemoved:*',
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: prefixForAdminTrigger,
},
],
},
},
Function: {
Ref: `function${functionName}Arn`,
},
},
],
};
storageCFNFile.Resources.AdminTriggerPermissions = {
Type: 'AWS::Lambda::Permission',
Properties: {
Action: 'lambda:InvokeFunction',
FunctionName: {
Ref: `function${functionName}Name`,
},
Principal: 's3.amazonaws.com',
SourceAccount: {
Ref: 'AWS::AccountId',
},
SourceArn: {
'Fn::Join': [
'',
[
'arn:aws:s3:::',
{
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'bucketName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'bucketName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
],
],
},
},
};
storageCFNFile.Resources.S3TriggerBucketPolicy = {
Type: 'AWS::IAM::Policy',
DependsOn: ['S3Bucket'],
Properties: {
PolicyName: 's3-trigger-lambda-execution-policy',
Roles: [
{
Ref: `function${functionName}LambdaExecutionRole`,
},
],
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['s3:PutObject', 's3:GetObject', 's3:ListBucket', 's3:DeleteObject'],
Resource: [
{
'Fn::Join': [
'',
[
'arn:aws:s3:::',
{
Ref: 'S3Bucket',
},
'/*',
],
],
},
],
},
],
},
},
};
return storageCFNFile;
};
const generateStorageCFNForAdditionalLambda = (storageCFNFile, functionName, prefixForAdminTrigger) => {
storageCFNFile.Parameters[`function${functionName}Arn`] = {
Type: 'String',
Default: `function${functionName}Arn`,
};
storageCFNFile.Parameters[`function${functionName}Name`] = {
Type: 'String',
Default: `function${functionName}Name`,
};
storageCFNFile.Parameters[`function${functionName}LambdaExecutionRole`] = {
Type: 'String',
Default: `function${functionName}LambdaExecutionRole`,
};
storageCFNFile.Parameters.triggerFunction = {
Type: 'String',
};
storageCFNFile.Parameters.adminTriggerFunction = {
Type: 'String',
};
storageCFNFile.Resources.S3Bucket.DependsOn.push('AdminTriggerPermissions');
const lambdaConfigurations = [];
storageCFNFile.Resources.S3Bucket.Properties.NotificationConfiguration.LambdaConfigurations.forEach((triggers) => {
if (!triggers.Filter) {
lambdaConfigurations.push(addObjectKeys(triggers, {
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: {
'Fn::Join': [
'',
[
'protected/',
{
Ref: 'AWS::Region',
},
],
],
},
},
],
},
},
}));
lambdaConfigurations.push(addObjectKeys(triggers, {
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: {
'Fn::Join': [
'',
[
'private/',
{
Ref: 'AWS::Region',
},
],
],
},
},
],
},
},
}));
lambdaConfigurations.push(addObjectKeys(triggers, {
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: {
'Fn::Join': [
'',
[
'public/',
{
Ref: 'AWS::Region',
},
],
],
},
},
],
},
},
}));
}
else {
lambdaConfigurations.push(triggers);
}
});
lambdaConfigurations.push({
Event: 's3:ObjectCreated:*',
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: prefixForAdminTrigger,
},
],
},
},
Function: {
Ref: `function${functionName}Arn`,
},
}, {
Event: 's3:ObjectRemoved:*',
Filter: {
S3Key: {
Rules: [
{
Name: 'prefix',
Value: prefixForAdminTrigger,
},
],
},
},
Function: {
Ref: `function${functionName}Arn`,
},
});
storageCFNFile.Resources.S3Bucket.Properties.NotificationConfiguration.LambdaConfigurations = lambdaConfigurations;
storageCFNFile.Resources.AdminTriggerPermissions = {
Type: 'AWS::Lambda::Permission',
Properties: {
Action: 'lambda:InvokeFunction',
FunctionName: {
Ref: `function${functionName}Name`,
},
Principal: 's3.amazonaws.com',
SourceAccount: {
Ref: 'AWS::AccountId',
},
SourceArn: {
'Fn::Join': [
'',
[
'arn:aws:s3:::',
{
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'bucketName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'bucketName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
],
],
},
},
};
storageCFNFile.Resources.S3TriggerBucketPolicy.Properties.Roles.push({
Ref: `function${functionName}LambdaExecutionRole`,
});
return storageCFNFile;
};
const generateLambdaAccessForRekognition = (identifyCFNFile, functionName, s3ResourceName) => {
identifyCFNFile.Parameters[`function${functionName}Arn`] = {
Type: 'String',
Default: `function${functionName}Arn`,
};
identifyCFNFile.Parameters[`function${functionName}Name`] = {
Type: 'String',
Default: `function${functionName}Name`,
};
identifyCFNFile.Parameters[`function${functionName}LambdaExecutionRole`] = {
Type: 'String',
Default: `function${functionName}LambdaExecutionRole`,
};
identifyCFNFile.Parameters[`storage${s3ResourceName}BucketName`] = {
Type: 'String',
Default: `storage${s3ResourceName}BucketName`,
};
identifyCFNFile.Outputs.collectionId = {
Value: {
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'resourceName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'resourceName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
};
identifyCFNFile.Resources.LambdaRekognitionAccessPolicy = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'amplify-lambda-execution-rekognition-policy',
Roles: [
{
Ref: `function${functionName}LambdaExecutionRole`,
},
],
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['rekognition:ListFaces', 'rekognition:IndexFaces', 'rekognition:DeleteFaces'],
Resource: [
{
'Fn::Join': [
'',
[
'arn:aws:rekognition:',
{
Ref: 'AWS::Region',
},
':',
{
Ref: 'AWS::AccountId',
},
':',
'collection/',
{
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'resourceName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'resourceName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
],
],
},
],
},
],
},
},
};
identifyCFNFile.Resources.CollectionCreationFunction = {
Type: 'AWS::Lambda::Function',
Properties: {
Code: {
ZipFile: {
'Fn::Join': [
'\n',
[
"const response = require('cfn-response');",
"const { RekognitionClient, CreateCollectionCommand, DeleteCollectionCommand, ListCollectionsCommand } = require('@aws-sdk/client-rekognition');",
"const { S3Client, PutObjectCommand } = require('@aws-sdk/client-s3');",
'let responseData = {};',
'exports.handler = function(event, context) {',
" // Don't return promise, response.send() marks context as done internally",
' const ignoredPromise = handleEvent(event, context)',
'};',
'async function handleEvent(event, context) {',
' try {',
" if (event.RequestType === 'Delete') {",
' try {',
' let params = {',
' CollectionId: event.ResourceProperties.collectionId',
' };',
' const rekognition = new RekognitionClient({ region: event.ResourceProperties.region });',
' const res = await rekognition.send(new DeleteCollectionCommand(params));',
' console.log("delete" + res);',
' console.log("response data" + JSON.stringify(res));',
' response.send(event, context, response.SUCCESS, res);',
' } catch(err) {',
" if (err.name !== 'NotFoundException') {",
' response.send(event, context, response.FAILED);',
' } else {',
' response.send(event, context, response.SUCCESS);',
' }',
' }',
" } else if (event.RequestType === 'Update' || event.RequestType === 'Create') {",
' const collectionId = event.ResourceProperties.collectionId;',
' const params = {',
' CollectionId: collectionId',
' };',
' const rekognition = new RekognitionClient({ region: event.ResourceProperties.region });',
' const res = await rekognition.send(new ListCollectionsCommand({}));',
' let CollectionIds = res.CollectionIds ?? [];',
' console.log("CollectionIds" + CollectionIds);',
' if(CollectionIds.indexOf(collectionId) !== -1) {',
' response.send(event, context, response.SUCCESS, responseData);',
' } else {',
' responseData = await rekognition.send(new CreateCollectionCommand(params));',
' console.log("responseData" + JSON.stringify(responseData)); console.log(collectionId);',
' let s3 = new S3Client({});',
' let s3params = {',
' Bucket: event.ResourceProperties.bucketName,',
' Key: "protected/predictions/index-faces/admin/"',
' };',
' const s3Res = await s3.send(new PutObjectCommand(s3params));',
' if (s3Res.ETag) {',
' response.send(event, context, response.SUCCESS, responseData);',
' }',
' else {',
' response.send(event, context, response.FAILED, s3Res);',
' }',
' }',
' }',
' } catch(err) {',
' console.log(err.stack);',
' responseData = {Error: err};',
' response.send(event, context, response.FAILED, responseData);',
' }',
'}',
],
],
},
},
Handler: 'index.handler',
Runtime: 'nodejs22.x',
Timeout: 300,
Role: {
'Fn::GetAtt': ['CollectionsLambdaExecutionRole', 'Arn'],
},
},
};
identifyCFNFile.Resources.CollectionFunctionOutputs = {
Type: 'Custom::LambdaCallout',
Properties: {
ServiceToken: {
'Fn::GetAtt': ['CollectionCreationFunction', 'Arn'],
},
region: {
Ref: 'AWS::Region',
},
collectionId: {
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'resourceName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'resourceName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
bucketName: {
Ref: `storage${s3ResourceName}BucketName`,
},
},
};
identifyCFNFile.Resources.LambdaCloudWatchPolicy = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'CollectionsLambdaCloudWatchPolicy',
Roles: [
{
Ref: 'CollectionsLambdaExecutionRole',
},
],
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'],
Resource: {
'Fn::Sub': [
'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${lambdaName}:log-stream:*',
{
lambdaName: {
Ref: 'CollectionCreationFunction',
},
},
],
},
},
],
},
},
};
identifyCFNFile.Resources.CollectionsLambdaExecutionRole = {
Type: 'AWS::IAM::Role',
Properties: {
RoleName: {
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'resourceName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'resourceName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
AssumeRolePolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Principal: {
Service: ['lambda.amazonaws.com'],
},
Action: ['sts:AssumeRole'],
},
],
},
Policies: [
{
PolicyName: {
Ref: 'identifyPolicyName',
},
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['rekognition:CreateCollection', 'rekognition:DeleteCollection', 's3:PutObject'],
Resource: [
{
'Fn::Join': [
'',
[
'arn:aws:rekognition:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':',
'collection/',
{
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'resourceName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'resourceName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
],
],
},
{
'Fn::Join': [
'',
[
'arn:aws:s3:::',
{
Ref: `storage${s3ResourceName}BucketName`,
},
'/*',
],
],
},
],
},
{
Effect: 'Allow',
Action: ['rekognition:ListCollections'],
Resource: '*',
},
],
},
},
],
},
};
return identifyCFNFile;
};
const generateStorageAccessForRekognition = (identifyCFNFile, s3ResourceName, prefixForAdminTrigger) => {
identifyCFNFile.Parameters[`storage${s3ResourceName}BucketName`] = {
Type: 'String',
Default: `storage${s3ResourceName}BucketName`,
};
identifyCFNFile.Resources.S3AuthPredicitionsAdminProtectedPolicy = {
Condition: 'CreateAdminAuthProtected',
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'S3RekognitionAuthAdminFolderAccess',
Roles: [
{
Ref: 'authRoleName',
},
],
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['s3:DeleteObject', 's3:GetObject', 's3:PutObject'],
Resource: [
{
'Fn::Join': [
'',
[
'arn:aws:s3:::',
{
Ref: `storage${s3ResourceName}BucketName`,
},
`/${prefixForAdminTrigger}`,
'${cognito-identity.amazonaws.com:sub}/*',
],
],
},
],
},
],
},
},
};
identifyCFNFile.Resources.IdentifyEntitiesSearchFacesPolicy = {
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: {
'Fn::Join': ['', [{ Ref: 'identifyPolicyName' }, '-', 'searchFaces']],
},
Roles: {
'Fn::If': ['AuthGuestRoleAccess', [{ Ref: 'authRoleName' }, { Ref: 'unauthRoleName' }], [{ Ref: 'authRoleName' }]],
},
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['rekognition:SearchFacesByImage'],
Resource: [
{
'Fn::Join': [
'',
[
'arn:aws:rekognition:',
{ Ref: 'AWS::Region' },
':',
{ Ref: 'AWS::AccountId' },
':',
'collection/',
{
'Fn::If': [
'ShouldNotCreateEnvResources',
{
Ref: 'resourceName',
},
{
'Fn::Join': [
'',
[
{
Ref: 'resourceName',
},
'-',
{
Ref: 'env',
},
],
],
},
],
},
],
],
},
],
},
],
},
},
};
identifyCFNFile.Resources.S3GuestPredicitionsAdminPublicPolicy = {
Condition: 'CreateAdminGuestProtected',
Type: 'AWS::IAM::Policy',
Properties: {
PolicyName: 'S3RekognitionGuestAdminFolderAccess',
Roles: [
{
Ref: 'unauthRoleName',
},
],
PolicyDocument: {
Version: '2012-10-17',
Statement: [
{
Effect: 'Allow',
Action: ['s3:DeleteObject', 's3:GetObject', 's3:PutObject'],
Resource: [
{
'Fn::Join': [
'',
[
'arn:aws:s3:::',
{
Ref: `storage${s3ResourceName}BucketName`,
},
`/${prefixForAdminTrigger}`,
'${cognito-identity.amazonaws.com:sub}/*',
],
],
},
],
},
],
},
},
};
return identifyCFNFile;
};
const addObjectKeys = (original, additional) => ({ ...original, ...additional });
const addTextractPolicies = (identifyCFNFile) => {
identifyCFNFile.Resources.IdentifyTextPolicy.Properties.PolicyDocument.Statement[0].Action = [
'rekognition:DetectText',
'rekognition:DetectLabel',
'textract:AnalyzeDocument',
'textract:DetectDocumentText',
'textract:GetDocumentAnalysis',
'textract:StartDocumentTextDetection',
];
return JSON.stringify(identifyCFNFile, null, 4);
};
const removeTextractPolicies = (identifyCFNFile) => {
identifyCFNFile.Resources.IdentifyTextPolicy.Properties.PolicyDocument.Statement[0].Action = [
'rekognition:DetectText',
'rekognition:DetectLabel',
];
return JSON.stringify(identifyCFNFile, null, 4);
};
module.exports = {
generateStorageAccessForRekognition,
generateLambdaAccessForRekognition,
generateStorageCFNForAdditionalLambda,
generateStorageCFNForLambda,
addTextractPolicies,
removeTextractPolicies,
};
//# sourceMappingURL=identifyCFNGenerate.js.map