aws, ai, security, serverless

Serverless KI-gestützte Inhaltsmoderationsdienst

2024-10-31
This post cover image
aws cloud serverless ai security

Diese Datei wurde automatisch von KI ubersetzt, es konnen Fehler auftreten

Vor etwa einem Jahr habe ich einen Blogbeitrag über die Erstellung eines Dateiverwaltungsdienstes veröffentlicht. In diesem Beitrag werden wir diesen Dienst als Grundlage verwenden und ihn um Inhaltsmoderation erweitern. Wir werden GuardDuty und Rekognition zur Unterstützung dieser Aufgabe einsetzen. Wie üblich wird alles serverlos und ereignisgesteuert bleiben.

Zusammenfassung

Um das Gedächtnis aufzufrischen, beginnen wir mit einer kurzen Zusammenfassung.

Der Dienst speichert Dateien in S3 und führt einen Datensatz aller Dateien in einer DynamoDB-Tabelle. Der Systemüberblick sieht wie folgt aus, wobei eine API die Funktionalität für den Benutzer exponiert und die Arbeit anschließend auf serverlose und ereignisgesteuerte Weise ausgeführt wird.

Architekturüberblick für den ursprünglichen Dateiverwaltungsdienst

Der Upload-Ablauf wird durch einen Client eingeleitet, der die API aufruft, wobei eine Lambda-Funktion eine vorunterzeichnete S3-URL erstellt, die der Client zur Upload der Datei verwenden kann. Wir laden die Datei nicht direkt über die API hoch, da Amazon API Gateway eine maximale Payload-Größe von 10 MB hat, was bei der Unterstützung aller Arten von Dateien zu einer Einschränkung werden würde.

Wenn der Client die Datei anschließend in S3 hochlädt, wird ein Ereignis ausgelöst, der Teil unter der gestrichelten Linie im Bild, der einen StepFunction aufruft, der das Dateiverzeichnis aktualisiert.

Upload-Ablauf für den ursprünglichen Dateiverwaltungsdienst

Erweiterte Architektur

In der erweiterten Architektur fügen wir Funktionalität hinzu, um GuardDuty S3-Malware-Scans und Rekognition für die Bildmoderation zu nutzen. GuardDuty wird neue Dateien, die im S3-Bucket ankommen, scannen, den ich Staging nenne, ein Tag wird dem Objekt hinzugefügt und das Scan-Ergebnis wird an den Standard-Event-Bus gesendet. Das Scan-Ergebnis, falls OK, wird einen StepFunction aufrufen, der Rekognition zur Bildmoderation nutzt. Ich habe die gleiche Logik in diesem StepFunction implementiert und füge ein Tag am Objekt hinzu und sende ein Ereignis an einen Event-Bus. Schließlich werden die Dateien entweder in einen Quarantäne- oder einen Langzeit-Speicher-Bucket verschoben.

Jeder Teil der Lösung ist entkoppelt und kann unabhängig laufen, und ein Saga-Muster wird angewendet, um die Logik in die nächste Phase zu überführen.

Erweiterter Überblick mit Inhaltsmoderation

Lassen Sie uns nun etwas tiefer in jeden Teil dieser Lösung eintauchen.

Malware-Scan

Der GuardDuty-Malware-Scan erfordert nicht viel Einrichtungsaufwand. Dies ist eine vollständig verwaltete Funktion in GuardDuty, und das Einzige, was erforderlich ist, ist die Konfiguration. GuardDuty wird dann automatisch neue Objekte erfassen.

Malware-Scan-Ablauf

Um diesen Ablauf zu erreichen, müssen wir nur einen S3MalwareProtectionPlan erstellen und ihm entsprechende Berechtigungen zuweisen. Eine wichtige Sache, die man sich merken sollte: Wenn Sie Ihre Objekte in S3 mit einem Customer Managed Key verschlüsseln, vergessen Sie nicht, GuardDuty Berechtigungen zu geben, um mit diesem Schlüssel zu entschlüsseln.

  S3MalwareProtectionPlan:
    Type: AWS::GuardDuty::MalwareProtectionPlan
    Properties:
      Actions:
        Tagging:
          Status: ENABLED
      ProtectedResource:
        S3Bucket:
          BucketName:
            Fn::ImportValue: !Sub ${CommonInfraStackName}:staging-bucket-name
      Role: !GetAtt S3MalwareProtectionPlanRole.Arn

