AWSTemplateFormatVersion: "2010-09-09"
Description: This template deploys the Amazon Rekognition PPE Demo (uksb-1qpqs27gu)
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: nodejs16.x
MemorySize: 128
Timeout: 120
Environment:
Variables:
REGION: !Ref AWS::Region
TOPIC_ARN: !Ref TopicArn
VERSION: "1.1"
Api:
EndpointConfiguration: REGIONAL
Cors:
AllowMethods: "'*'"
AllowHeaders: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
AllowOrigin: "'*'"
Auth:
DefaultAuthorizer: CognitoAuthorizer
Authorizers:
CognitoAuthorizer:
UserPoolArn: !GetAtt CognitoUserPool.Arn
AddDefaultAuthorizerToCorsPreflight: False
GatewayResponses:
DEFAULT_4XX:
ResponseTemplates:
"application/json": '{ "Message": $context.error.messageString }'
ResponseParameters:
Headers:
Access-Control-Allow-Methods: "'*'"
Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
Access-Control-Allow-Origin: "'*'"
DEFAULT_5XX:
ResponseTemplates:
"application/json": '{ "Message": $context.error.messageString }'
ResponseParameters:
Headers:
Access-Control-Allow-Methods: "'*'"
Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
Access-Control-Allow-Origin: "'*'"
BAD_REQUEST_BODY:
StatusCode: 422
ResponseTemplates:
"application/json": '{ "Message": $context.error.messageString }'
ResponseParameters:
Headers:
Access-Control-Allow-Methods: "'*'"
Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
Access-Control-Allow-Origin: "'*'"
BAD_REQUEST_PARAMETERS:
StatusCode: 422
ResponseTemplates:
"application/json": '{ "Message": $context.error.messageString }'
ResponseParameters:
Headers:
Access-Control-Allow-Methods: "'*'"
Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
Access-Control-Allow-Origin: "'*'"
Parameters:
AdminEmail:
Description: Creates a username to be used for Authentication. It needs to be an e-mail address.
Type: String
AllowedPattern: ^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$
ResourcePrefix:
Description: AWS Resources are named based on the value of this parameter. You must customise this if you are launching more than one instance of the stack within the same account.
Type: String
Default: PPEDemo
AllowedPattern: ^[a-zA-Z0-9_]*$
CreateCloudFrontDistribution:
Description: Creates a CloudFront distribution for accessing the web interface of the demo. This must be enabled if S3 Block Public Access is enabled at an account level.
Type: String
Default: "true"
AllowedValues:
- "true"
- "false"
TopicArn:
Description: When an SNS Topic Arn is provided, SNS notifications will be sent for each body part detected. The SNS Topic and the Demo need to be located in the same AWS Region.
Type: String
Default: "false"
Conditions:
WithCloudFront: !Equals [!Ref CreateCloudFrontDistribution, "true"]
WithSNS: !Not [!Equals [!Ref TopicArn, "false"]]
Outputs:
api:
Value: !Sub https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/
Description: PPE Demo API
url:
Value: !If
- WithCloudFront
- !Sub "https://${CloudFrontDistribution.DomainName}"
- !Sub "https://${WebUIBucket.RegionalDomainName}/index.html"
Description: PPE Demo URL
Resources:
SetupRekognitionAndWebUI:
Type: Custom::Setup
Properties:
ServiceToken: !GetAtt LambdaSetup.Arn
Region: !Ref AWS::Region
WebUIBucket:
Type: AWS::S3::Bucket
Properties:
VersioningConfiguration:
Status: Enabled
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
CorsConfiguration:
CorsRules:
- AllowedHeaders: ["*"]
AllowedMethods: [GET]
AllowedOrigins: ["*"]
Id: RekogCorsRule
MaxAge: 3600
WebUIBucketReadPolicy:
Type: AWS::S3::BucketPolicy
Condition: WithCloudFront
Properties:
Bucket: !Ref WebUIBucket
PolicyDocument:
Statement:
- Action: s3:GetObject
Effect: Allow
Resource: !Sub arn:aws:s3:::${WebUIBucket}/*
Principal:
CanonicalUser: !GetAtt CloudFrontOriginAccessIdentity.S3CanonicalUserId
CognitoIdentityPool:
Type: AWS::Cognito::IdentityPool
Properties:
IdentityPoolName: !Sub RekogIdentityPool${ResourcePrefix}
AllowUnauthenticatedIdentities: false
CognitoIdentityProviders:
- ClientId: !Ref CognitoUserPoolClient
ProviderName: !GetAtt CognitoUserPool.ProviderName
CognitoIdentityPoolRole:
Type: AWS::Cognito::IdentityPoolRoleAttachment
Properties:
IdentityPoolId: !Ref CognitoIdentityPool
Roles:
authenticated: !GetAtt ApiGatewayInvokeRole.Arn
unauthenticated: !GetAtt ApiGatewayInvokeRole.Arn
CognitoUserPool:
Type: AWS::Cognito::UserPool
Properties:
UserPoolName: !Sub ${ResourcePrefix}RekogUsersPool
AdminCreateUserConfig:
AllowAdminCreateUserOnly: true
InviteMessageTemplate:
EmailMessage: !Sub
- 'Your Amazon Rekognition PPE Demo username is {username} and the temporary password is {####}
Click here to access the web interface: ${UIUrl}'
- {
UIUrl:
!If [
WithCloudFront,
!Sub "https://${CloudFrontDistribution.DomainName}",
!Sub "https://${WebUIBucket.RegionalDomainName}/index.html",
],
}
EmailSubject: "Your temporary password for Amazon Rekognition PPE Demo"
SMSMessage: "Your Amazon Rekognition PPE Demo username is {username} and the temporary password is {####}"
AutoVerifiedAttributes:
- email
Policies:
PasswordPolicy:
MinimumLength: 8
RequireLowercase: false
RequireNumbers: false
RequireSymbols: false
RequireUppercase: false
CognitoUserPoolClient:
Type: AWS::Cognito::UserPoolClient
Properties:
UserPoolId: !Ref CognitoUserPool
ClientName: !Sub ${ResourcePrefix}RekogUsersPoolClient
GenerateSecret: false
RefreshTokenValidity: 1
CognitoUserPoolUser:
Type: AWS::Cognito::UserPoolUser
DependsOn: SetupRekognitionAndWebUI
Properties:
Username: !Ref AdminEmail
UserPoolId: !Ref CognitoUserPool
DesiredDeliveryMediums:
- EMAIL
UserAttributes:
- Name: email
Value: !Ref AdminEmail
- Name: email_verified
Value: "true"
ApiGatewayInvokeRole:
Type: AWS::IAM::Role
Properties:
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonAPIGatewayInvokeFullAccess
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Principal:
Federated:
- cognito-identity.amazonaws.com
Action: sts:AssumeRoleWithWebIdentity
Condition:
StringEquals:
"cognito-identity.amazonaws.com:aud": !Ref CognitoIdentityPool
Path: "/"
Policies:
- PolicyName: WebServiceExecutionPolicy
PolicyDocument:
Version: "2012-10-17"
Statement:
- Effect: Allow
Action: rekognition:DetectProtectiveEquipment
Resource: "*"
# Lambdas
ProcessImageFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.processHandler
CodeUri: ../backend/functions/detect/
Events:
Get:
Type: Api
Properties:
Path: /process
Method: post
Policies:
- RekognitionDetectOnlyPolicy: {}
- Version: "2012-10-17"
Statement:
- Effect: Allow
Action:
- rekognition:DetectProtectiveEquipment
Resource: "*"
- !If
- WithSNS
- Effect: Allow
Resource: !Ref TopicArn
Action: sns:Publish
- !Ref AWS::NoValue
LambdaSetup:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
CodeUri: ../backend/functions/setup/
Description: Custom Lambda resource for the PPE Demo Cloudformation Stack
Environment:
Variables:
API_GATEWAY: !Sub https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/
COGNITO_IDENTITY_POOL: !Ref CognitoIdentityPool
COGNITO_USERPOOL_ID: !Ref CognitoUserPool
COGNITO_USERPOOLCLIENT_ID: !Ref CognitoUserPoolClient
COLLECTION_ID: !Ref ResourcePrefix
CREATE_CLOUDFRONT_DISTRIBUTION: !Ref CreateCloudFrontDistribution
FROM_BUCKET: !Sub solution-builders-${AWS::Region}
TO_BUCKET: !Ref WebUIBucket
Timeout: 900
Policies:
- Statement:
- Effect: Allow
Action:
- s3:PutObject
- s3:PutObjectAcl
- s3:DeleteObject
- s3:ListBucket
Resource:
- !Sub arn:aws:s3:::${WebUIBucket}
- !Sub arn:aws:s3:::${WebUIBucket}/*
- Effect: Allow
Action: s3:GetObject
Resource: !Sub arn:aws:s3:::solution-builders-${AWS::Region}/*
CloudFrontOriginAccessIdentity:
Type: AWS::CloudFront::CloudFrontOriginAccessIdentity
Condition: WithCloudFront
Properties:
CloudFrontOriginAccessIdentityConfig:
Comment: !Ref WebUIBucket
CloudFrontDistribution:
Type: AWS::CloudFront::Distribution
Condition: WithCloudFront
Properties:
DistributionConfig:
Origins:
- DomainName: !GetAtt WebUIBucket.RegionalDomainName
Id: !Sub myS3Origin-${ResourcePrefix}
S3OriginConfig:
OriginAccessIdentity: !Sub origin-access-identity/cloudfront/${CloudFrontOriginAccessIdentity}
Enabled: true
HttpVersion: http2
Comment: The Distribution for the Rekognition Meter Web UI
DefaultRootObject: index.html
DefaultCacheBehavior:
AllowedMethods:
- HEAD
- GET
- OPTIONS
TargetOriginId: !Sub myS3Origin-${ResourcePrefix}
ForwardedValues:
QueryString: false
Cookies:
Forward: none
ViewerProtocolPolicy: redirect-to-https
PriceClass: PriceClass_All
ViewerCertificate:
CloudFrontDefaultCertificate: true