AWSTemplateFormatVersion: "2010-09-09"
Description: This template deploys the Amazon Rekognition Virtual Proctor (uksb-1qoed5fri)
Transform: AWS::Serverless-2016-10-31
Globals:
Function:
Runtime: nodejs16.x
MemorySize: 128
Timeout: 30
Environment:
Variables:
COLLECTION_ID: !Ref ResourcePrefix
FACES_TABLENAME: !Ref FacesTable
MIN_CONFIDENCE: !Ref MinConfidence
OBJECTS_OF_INTEREST_LABELS: !Join [",", !Ref ObjectsOfInterestLabels]
REGION: !Ref AWS::Region
VERSION: '2.2'
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: "'*'"
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-.]+$
MinConfidence:
Description: Specifies the minimum confidence level for the labels to return
Type: Number
Default: 85
MinValue: 0
MaxValue: 100
ObjectsOfInterestLabels:
Description: Comma-delimited list of labels used to detect Objects of interest
Type: CommaDelimitedList
Default: "Mobile Phone,Cell Phone"
PreBuiltArtefactsBucketOverride:
Description: >
The name of an S3 Bucket containing the built web-ui.
Use this to deploy a modified version of the Virtual Proctor web ui.
The default is to use the Virtual Proctor version from a predefined bucket in the given region (for example solution-builders-us-west-1)
Type: String
Default: "false"
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: VirtualProctor
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"
Conditions:
WithCloudFront: !Equals [!Ref CreateCloudFrontDistribution, "true"]
DefaultPreBuiltArtefactsBucket:
!Equals [!Ref PreBuiltArtefactsBucketOverride, "false"]
Outputs:
api:
Value: !Sub https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/
Description: Virtual Proctor API
url:
Value: !If
- WithCloudFront
- !Sub 'https://${CloudFrontDistribution.DomainName}'
- !Sub 'https://${WebUIBucket.RegionalDomainName}/index.html'
Description: Virtual Proctor 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 Virtual Proctor 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 Virtual Proctor'
SMSMessage: 'Your Amazon Rekognition Virtual Proctor 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
# Lambdas
IndexFaceFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.indexHandler
CodeUri: ../backend/functions/proctor/
Events:
Get:
Type: Api
Properties:
Path: /faces/index
Method: post
Policies:
- DynamoDBWritePolicy:
TableName: !Ref FacesTable
- RekognitionWriteOnlyAccessPolicy:
CollectionId: !Ref ResourcePrefix
ProcessImageFunction:
Type: AWS::Serverless::Function
Properties:
Handler: index.processHandler
CodeUri: ../backend/functions/proctor/
Events:
Get:
Type: Api
Properties:
Path: /process
Method: post
Policies:
- DynamoDBReadPolicy:
TableName: !Ref FacesTable
- RekognitionReadPolicy:
CollectionId: !Ref ResourcePrefix
- RekognitionDetectOnlyPolicy: {}
LambdaSetup:
Type: AWS::Serverless::Function
Properties:
Handler: index.handler
CodeUri: ../backend/functions/setup/
Description: Custom Lambda resource for the Virtual Proctor 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:
!If [
DefaultPreBuiltArtefactsBucket,
!Sub 'solution-builders-${AWS::Region}',
!Ref PreBuiltArtefactsBucketOverride,
]
REGION: !Ref 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:
!If [
DefaultPreBuiltArtefactsBucket,
!Sub 'arn:aws:s3:::solution-builders-${AWS::Region}/*',
!Sub 'arn:aws:s3:::${PreBuiltArtefactsBucketOverride}/*',
]
- Effect: Allow
Action:
- rekognition:CreateCollection
- rekognition:DeleteCollection
Resource: !Sub arn:aws:rekognition:${AWS::Region}:${AWS::AccountId}:collection/${ResourcePrefix}
FacesTable:
Type: AWS::DynamoDB::Table
Properties:
AttributeDefinitions:
-
AttributeName: ExternalImageId
AttributeType: S
KeySchema:
-
AttributeName: ExternalImageId
KeyType: HASH
BillingMode: PAY_PER_REQUEST
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