Befolgen Sie die nachstehende Schritt-für-Schritt-Anleitung zur Erstellung eines serverlosen Backends. Klicken Sie auf die Nummer eines jeweiligen Schritts, um den Bereich zu erweitern.

  • Schritt 1: Erstellen einer IAM-Richtlinie für eine benutzerdefinierte IAM-Rolle.

    Um Berechtigungen zur Verarbeitung von Backend-Anforderungen für Ihre Website zu gewähren, erstellen Sie eine benutzerdefinierte IAM-Richtlinie, die Berechtigungen für die folgenden AWS-Services gewährt:

    • Step Functions
      • StartExecution (stateMachine:examplecorp_eao)
      • Sts:AssumeRole
    • Lambda
      • function:examplecorp_eao_createfleet
      • function:examplecorp_eao_createimagebuilder
      • function:examplecorp_eao_getimagename
      • function:examplecorp_eao_getstatus
      • function:examplecorp_eao_sendstreamingurl
      • function:examplecorp_eao_stopresources
      • Sts:AssumeRole
    • AppStream 2.0
      • AssociateFleet (Fleet/*)
      • CreateFleet (Fleet/*)
      • CreateImageBuilder (Image-Builder/*)
      • CreateImageBuilderStreamingURL (Image-Builder/*)
      • CreateStack (Stack/*)
      • CreateStreamingURL (Fleet/*)
      • DescribeFleets (Fleet/*)
      • DescribeImageBuilders (Image-Builder/*)
      • DescribeImages (Image/*)
      • StartFleet (Fleet/*)
      • StartImageBuilder (Image-Builder/*)
      • StopFleet (Fleet/*)
      • StopImageBuilder (Image-Builder/*)
    • SES
      • SendEmail
    • API Gateway
      • Sts:AssumeRole
    • CloudWatch
      • *

    Führen Sie die folgenden Schritte zur Erstellung der benutzerdefinierten IAM-Richtlinie aus.

     1. Öffnen Sie die IAM-Konsole über https://console.aws.amazon.com/iam/.

     2. Wählen Sie Richtlinien im Navigationsbereich aus.

     3. Wenn Sie zum ersten Mal Richtlinien auswählen, wird die Seite Willkommen zu den verwalteten Richtlinien angezeigt. Wählen Sie Erste Schritte aus.

     4. Wählen Sie Richtlinie erstellen aus.

     5. Wählen Sie die Registerkarte JSON aus.

     6. Kopieren Sie die folgende JSON-Richtlinie und fügen Sie sie in das Richtliniendokument-Feld ein.

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "VisualEditor0",
                "Effect": "Allow",
                "Action": [
                    "lambda:InvokeFunction",
                    "appstream:DescribeImages",
                    "appstream:StartFleet",
                    "appstream:StopImageBuilder",
                    "appstream:CreateStack",
                    "appstream:CreateImageBuilderStreamingURL",
                    "appstream:AssociateFleet",
                    "appstream:DescribeImageBuilders",
                    "appstream:StopFleet",
                    "appstream:CreateImageBuilder",
                    "appstream:CreateFleet",
                    "appstream:DescribeFleets",
                    "states:StartExecution",
                    "appstream:StartImageBuilder",
                    "appstream:CreateStreamingURL"
                ],
                "Resource": [
                    "arn:aws:appstream:*:*:fleet/*",
                    "arn:aws:appstream:*:*:image/*",
                    "arn:aws:appstream:*:*:stack/*",
                    "arn:aws:appstream:*:*:image-builder/*",
                    "arn:aws:states:<REGION-CODE>:<AWS-ACCOUNT-ID>:stateMachine:examplecorp_eao",
                    "arn:aws:lambda:<REGION-CODE>:<AWS-ACCOUNT-ID>:function:examplecorp_eao_sendstreamingurl",
                    "arn:aws:lambda:<REGION-CODE>:<AWS-ACCOUNT-ID>:function:examplecorp_eao_createimagebuilder",
                    "arn:aws:lambda:<REGION-CODE>:<AWS-ACCOUNT-ID>:function:examplecorp_eao_getstatus",
                    "arn:aws:lambda:<REGION-CODE>:<AWS-ACCOUNT-ID>:function:examplecorp_eao_getimagename",
                    "arn:aws:lambda:<REGION-CODE>:<AWS-ACCOUNT-ID>:function:examplecorp_eao_createfleet",
                    "arn:aws:lambda:<REGION-CODE>:<AWS-ACCOUNT-ID>:function:examplecorp_eao_stopresources"
                ]
            },
            {
                "Sid": "VisualEditor1",
                "Effect": "Allow",
                "Action": [
                    "ses:SendEmail",
                    "logs:CreateLogStream",
                    "cloudwatch:*",
                    "logs:CreateLogGroup",
                    "logs:PutLogEvents"
                ],
                "Resource": "*"
            }
        ]
    }
    

     7. Ersetzen Sie <REGION-CODE> mit dem Wert, der der AWS-Region entspricht, in der Sie das Anwendungs-Onboarding-Portal bereitstellen. Der Wert muss in Kleinbuchstaben angegeben werden. Eine Liste der AWS-Regionscodes für AppStream 2.0 finden Sie in der Spalte Region der Tabelle Amazon AppStream 2.0-Endpunkte in der AWS General Reference. Ersetzen Sie <AWS-ACCOUNT-ID> mit Ihrer AWS-Kontonummer.

     8. Wenn Sie fertig sind, wählen Sie Richtlinie überprüfen aus.

     9. Geben Sie bei Name den folgenden Namen für Ihre neue Richtlinie ein: examplecorp_eao_policy.

     10. Wählen Sie Richtlinie erstellen aus.

  • Schritt 2: Erstellen einer Service-verknüpften IAM-Rolle, mit der AWS-Services von Lambda-Funktionen abgerufen werden können.

    Bei Lambda muss eine Service-verknüpfte IAM-Rolle dem Service erlauben, an Ihrer Stelle auf Ressourcen in anderen Services zuzugreifen. Führen Sie die folgenden Schritte aus, um eine Service-verknüpfte IAM-Rolle zu erstellen und fügen Sie die Richtlinie hinzu, die Sie für diese Rolle erstellt haben.

       1. Öffnen Sie die IAM-Konsole über https://console.aws.amazon.com/iam/.

       2. Wählen Sie im Navigationsbereich bei Rollen die Option Rolle erstellen aus.

       3. Behalten Sie bei Typ der vertrauenswürdigen Entität auswählen die Auswahl AWS-Service bei.

       4. Wählen Sie Lambda und dann Weiter: Berechtigungen aus.

       5. Geben Sie in das Suchfeld Richtlinien filtern den Text examplecorp_eao_policy ein. Wenn die Richtlinie in der Liste angezeigt wird, aktivieren Sie das Kontrollkästchen neben dem Richtliniennamen.

       6. Wählen Sie Weiter: Tags aus. Sie können zwar einen Tag für die Richtlinie angeben, aber das ist nicht erforderlich.

       7. Klicken Sie auf Weiter: Überprüfung.

       8. Geben Sie examplecorp_eao_role als Rollenname ein.

       9. Wählen Sie Rolle erstellen aus.

       10. Geben Sie examplecorp_eao_role in das Suchfeld ein. Wenn die Rolle in der Liste angezeigt wird, wählen Sie den Namen der Rolle aus.

       11. Oben auf der Seite Zusammenfassung wird der ARN der Rolle angezeigt. Notieren Sie sich diesen ARN. Sie benötigen diesen ARN im späteren Verlauf des Projekts.

       12. Wählen Sie die Registerkarte Vertrauensstellungen und dann Vertrauensstellung bearbeiten aus.

       13. Konfigurieren Sie bei Richtliniendokument die Richtlinie für die Vertrauensstellung, um die Aktion "sts:AssumeRole" für die Serviceprinzipalen lambda.amazonaws.com, states.amazonaws.com und apigateway.amazonaws.com einzubeziehen. Das folgende Format muss verwendet werden:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Sid": "",
          "Effect": "Allow",
          "Principal": {
            "Service": [
              "lambda.amazonaws.com",
              “states.amazonaws.com”,
              "apigateway.amazonaws.com"
            ]
          },
          "Action": "sts:AssumeRole"
        }
      ]
    }

    14. Wenn Sie fertig sind, wählen Sie Vertrauensrichtlinie aktualisieren aus, um Ihre Änderungen zu speichern.  

  • Schritt 3: Erstellen und Konfigurieren von sechs Lambda-Funktionen.

    Führen Sie die folgenden Schritte zur Erstellung von sechs Lambda-Funktionen aus.

       1. Öffnen Sie die Lambda-Konsole unter https://console.aws.amazon.com/lambda/.

       2. Führen Sie eine der folgenden Aktionen aus:

          • Wenn Sie keine Lambda-Funktionen erstellt haben, wird die Seite "Erste Schritte" angezeigt. Wählen Sie bei Erste Schritte die Option Funktion erstellen aus.

          • Wenn Sie eine Lambda-Funktion erstellt haben, wählen Sie in der oberen rechten Ecke der Seite Funktionen die Option Funktion erstellen aus.

       3. Behalten Sie auf der Seite Funktion erstellen die Auswahl Von Grund auf neu erstellen bei.

       4. Führen Sie bei Grundlegende Informationen die folgenden Aktionen aus:

          • Geben Sie bei Name den Text examplecorp_eao_createimagebuilder ein.

          • Wählen Sie bei Laufzeit die Option Python 3.7 aus.

       5. Wählen Sie bei Berechtigungen das Symbol neben Ausführungsrolle auswählen oder erstellen aus. Führen Sie danach folgende Aktionen aus:

          • Wählen Sie bei Ausführungsrolle die Option Vorhandene Rolle verwenden aus.

          • Wählen Sie bei Vorhandene Rolle den Eintrag examplecorp_eao_role von der Liste aus.

       6. Wählen Sie "Funktion erstellen" aus.

       7. Im Abschnitt Funktionscode auf der Registerkarte lambda_function wird der Platzhaltercode angezeigt. Löschen Sie den Platzhaltercode, kopieren Sie den folgenden Code und fügen Sie ihn bei der Registerkarte ein:

    from __future__ import print_function
    import json
    import boto3
    appstream = boto3.client('appstream')
    
    def lambda_handler(event, context):
        # Log the received event
        print("Received event: " + json.dumps(event, indent=2))
        # Get variables from web form
        strIBName = event['ib_name']
        strIBARN = event['ib_arn']
        strInstType = event['instance_type']
        strSubnetId = event['subnet1id']
        strSecurityGroups = event['securitygroups']
        strUserEmail = event['email']
        strUserName = event['user_name']
        strUserEmail = strUserEmail.strip()
        strUserName= strUserName.strip()  
    
        try:
            response = appstream.create_image_builder(
                Name=strIBName,
                ImageArn=strIBARN,
                VpcConfig={
                    'SubnetIds':[
                        strSubnetId
                        ],
                    'SecurityGroupIds':[
                        strSecurityGroups
                        ]
                },
                InstanceType=strInstType)
            print("Started: " + strIBName)
            return 1
        except Exception as e:
            print(e)
            message = 'Error creating image builder'
            print(message)
    

       8. Speichern Sie die Funktion. Diese Funktion erstellt einen AppStream 2.0-Image-Builder.

       9. Wiederholen Sie die Schritte 2 bis 8 für jede der folgenden Lambda-Funktionen.
           Hinweis: Bei Schritt 7 fügen Sie den Code für die entsprechende Lambda-Funktion ein.

    Lambda-Funktion 2: Abrufen des Status vom AppStream 2.0-Image-Builder und der AppStream 2.0-Flotte

    Wenn Sie diese Funktion erstellen, geben Sie ihr den Namen examplecorp_eao_getstatus.

    from __future__ import print_function
    
    import json
    import boto3
    
    print('Loading function')
    appstream = boto3.client('appstream')
    
    def Status_to_Return(received_state):
        switcher = {
        "PENDING": 0,
        "RUNNING": 1,
        "SNAPSHOTTING": 2,
        "STOPPED": 3,
        "STOPPING": 4,
        "STARTING": 5  
        }
        return switcher.get(received_state, -1)
    
    def lambda_handler(event, context):
        # Log the received event
        print("Received event: " + json.dumps(event, indent=2))
        # Get names to query against
        strIBName = event['ib_name']
        strFleetName = event['fleet_name']
        strType = event['type']
        try:
            #Fleet status check
            if strType == 2:
                print ("Type is Fleet")
                AS2state = appstream.describe_fleets(Names=[strFleetName])
                Status = AS2state['Fleets'][0]['State']
                print ("State: " + Status)
            #Image Builder status check
            elif strType == 1:
                print ("Type is ImageBuilder")
                AS2state = appstream.describe_image_builders(Names=[strIBName])
                Status = AS2state['ImageBuilders'][0]['State']
                print ("State: " + Status)
            return Status_to_Return(Status)
        except Exception as e:
            print(e)
            print("Error getting status")
            return -1
    

    Lambda-Funktion 3: Senden einer Streaming-URL

    Wenn Sie diese Funktion erstellen, geben Sie ihr den Namen examplecorp_eao_sendstreamingurl.

    Hinweis: Bevor Sie diese Funktion speichern, suchen Sie nach <REGION-CODE> und ersetzen Sie diese Zeichenfolge mit dem Regionscode, der der AWS-Region entspricht, in der Sie den SES konfiguriert haben. Suchen Sie dann nach Source='noreply@example.com' und ändern Sie den Wert zu der E-Mail-Adresse, die Sie beim vorherigen Modul im SES bestätigt haben. 

    from __future__ import print_function
    
    import json
    import boto3
    
    print('Loading function')
    appstream = boto3.client('appstream')
    ses = boto3.client('ses',region_name=<REGION-CODE>)
    
    def lambda_handler(event, context):
        # Log the received event
        print("Received event: " + json.dumps(event, indent=2))
        # Get resource names
        strUserName = event['user_name']
        strUserName = strUserName.strip()
        strEmail = event['email']
        strEmail = strEmail.strip()
        strIBName = event['ib_name']
        strFleetName = event['fleet_name']
        strStackName = event['stack_name']
        strType = event['type']
    
        try:
            #Create Fleet Streaming URL
            if strType == 2:
                print ("Type is Fleet")
                mailBody = "Your fleet is now created and ready for verification. Please use the connect link below to connect to the instance."
                url = appstream.create_streaming_url(
                    StackName=strStackName,
                    FleetName=strFleetName,
                    UserId=strUserName,
                    Validity=604800
                )            
            #Create Image Builder Streaming URL
            elif strType == 1:
                print ("Type is ImageBuilder")
                mailBody = "If this is your first time installing your application with AppStream2.0, you can check the getting started guide below for assistance. Otherwise, please click the connect link below to get started."
                url = appstream.create_image_builder_streaming_url(
                    Name=strIBName,
                    Validity=604800
                )
            strStreamingURL = url['StreamingURL']
            print("Streaming URL: " + strStreamingURL)
            #Send Streaming URL in E-mail via SES
            ses.send_email(
                Source='noreply@example.com',
                Destination={
                    'ToAddresses': [strEmail],
                            },
                Message={
                    'Body': {
                    'Html': {
                    'Charset': 'UTF-8',
                    'Data': '<html><head><title>Example Corp</title></head><body bgcolor="#e0e0e0">' + strUserName + ',<p>Thank you for trying out the Example Corp <strong>Enterprise Application Onboarding</strong> demo. ' + mailBody + '</p><p><a href=" ' + strStreamingURL + ' ">Connect</a></p><a href="https://d1.awsstatic.com/product-marketing/AppStream2.0/Amazon%20AppStream%202.0%20Getting%20Started%20Guide%20April%202018.pdf">Getting Started Guide</a></body></html>',
                    },
                    },
                    'Subject': {
                    'Charset': 'UTF-8',
                    'Data': 'Example Corp Enterprise Application Onboarding for ' + strUserName                    
                    },
                }
            )
            return 1
    
        except Exception as e:
            print(e)
            print("Error getting streaming URL")
            return -1
    

    Lambda-Funktion 4: Abrufen des AppStream 2.0-Image-Namens

    Wenn Sie diese Funktion erstellen, geben Sie ihr den Namen examplecorp_eao_getimagename.

    from __future__ import print_function
    
    import json
    import boto3
    import datetime
    
    print('Loading function')
    appstream = boto3.client('appstream')
    
    def lambda_handler(event, context):
        # Log the received event
        print("Received event: " + json.dumps(event, indent=2))
        # Get names to query against
        strIBName = event['ib_name']
        try:
            ImagesCMD = appstream.describe_images(Type='PRIVATE')
            Images = ImagesCMD['Images']
            for Image in Images:
                if Image.get('ImageBuilderName','') == strIBName:
                    ImageTime = Image['CreatedTime']
                    now = datetime.datetime.utcnow().replace(tzinfo=datetime.timezone.utc)
                    howold = now - ImageTime
                    HowOldSec = howold.total_seconds()
                    if HowOldSec < 3600:
                        imagename = Image['Name']
                        return (imagename)
        except Exception as e:
            print(e)
            print("Error getting Image Name")
            return -1
    

    Lambda-Funktion 5: Erstellen einer AppStream-Flotte und eines Stacks und Herstellen einer Zuordnung zwischen Flotte und Stack

    Wenn Sie diese Funktion erstellen, geben Sie ihr den Namen examplecorp_eao_createfleet.

    from __future__ import print_function
    import json
    import boto3
    print('Loading function')
    appstream = boto3.client('appstream')
    
    def lambda_handler(event, context):
        # Log the received event
        print("Received event: " + json.dumps(event, indent=2))
        strFleetName = event['fleet_name']
        strStackName = event['stack_name']
        strImageName = event['imagename']
        strInstType = event['instance_type']
        strSubnet1Id = event['subnet1id']
        strSubnet2Id = event['subnet2id']
        strSecurityGroups = event['securitygroups']
    
        try:
            #Create AppStream fleet
            fleet = appstream.create_fleet(
                Name=strFleetName,
                ImageName=strImageName,
                ComputeCapacity={
                    'DesiredInstances': 1
                },            
                VpcConfig={
                    'SubnetIds':[
                        strSubnet1Id,
                        strSubnet2Id
                        ],
                    'SecurityGroupIds':[
                        strSecurityGroups
                        ]
                },
                InstanceType=strInstType)
            #Create AppStream stack
            stack = appstream.create_stack(
                Name=strStackName,
                StorageConnectors=[
                    {
                        'ConnectorType': 'HOMEFOLDERS'
                    },
                ],
                UserSettings=[
                    {
                        'Action': 'CLIPBOARD_COPY_FROM_LOCAL_DEVICE',
                        'Permission': 'ENABLED'
                    },
                ],
                ApplicationSettings={
                    'Enabled': False
                }
            )
            #Associate Stack to Fleet
            associate = appstream.associate_fleet(
                FleetName=strFleetName,
                StackName=strStackName
            )
            startfleet = appstream.start_fleet(
                Name=strFleetName
            )
            return 2
        except Exception as e:
            print(e)
            print("Error creating fleet")
            return -1
    

    Lambda-Funktion 6: Stoppen der AppStream 2.0-Flotte und des AppStream 2.0-Image-Builders

    Wenn Sie diese Funktion erstellen, geben Sie ihr den Namen examplecorp_eao_stopresources.

    from __future__ import print_function
    
    import json
    import boto3
    
    print('Loading function')
    appstream = boto3.client('appstream')
    
    def Status_to_Return(received_state):
        switcher = {
        "PENDING": 0,
        "RUNNING": 1,
        "SNAPSHOTTING": 2,
        "STOPPED": 3,
        "STOPPING": 4
        }
        return switcher.get(received_state, -1)
    
    def lambda_handler(event, context):
        # Log the received event
        print("Received event: " + json.dumps(event, indent=2))
        # Get names to query against
        strIBName = event['ib_name']
        strFleetName = event['fleet_name']
        strType = event['type']
        try:
            #Fleet status check
            if strType == 2:
                print ("Type is Fleet")
                AS2state = appstream.describe_fleets(Names=[strFleetName])
                Status = AS2state['Fleets'][0]['State']
                State = Status_to_Return(Status)
                if State < 3:            
                    print (strFleetName + " is " + Status + " attempting to stop")
                    AS2stop = appstream.stop_fleet(Name=strFleetName)
                print ("State: " + Status)
            #Image Builder status check
            elif strType == 1:
                print ("Type is ImageBuilder")
                AS2state = appstream.describe_image_builders(Names=[strIBName])
                Status = response['ImageBuilders'][0]['State']
                State = Status_to_Return(Status)
                if State < 3:
                    print (strIBName + " is " + Status + " attempting to stop")
                    AS2stop = appstream.stop_image_builder(Names=[strIBName])
                print ("State: " + Status)
            return Status_to_Return(Status)
        except Exception as e:
            print(e)
            print("Error stopping services")
            return -1