Bildmoderation

Der Moderationsteil mit Rekognition beinhaltet ein paar weitere Schritte. Ein StepFunction wird durch das Ergebnis des Malware-Scans aufgerufen und ruft Rekognition auf, um das Bild zu moderieren. Dieser StepFunction wird dann das Objekt taggen und das Scan-Ergebnis an den EventBridge benutzerdefinierten Service-Bus senden. Eine wichtige Sache, die man sich merken sollte: Wenn Sie Ihre Objekte in S3 mit einem Customer Managed Key verschlüsseln, vergessen Sie nicht, Berechtigungen zum Entschlüsseln mit diesem Schlüssel zu geben. Rekognition gibt Ihnen einen seltsamen Fehler Unsupported und keinen klaren Fehler, warum es in diesem Fall gescheitert ist.

Bildmoderations-Ablauf

Um diesen Ablauf zu erreichen, müssen wir nur die StateMachine erstellen und die Ereignisse einrichten, bei denen sie aufgerufen werden soll.

  ModerateImageStateMachineStandard:
    Type: AWS::Serverless::StateMachine
    Properties:
      DefinitionUri: StateMachine/moderation.asl.yaml
      DefinitionSubstitutions:
        EventBusName: 
          Fn::ImportValue: !Sub ${CommonInfraStackName}:event-bus-name
      Tracing:
        Enabled: true
      Policies:
        - Statement:
            - Effect: Allow
              Action:
                - logs:*
              Resource: "*"
        - S3FullAccessPolicy:
            BucketName: 
              Fn::ImportValue: !Sub ${CommonInfraStackName}:staging-bucket-name
        - EventBridgePutEventsPolicy:
            EventBusName: 
              Fn::ImportValue: !Sub ${CommonInfraStackName}:event-bus-name
        - RekognitionDetectOnlyPolicy: {}
      Events:
        GuardDutyMalwareScanResult:
          Type: EventBridgeRule
          Properties:
            InputPath: $.detail
            Pattern:
              source:
                - aws.guardduty
              detail-type:
                - GuardDuty Malware Protection Object Scan Result
              detail:
                scanResultDetails:
                  scanResultStatus:
                    - NO_THREATS_FOUND

Die StateMachine-Definition ist ziemlich groß und erfordert etwas Magie. Da Sie keinen Tags zu einem S3-Objekt hinzufügen können, müssen wir zuerst alle vorhandenen Tags abrufen, unseren neuen Tag anhängen und den gesamten Array von Tags auf das Objekt setzen. Dies wäre wahrscheinlich einfacher in einer Lambda-Funktion zu implementieren, aber wo wäre da der Spaß? Intrinsische Funktionen für den Sieg....

