Desktop and Application Streaming

AWS CloudFormation support for Amazon AppStream 2.0 resources and API enhancements

We’ve learned from our customers that they want to create AppStream 2.0 resources along with their AWS resources to support a workshop or event. Today, AWS is announcing that AWS CloudFormation now supports creating AppStream 2.0 resources. With a single template, you can automate the creation of your stacks, fleets, image builders, directory configurations, and user pool users. You can now create AppStream 2.0 resources in your AWS CloudFormation templates along with your other AWS resources.

AppStream 2.0 also released API operations that enable programmatic management of user pool users. With these API operations, you can now create, manage, and delete your AppStream 2.0 user pool users.

AWS CloudFormation support for AppStream 2.0 resources

AWS CloudFormation provides a common language for you to describe and provision all the infrastructure resources in your cloud environment. AWS CloudFormation lets you use a text file to model and provision, in an automated and secure manner, all the resources needed for your applications across all AWS Regions and accounts. You can now use AWS CloudFormation to create and manage your AppStream 2.0 image builders, stacks, fleets, directory configs, and user pool users.

The following is an example AWS CloudFormation YAML configuration for creating a demo stack, fleet, and user:

AWSTemplateFormatVersion: 2010-09-09
Description: "This CloudFormation Stack creates AppStream resources within the default VPC."

Resources:
  AppStreamFleet:
    Type: "AWS::AppStream::Fleet"
    Properties:
      Name: "DemoFleet"
      Description: "This is a demo fleet that was created using CloudFormation"
      DisplayName: "A demo fleet created in CloudFormation"
      ImageName: "MySampleImage"
      InstanceType: "stream.standard.medium"
      FleetType: "ALWAYS_ON"
      ComputeCapacity:
        DesiredInstances: 5
      VpcConfig:
        SubnetIds:
          - subnet-<redacted>
          - subnet-<redacted>          
        SecurityGroupIds:
          - sg-<redacted>          
      MaxUserDurationInSeconds: "57600"
      DisconnectTimeoutInSeconds: "900"
      EnableDefaultInternetAccess: False
    CreationPolicy:
      StartFleet: True

  ScaleTarget:
    Type: 'AWS::ApplicationAutoScaling::ScalableTarget'
    Properties:
      MinCapacity: 1
      MaxCapacity: 5
      ResourceId:  !Join
        - ''
        - - 'fleet/'
          - !Ref AppStreamFleet
      RoleARN: >-
        arn:aws:iam::<aws-account-number>:role/service-role/ApplicationAutoScalingForAmazonAppStreamAccess
      ScalableDimension: 'appstream:fleet:DesiredCapacity'
      ServiceNamespace: appstream
    DependsOn:
      - AppStreamFleet

  ScaleInPolicy:
    Type: 'AWS::ApplicationAutoScaling::ScalingPolicy'
    Properties:
      PolicyName: !Join
        - ''
        - - 'ScaleIn-'
          - !Ref AppStreamFleet
      PolicyType: StepScaling
      ScalingTargetId: !Ref ScaleTarget
      StepScalingPolicyConfiguration:
        AdjustmentType: ChangeInCapacity
        Cooldown: 360
        MetricAggregationType: Average
        StepAdjustments:
          - MetricIntervalUpperBound: 0.0
            ScalingAdjustment: -1
    DependsOn:
      - ScaleTarget

  ScaleOutPolicy:
    Type: 'AWS::ApplicationAutoScaling::ScalingPolicy'
    Properties:
      PolicyName:  !Join
        - ''
        - - 'ScaleOut-'
          - !Ref AppStreamFleet
      PolicyType: StepScaling
      ScalingTargetId: !Ref ScaleTarget
      StepScalingPolicyConfiguration:
        AdjustmentType: ChangeInCapacity
        Cooldown: 120
        MetricAggregationType: Average
        StepAdjustments:
          - MetricIntervalLowerBound: 0.0
            ScalingAdjustment: 2
    DependsOn:
      - ScaleTarget

  ScaleInAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties : 
      AlarmActions : 
        - !Ref ScaleInPolicy
      AlarmDescription : "Scale in the fleet when using 25% capacity"
      AlarmName :  !Join
        - ''
        - - 'ScaleInAlarm'
          - !Ref AppStreamFleet
      Dimensions : 
        - Name: Fleet
          Value: !Ref AppStreamFleet
      MetricName : CapacityUtilization
      Namespace : AWS/AppStream
      Period : 120
      EvaluationPeriods : 10      
      Statistic : Average
      Threshold : 25
      ComparisonOperator : LessThanOrEqualToThreshold      
      Unit : Percent
    DependsOn:
      - ScaleInPolicy   

  ScaleOutAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties : 
      AlarmActions : 
        - !Ref ScaleOutPolicy
      AlarmDescription : "Scale out the fleet when using 75% capacity"
      AlarmName :  !Join
        - ''
        - - 'ScaleOutAlarm'
          - !Ref AppStreamFleet
      Dimensions : 
        - Name: Fleet
          Value: !Ref AppStreamFleet
      MetricName : CapacityUtilization
      Namespace : AWS/AppStream
      Period : 60
      EvaluationPeriods : 3      
      Statistic : Average
      Threshold : 75
      ComparisonOperator : GreaterThanOrEqualToThreshold      
      Unit : Percent
    DependsOn:
      - ScaleOutPolicy
      
  AppStreamStack:
    Type: "AWS::AppStream::Stack"
    Properties:
      Name: "DemoStack"
      Description: "This demo stack was created using CloudFormation"
      StorageConnectors:
        - ConnectorType: "HOMEFOLDERS"
          ResourceIdentifier: "TestCloudFormationStackBucket"
          
  AppStreamDemoStackFleetAssociation:
    Type: 'AWS::AppStream::StackFleetAssociation'
    Properties:
      FleetName: !Ref AppStreamFleet
      StackName: !Ref AppStreamStack
    DependsOn:
      - AppStreamFleet
      - AppStreamStack
      
  AppStreamUser:
    Type: "AWS::AppStream::User"
    Properties:
      UserName: "user@email.com"
      FirstName: "John"
      LastName: "Smith"
      AuthenticationType: "USERPOOL"
      
  AppStreamStackUserAssociation:
    Type: "AWS::AppStream::StackUserAssociation"
    Properties:
      UserName: "user@email.com"
      StackName: !Ref AppStreamStack
      SendEmailNotification: False
    DependsOn:
     - AppStreamStack
     - AppStreamUser

