Suivez les instructions détaillées ci-dessous pour créer un backend sans serveur. Cliquez sur chaque numéro d'étape pour développer la section correspondante.

  • Étape 1. Créer une stratégie IAM pour un rôle IAM personnalisé.

    Pour accorder les autorisations de gestion des requêtes backend pour votre site Web, vous devez créer une stratégie IAM personnalisée qui accorde des autorisations pour les services AWS suivants :

    • 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
      • *

    Pour créer une stratégie IAM personnalisée, procédez comme suit.

     1. Ouvrez la console IAM sur https://console.aws.amazon.com/iam/.

     2. Dans le volet de navigation, choisissez Stratégies.

     3. Si vous sélectionnez Stratégies pour la première fois, la page Bienvenue dans les stratégies gérées s'affiche. Sélectionnez Mise en route.

     4. Sélectionnez Créer une stratégie.

     5. Sélectionnez l'onglet JSON.

     6. Copiez et collez la stratégie JSON suivante dans le champ du document de stratégie.

    {
        "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. Remplacez <REGION-CODE> par la valeur correspondant à la région AWS dans laquelle vous déployez le portail d'intégration d'applications. Cette valeur doit être introduite en minuscules. Pour obtenir la liste des codes des régions AWS pour AppStream 2.0, consultez la colonne Régions du tableau Points de terminaison Amazon AppStream 2.0 dans les Références générales AWS. Remplacez <AWS-ACCOUNT-ID> par votre ID de compte AWS.

     8. Lorsque vous avez terminé, sélectionnez Examiner une stratégie.

     9. Dans le champ Nom, saisissez le nom suivant pour votre nouvelle stratégie : examplecorp_eao_policy.

     10. Sélectionnez Créer une stratégie.

  • Étape 2. Créer un rôle IAM lié à un service qui permet aux fonctions Lambda d'appeler des services AWS.

    Lambda nécessite un rôle IAM lié à un service pour permettre au service d'accéder, en votre nom, aux ressources d'autres services. Pour créer un rôle IAM lié à un service et attacher la stratégie que vous avez créée à ce rôle, procédez comme suit.

       1. Ouvrez la console IAM sur https://console.aws.amazon.com/iam/.

       2. Dans le volet de navigation, sous Rôles, sélectionnez Créer un rôle.

       3. Pour Sélectionner le type d'entité de confiance, laissez l'option Service AWS sélectionnée.

       4. Sélectionnez Lambda, puis sélectionnez Suivant : autorisations.

       5. Dans la zone de recherche Filtrer les stratégies, saisissez examplecorp_eao_policy. Lorsque la stratégie apparaît dans la liste, cochez la case située à côté du nom de la stratégie.

       6. Sélectionnez Suivant : balises. Aucune balise n'est requise, même si vous pouvez spécifier une balise pour la stratégie.

       7. Sélectionnez Suivant : vérification.

       8. Saisissez examplecorp_eao_role pour le nom du rôle.

       9. Sélectionnez Créer le rôle.

       10. Dans la zone de recherche, saisissez examplecorp_eao_role. Lorsque le nom apparaît dans la liste, sélectionnez le nom du rôle.

       11. L'ARN de rôle s'affiche en haut de la page Récapitulatif. Prenez note de cet ARN. Cet ARN vous sera demandé plus tard dans le projet.

       12. Sélectionnez l'onglet Relations d'approbation, puis sélectionnez Modifier la relation d'approbation.

       13. Sous Document de stratégie, configurez la stratégie de relation d'approbation afin d'inclure l'action sts:AssumeRole pour les mandataires de service lambda.amazonaws.com, states.amazonaws.com et apigateway.amazonaws.com. Le format est le suivant :

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

    14. Lorsque vous avez terminé, sélectionnez Mettre à jour la stratégie de confiance pour enregistrer vos modifications.  

  • Étape 3. Créer et configurer six fonctions Lambda.

    Pour créer six fonctions Lambda, procédez comme suit.

       1. Ouvrez la console Lambda sur https://console.aws.amazon.com/lambda/.

       2. Effectuez l'une des actions suivantes :

          • Si vous n'avez pas encore créé de fonction Lambda, une page Mise en route s'affiche. Sous Mise en route, sélectionnez Créer une fonction.

          • Si vous avez déjà créé une fonction Lambda, sélectionnez Créer une fonction dans le coin supérieur droit de la page Fonctions.

       3. Sur la page Créer une fonction, laissez l'option Créer à partir de zéro sélectionnée.

       4. Sous Informations de base, procédez comme suit :

          • Dans le champ Nom, saisissez examplecorp_eao_createimagebuilder.

          • Dans le champ Exécution, sélectionnez Python 3.7.

       5. Sous Autorisations, sélectionnez l'icône située à côté de Sélectionner ou créer un rôle d'exécution. Puis, procédez comme suit :

          • Dans le champ Rôle d'exécution, sélectionnez Utiliser un rôle existant.

          • Dans le champ Rôle existant, sélectionnez examplecorp_eao_role depuis la liste.

       6. Sélectionnez Créer une fonction.

       7. Le code de l'espace apparaît dans la section Code de fonction, dans l'onglet lambda_function. Supprimez le code de l'espace, et copiez et collez le code suivant dans l'onglet :

    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. Enregistrez la fonction. Cette fonction crée un générateur d'images AppStream 2.0.

       9. Répétez les étapes 2 à 8 pour chacune des fonctions Lambda suivantes.
           Remarque : pour l'étape 7, collez le code de la fonction Lambda correspondante.

    Fonction Lambda 2 : obtenir le statut du générateur d'images et de la flotte AppStream 2.0

    Lorsque vous créez cette fonction, nommez-la 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
    

    Fonction Lambda 3 : envoyer une URL de streaming

    Lorsque vous créez cette fonction, nommez-la examplecorp_eao_sendstreamingurl.

    Remarque : avant d'enregistrer cette fonction, recherchez <REGION-CODE> et remplacez-le par le code de la région correspondant à la région AWS dans laquelle vous avez configuré SES. Ensuite, recherchez Source='noreply@example.com' et modifiez cette valeur par l'adresse e-mail que vous avez vérifiée dans SES lors du module précédent. 

    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
    

    Fonction Lambda 4 : obtenir le nom d'image AppStream 2.0

    Lorsque vous créez cette fonction, nommez-la 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
    

    Fonction Lambda 5 : créer une flotte et une pile AppStream, et associer la flotte à une pile

    Lorsque vous créez cette fonction, nommez-la 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
    

    Fonction Lambda 6 : arrêter la flotte et le générateur d'images AppStream 2.0

    Lorsque vous créez cette fonction, nommez-la 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