Comment: Bilder mit Rekognition moderieren
StartAt: Debug
States:
  Debug:
    Type: Pass
    Next: Get Object Metadata
  Get Object Metadata:
    Type: Task
    Parameters:
      Bucket.$: $.s3ObjectDetails.bucketName
      Key.$: $.s3ObjectDetails.objectKey
    Resource: arn:aws:states:::aws-sdk:s3:headObject
    Next: Get Object Tags
    ResultPath: $.S3MetaData
  Get Object Tags:
    Type: Task
    Parameters:
      Bucket.$: $.s3ObjectDetails.bucketName
      Key.$: $.s3ObjectDetails.objectKey
    Resource: arn:aws:states:::aws-sdk:s3:getObjectTagging
    Next: Is File Supported?
    ResultPath: $.s3Tags
  Is File Supported?:
    Type: Choice
    Choices:
      - Or:
          - Variable: $.S3MetaData.ContentType
            StringMatches: image/png
          - Variable: $.S3MetaData.ContentType
            StringMatches: image/jpeg
        Next: Moderate Image
    Default: File Not Supported
  File Not Supported:
    Type: Pass
    Next: Add FILE_NOT_SUPPORTED to Object Tags Array
    Parameters:
      ContentTypes: []
      ModerationLabels: []
      ModerationModelVersion: "7.0"
      ThreatsFound: "-1"
    ResultPath: $.RekognitionModeration
  Add FILE_NOT_SUPPORTED to Object Tags Array:
    Type: Pass
    ResultPath: $.scanResult
    Parameters:
      status: FILE_NOT_SUPPORTED
      newTagSet.$: >-
        States.StringToJson(States.Format('[{},{}]',
        States.ArrayGetItem(States.StringSplit(States.JsonToString($.s3Tags.TagSet),
        '[]'),0), '{"Key":"ImageModerationStatus","Value":"FILE_NOT_SUPPORTED"}'))
    Next: Tag S3 Object
  Moderate Image:
    Type: Task
    Parameters:
      Image:
        S3Object:
          Bucket.$: $.s3ObjectDetails.bucketName
          Name.$: $.s3ObjectDetails.objectKey
    Resource: arn:aws:states:::aws-sdk:rekognition:detectModerationLabels
    Next: File Supported
    ResultPath: $.RekognitionModeration
  File Supported:
    Type: Pass
    Parameters:
      ThreatsFound.$: States.ArrayLength($.RekognitionModeration.ModerationLabels)
      ContentTypes.$: $.RekognitionModeration.ContentTypes
      ModerationLabels.$: $.RekognitionModeration.ModerationLabels
      ModerationModelVersion.$: $.RekognitionModeration.ModerationModelVersion
    ResultPath: $.RekognitionModeration
    Next: Was Threats Found?
  Was Threats Found?:
    Type: Choice
    Choices:
      - Variable: $.RekognitionModeration.ThreatsFound
        NumericGreaterThan: 0
        Next: Add THREATS_DETECTED to Object Tags Array
    Default: Add NO_THREATS to Object Tags Array
  Add THREATS_DETECTED to Object Tags Array:
    Type: Pass
    Parameters:
      status: THREATS_FOUND
      newTagSet.$: >-
        States.StringToJson(States.Format('[{},{}]',
        States.ArrayGetItem(States.StringSplit(States.JsonToString($.s3Tags.TagSet),
        '[]'),0), '{"Key":"ImageModerationStatus","Value":"THREATS_FOUND"}'))
    ResultPath: $.scanResult
    Next: Tag S3 Object
  Add NO_THREATS to Object Tags Array:
    Type: Pass
    Next: Tag S3 Object
    Parameters:
      status: NO_THREATS_FOUND
      newTagSet.$: >-
        States.StringToJson(States.Format('[{},{}]',
        States.ArrayGetItem(States.StringSplit(States.JsonToString($.s3Tags.TagSet),
        '[]'),0), '{"Key":"ImageModerationStatus","Value":"NO_THREATS_FOUND"}'))
    ResultPath: $.scanResult
  Tag S3 Object:
    Type: Task
    Parameters:
      Bucket.$: $.s3ObjectDetails.bucketName
      Key.$: $.s3ObjectDetails.objectKey
      Tagging:
        TagSet.$: $.scanResult.newTagSet
    Resource: arn:aws:states:::aws-sdk:s3:putObjectTagging
    ResultPath: null
    Next: Post Scan Result Event
  Post Scan Result Event:
    Type: Task
    Resource: arn:aws:states:::events:putEvents
    Parameters:
      Entries:
        - Detail:
            metadata: {}
            data:
              id.$: $.s3ObjectDetails.objectKey
              status.$: $.scanResult.status
              scanData.$: $.RekognitionModeration
          DetailType: Moderation Scan Completed
          EventBusName: ${EventBusName}
          Source: ImageModeration
    End: true
    ResultPath: null

Abschluss des Uploads

Der letzte Teil dieser Lösung besteht darin, auf die Moderation zu reagieren und den Inhalt entweder im Quarantäne-Bucket oder im Langzeit-Bucket zu platzieren. Dafür verwende ich zwei verschiedene StepFunctions mit einigen Unterschieden in den Ereignissen, die sie aufrufen.