In the previous example, the AppStream stack and fleet resource are created independently. To associate them, use the StackFleetAssociation AWS CloudFormation resource. To associate the fleet and stack at the right time, the StackFleetAssociation resource should have a dependency on the creation of the resources it is associating.

For more information about AppStream 2.0 resource creation with AWS CloudFormation templates, see the AWS CloudFormation user guide.

AppStream 2.0 user pool API operations

The user pool feature in AppStream 2.0 lets you efficiently create and manage users within the AppStream 2.0 console. Your users can use a persistent login link to set a password and stream the apps you have assigned to them. Our customers told us that they wanted to manage their user pool users via the API and SDK. With the API operations, you can create, assign to stacks, enable, disable, and delete users. You can also describe your user pool users and describe their stack associations.

The following is an example of creating a user, assigning the user to a stack, disabling the user, and then deleting the user.

Create the user’s account, by using the following:

aws appstream create-user --user-name "<email redacted>" --first-name "John" --last-name "Smith" --authentication-type "USERPOOL"

The user receives the welcome to AppStream 2.0 email that contains their initial password, and the login link. Now that the user’s account has been created, we must assign the account to a stack with apps. Assign the account to a stack by using the following:

aws appstream batch-associate-user-stack --user-stack-associations AuthenticationType="USERPOOL",SendEmailNotification=True,StackName="TestStack",UserName="<email redacted>"

The user receives the assignment email notifying them that they have new apps available. The user can now log in with their temporary password, set a permanent password, and stream apps!

When the user temporarily doesn’t need their applications, you can disable their account. Disabling their account keeps their stack associations and password; however, they can’t log in and stream until you enable them again. Disable an account by using the following:

aws appstream disable-user --user-name "<email redacted>" --authentication-type "USERPOOL"

Disabled users receive an error when they try to log in. When the user no longer needs access to their applications, you can delete their account. When you delete their account, the stack associations and their password are deleted. If the user needs access again, create a new account for them, and associate it to your stacks. The user must then use the temporary password to set a new permanent password. Delete an account by using the following:

aws appstream delete-user --user-name "<email redacted>" --authentication-type "USERPOOL"

Conclusion

That’s it! You can create your own AWS CloudFormation templates to create your AppStream 2.0 resources along with your other AWS resources and now use the user pool API operations to create and manage your users.