Project Doorbell: infrastructure setup

Project Doorbell: infrastructure setup

Project Doorbell is an idea that I got to know the managed AI AWS services and to keep going to write some code in Rust.

Working with people is more fun but require a bit of organization.

Project doorbell will be part of a series to document my steps to deliver a working proof of concept.

Smart doorbell

Smart doorbells include a camera, microphone and speaker to allow for a two-way conversation between the doorbell and its smartphone app.

This project is concentrated on the backend side of communication. Therefore, I will not consider the hardware and the mobile app.

I will assume they exist to facilitate this PoC.

For example, I will use Amazon API Gateway with WebSocket because they are bidirectional, and this behaviour enables me to interact between the device and the AWS services.

Probably the best fit is AWS IoT because it connects IoT devices to other devices and AWS cloud services. I am unfamiliar with this service and the MQTT over WSS protocol, so I deliberately decided to use Amazon API Gateway with WebSocket. I will try to use AWS IoT later on for future development.

How it works

The doorbell connects to the WebSocket API by sending a WebSocket request. If the request succeeds, an event is emitted.

This event will trigger a Lambda function that will generate a presigned URL, and thanks to the WebSocket, will send it to the doorbell. Presigned URL is needed because all objects, by default, are private. By creating a presigned URL, I can grant time-limited permission to upload the photo taken by the doorbell.

Once the upload is completed, an event is emitted, and it will execute AWS Step Functions, where the photo taken by the doorbell is compared against a set of source photos of the owner(s). In this PoC, I will assume only one owner.

If the photo match, a six-digit code will be sent to the owner device and with this code entry, the owner can access the property.

If the photo does not match, we have two options:

  • leave the doorbell ring
  • send the photo to the owner device, where it is possible to review it and decide on some action.

GitHub

I am using GitHub, and there is no need for introduction, but just in case here, you find a short and fun lab.

Because this time I have a collaborator, I need to share my ideas and what I have in my mind, so I have found the excuse to use the issue sections and the dashboard.

issues.png

dashboard.png

You are free to tag along if you want. I will try my best to involve you or satisfy your requests.

The repository is available on GitHub.

Infrastructure

The current solution is composed mainly by:

  • Amazon API Gateway with WebSocket
  • AWS S3
  • AWS Step Functions
  • Lambda functions

I will show the relative new configuration to connect AWS S3 with AWS Step Function by Amazon EventBridge.

AWS S3

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: S3 Bucket to store the photos

Resources:
##########################################################################
#   S3                                                                  #
##########################################################################
  SourceBucket:
    Type: AWS::S3::Bucket
    Properties:
      NotificationConfiguration:
        EventBridgeConfiguration:
          EventBridgeEnabled: True
      LifecycleConfiguration:
        Rules:
          - Id: DeleteLifeCyclePolicy
            Status: Enabled
            ExpirationInDays: 1
##########################################################################
#   BUCKET POLICY                                                        #
##########################################################################
  SourceBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref SourceBucket
      PolicyDocument:
        Statement:
        - Action: s3:*
          Effect: Deny
          Principal: "*"
          Resource:
          - !Sub "arn:aws:s3:::${SourceBucket}/*"
          - !Sub "arn:aws:s3:::${SourceBucket}"
          Condition:
            Bool:
              aws:SecureTransport: false

Outputs:
  SourceBucketName:
    Value: !Ref SourceBucket
    Export:
      Name: SourceBucket
  SourceBucketArn:
      Value:
        Fn::GetAtt:
          - SourceBucket
          - Arn
      Export:
        Name: SourceBucketArn

I want to highlight the following part.

NotificationConfiguration:
  EventBridgeConfiguration:
    EventBridgeEnabled: True

NotificationConfiguration describes the notification configuration for an Amazon S3 bucket. Amazon S3 can send events to Amazon EventBridge whenever certain events happen in your bucket.

Under SourceBucketName, we export the bucket name, which is how to share information between stacks. Then, other stacks in the same AWS account and region can import the exported values.

Outputs:
  SourceBucketName:
    Value: !Ref SourceBucket
    Export:
      Name: SourceBucket

AWS Step Functions

AWSTemplateFormatVersion: 2010-09-09
Transform: AWS::Serverless-2016-10-31
Description: StepFunctions state machine

Resources:
##########################################################################
#   STEP FUNCTION                                                        #
##########################################################################
  MyStateMachine:
    Type: AWS::Serverless::StateMachine
    Properties:
      DefinitionUri: statemachine/stateMachine.asl.json
      Policies:
        - Version: "2012-10-17"
          Statement:
            - Effect: Allow
              Action:
                - "cloudwatch:*"
                - "logs:*"
                - "rekognition:CompareFaces"
              Resource: "*"
            - Effect: Allow
              Action:
                - "s3:GetObject"
              Resource:
                - !ImportValue SourceBucketArn
      Logging:
        Destinations:
          - CloudWatchLogsLogGroup:
              LogGroupArn: !GetAtt MyStateMachineLogGroup.Arn
        IncludeExecutionData: false
        Level: 'ALL'
      Events:
        StateChange:
          Type: EventBridgeRule
          Properties:
            InputPath: $.detail
            Pattern:
              source:
                - aws.s3
              detail:
                bucket:
                  name: 
                    - !ImportValue SourceBucket
                reason:
                  - PutObject

##########################################################################
#  STEP FUNCTION LOG GROUP                                               #
##########################################################################
  MyStateMachineLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Join [ "/", [ "stepfunctions", MyStateMachine]]

Outputs:
  MyStateMachine:
    Value: !Ref MyStateMachine
    Description: MyStateMachine Arn

I want to highlight the integration to trigger AWS Step Functions with Amazon EventBridge.

 Events:
        StateChange:
          Type: EventBridgeRule
          Properties:
            InputPath: $.detail
            Pattern:
              source:
                - aws.s3
              detail:
                bucket:
                  name: 
                    - !ImportValue SourceBucket
                reason:
                  - PutObject

When the delivery of events to EventBridge is enabled, Amazon S3 will send all events to EventBridge, and so for my case, I listen only to events for:

  • The bucket where we upload the photo (reference from the output section of the s3 template)
  • PutObject actions

Conclusion

It is an amateur project to play around with. Still, a project board or writing down stories help you organize and prioritize the work, and GitHub allows you easily to add collaboration to your project. Starting with infrastructure as code (IaC) makes things faster by eliminating manual processes and eliminating errors. Additionally, I found it helpful with the principle of least privilege because usually, from the AWS console, I set full access to make it works while writing IaC help me apply the bare minimum permission to perform the task.