Abgeschlossener Ablauf

Um diesen Ablauf zu erreichen, wird eine neue StateMachine erstellt.

  MoveFilesToPermanentStorageStateMachineStandard:
    Type: AWS::Serverless::StateMachine
    Properties:
      DefinitionUri: StateMachine/move-to-permanent-storage.asl.yaml
      DefinitionSubstitutions:
        EventBusName:
          Fn::ImportValue: !Sub ${CommonInfraStackName}:event-bus-name
        StorageBucketName:
          Fn::ImportValue: !Sub ${CommonInfraStackName}:storage-bucket-name
        StagingBucketName:
          Fn::ImportValue: !Sub ${CommonInfraStackName}:staging-bucket-name
      Tracing:
        Enabled: true
      Policies:
        - Statement:
            - Effect: Allow
              Action:
                - logs:*
              Resource: "*"
        - S3FullAccessPolicy:
            BucketName:
              Fn::ImportValue: !Sub ${CommonInfraStackName}:staging-bucket-name
        - S3FullAccessPolicy:
            BucketName:
              Fn::ImportValue: !Sub ${CommonInfraStackName}:storage-bucket-name
        - EventBridgePutEventsPolicy:
            EventBusName:
              Fn::ImportValue: !Sub ${CommonInfraStackName}:event-bus-name
      Events:
        NoModerationThreatsFoundEvent:
          Type: EventBridgeRule
          Properties:
            EventBusName:
              Fn::ImportValue: !Sub ${CommonInfraStackName}:event-bus-name
            InputPath: $.detail
            Pattern:
              source:
                - ImageModeration
              detail-type:
                - Moderation Scan Completed
              detail:
                data:
                  status:
                    - NO_THREATS_FOUND 

Mit einer StateMachine-Definition, die etwas einfacher zu verfolgen ist als der Bildmoderations-Teil.

Comment: Ergebnis verarbeiten und Dateien in den Speicher-Bucket kopieren
StartAt: Debug
States:
  Debug:
    Type: Pass
    Next: Get Object Metadata
  Get Object Metadata:
    Type: Task
    Parameters:
      Bucket: ${StagingBucketName}
      Key.$: $.data.id
    Resource: arn:aws:states:::aws-sdk:s3:headObject
    Next: CopyObject
    ResultPath: $.S3MetaData
  CopyObject:
    Type: Task
    Parameters:
      Bucket: ${StorageBucketName}
      CopySource.$: >-
        States.Format('${StagingBucketName}/{}',$.data.id)
      Key.$: $.data.id
    Resource: arn:aws:states:::aws-sdk:s3:copyObject
    ResultPath: null
    Next: DeleteObject
  DeleteObject:
    Type: Task
    Parameters:
      Bucket: ${StagingBucketName}
      Key.$: $.data.id
    Resource: arn:aws:states:::aws-sdk:s3:deleteObject
    ResultPath: null
    Next: Post Event File Moved
  Post Event File Moved:
    Type: Task
    Resource: arn:aws:states:::events:putEvents
    Parameters:
      Entries:
        - Detail:
            metadata: {}
            data:
              id.$: $.data.id
              status: STORED
              contentType.$: $.S3MetaData.ContentType
              fileSize.$: $.S3MetaData.ContentLength
          DetailType: Completed
          EventBusName: ${EventBusName}
          Source: ImageModeration
    End: true
    ResultPath: null

Fazit

Dies war ein kurzer Beitrag darüber, wie ich meinen zuvor erstellten Dateiverwaltungsdienst um Malware-Scans und Bildmoderation erweitert habe. Die Verwendung von nur verwalteten Diensten hat dies zu einer ziemlich einfachen Aufgabe gemacht.

Um den vollständigen Quellcode zu erhalten und ihn selbst zu deployen, besuchen Sie Serverless-Handbuch Bildmoderation

Abschließende Worte

Vergessen Sie nicht, mir auf LinkedIn und X zu folgen, um weitere Inhalte zu erhalten, und lesen Sie den Rest meiner Blogs

Wie Werner sagt! Jetzt loslegen!