Desktop and Application Streaming

Automate Amazon WorkSpaces custom images across AWS Regions

Customers ask how they can automate copying Amazon WorkSpaces custom images between AWS Regions. Common use cases for synchronizing custom Amazon WorkSpaces images between Regions include:

Consistency for multi-Region deployments: Multi-region deployments of Amazon WorkSpaces allow WorkSpaces to be deployed for user who need low-latency connection to a specific geographic area. One custom image with a base set of applications and critical operating system updates is created. This image is copied to other AWS Regions. This accelerates, and standardizes the image management processes.

Managing disaster recovery/business continuity configurations: A disaster recovery (DR) deployment should have the latest image available. On a DR event, an administrator can rapidly launch Amazon WorkSpaces to provide a working environment.

In this blog, I use AWS Lambda to automate an image copy between AWS Regions. Amazon CloudWatch Events and Amazon CloudWatch Logs schedule, and monitor, the automation. “Security is job zero,” so AWS Identity and Access Management (IAM) is used to ensure that the principle of least privilege is applied.


Time to read 30 minutes
Time to complete 1.5 hours
Cost to complete The following cost considerations are detailed for this solution:

  1. CloudWatch Event – $1.00 per million events (in most AWS Regions)
  2. Lambda Function – approximately $0.20 per million requests, AWS Lambda pricing
  3. Copy the custom Amazon WorkSpaces image – there is no cost for hosting custom Amazon WorkSpaces images, or for copying of custom images
  4. CloudWatch Logs – <5 GB is $0, tiered pricing for over 5 GB, Amazon CloudWatch pricing
Learning level 200
Services used
  • Amazon WorkSpaces
  • AWS Identity and Access Management
  • AWS Lambda
  • Amazon CloudWatch


Before getting started, make sure you have the following:


The following four steps must be completed to have this automation covered in this blog securely in place.

  1. Create an IAM Role and Policy that contains the minimum permissions required for Lambda execution role.
  2. Create a Lambda Function using the AWS SDK through Python 3.8 runtime.
  3. Create a scheduled event using CloudWatch Event to start the Lambda Function in the interval required.
  4. Validate the results in a CloudWatch Log.

Step 1: Create the IAM role and policy

Before Lambda performs any functions, it needs permission to access resources. This policy allows the minimum permissions required for Lambda to create logs when the function runs, and to list and copy Amazon WorkSpaces images.

  1. Open the Amazon IAM console.
  2. Select Policies from the navigation pane.
  3. Choose ‘Create policy‘, then choose the JSON tab.
  4. In the editor, paste the following policy:
    "Version": "2012-10-17",
    "Statement": [
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
            "Resource": "*"

Note Resource is set to all. You can restrict the Amazon WorkSpaces images used, and the CloudWatch log groups by specifying the ARNs of those resources.

  1. Choose ‘Next: Tags‘, optionally add Tag information.
  2. Choose ‘Next: Review Policy.’
  3. Complete the review:

Name (required): lambdaWksImgCopyPolicy

Description (optional): Image copy policy

  1. Choose ‘Create Policy.’
  2. Select Roles from the navigation pane.
  3. Choose ‘Create Role.’
  4. Select ‘AWS Service‘ for Trusted Entity type.
  5. Select ‘Lambda‘ from Common Use cases.
  6. Choose ‘Next: Permissions‘ to continue.
  7. Select ‘Filter Policies‘, and select ‘Customer Managed.’ Choose the newly created lamdaWksImgCopyPolicy.
  8. Choose ‘Next: Tags‘ and enter any tags that may be required for your Organization.
  9. Choose ‘Next: Review‘ and provide the ‘NamelambdaWksImgCopyRole.
  10. Choose ‘Create role.’

For more information about the IAM permissions required, review the administration guide to copy a custom Amazon WorkSpaces image.

Step 2: Create Python 3.8 Lambda function

  1. Launch AWS Lambda from the AWS Management Console in your production Amazon WorkSpaces AWS Region.
  2. Choose ‘Create function‘ to begin creating your custom Lambda function.
  3. Keep ‘Author from scratch’ select. In the ‘Function name‘ field, enter copyCustomWorkSpaceImage. Optionally, enter a description.
  4. In the ‘Runtime‘ drop-down, select Python 3.8.
  5. Under ‘Permissions,’ expand the settings and select ‘Use an existing role.’
  6. From the drop-down, select lambdaWksImgCopyRole.
  7. Choose ‘Create function‘ and select the ‘Function code’ section.

2.1 Function Code

  1. Paste the following Python code into the Code editor:
import json
import boto3
import os

from botocore.exceptions import EndpointConnectionError

# Pull AWS Regions from environment variables

WKS_DESTINATION = boto3.client('workspaces', region_name=DESTINATION_REGION)
WKS_SOURCE = boto3.client('workspaces', region_name=SOURCE_REGION)

def collect_images():
        all_src_images = WKS_SOURCE.describe_workspace_images()
    except EndpointConnectionError:
        print(“Invalid SOURCE region, check environment variable”)

        all_des_images = WKS_DESTINATION.describe_workspace_images()
    except EndpointConnectionError:
        print(“Invalid DESTINATION region, check environment variable”)

    list_of_src_images = []
    list_of_des_images = []
    for src_img in all_src_images['Images']:
        # Keeping a dict of Name and ImageId for copy from source purposes.
        detail_src_images = {
            'Name': src_img['Name'],
            'ImageId': src_img['ImageId']
    for des_img in all_des_images['Images']:
        # We only keep the images names in the destination list because that's all we need.
    return(list_of_src_images, list_of_des_images)

def copy_wks_image(name, imgId):
        WKS_DESTINATION.copy_workspace_image(Name=name, Description='Copied with Lambda', SourceImageId=imgId, SourceRegion=SOURCE_REGION)
        print('Copying {} to {}...'.format(imgId, DESTINATION_REGION))
    except Exception as error:
        print('Copy Failed:', error)

def lambda_handler(event, context):
    # TODO implement
    source_images, destination_images = collect_images()

    # Loop through all source images.
    for source_img in source_images:
        # Check if the image exists in the destination region.
        if source_img['Name'] not in destination_images:
            # Copy the image!
            copy_wks_image(source_img['Name'], source_img['ImageId'])
            print('Nothing to copy from {} to {}.'.format(SOURCE_REGION, DESTINATION_REGION))

    return {
        'statusCode': 200,
        'body': json.dumps('Successful code')
  1. Select File → Save, and then click Deploy. If your organization has deployments of Amazon WorkSpaces in more than two AWS Regions, use this code to deploy AWS Lambda functions to the other Regions, and change the environment variables.

2.2 Environment variables

In this step, you define variables for the source and destination AWS Regions that the Lambda function will use to copy the Custom Images. The environment variables can be swapped to allow bidirectional custom image copy between two AWS Regions. CloudWatch Event rule targets must reside in the same AWS Regions as the rule itself. When creating this AWS Lambda function in other AWS Regions, matching CloudWatch Event rules must also exist in the same AWS Regions.

  1. Select the ‘Environment Variables‘ section.
  2. Choose Edit.
  3. Choose ‘Add environment variable.’
  4. Create an environment variable for the destination Region:


Value: [your destination Region value, for example us-west-2]

  1. Choose ‘Add environment variable.’
  2. Create an environment variable for the source Region:


Value: [your source Region value, for example, us-east-1]

  1. Choose ‘Save.’

Step 3: Scheduling your Lambda copy function

Launch Amazon CloudWatch from the AWS Management Console.

  1. Click Events → Rules, and then click ‘Create rule.’
  2. Choose ‘Schedule‘ in the Event Source section and enter the interval that you require using the drop-down to specify minutes, hours, or days.
  3. On the right side, click ‘Add target‘ and keep the default for Lambda.
  4. Select copyCustomWorkSpaceImage you created in Step 2 from the drop-down, and then choose ‘Configure details‘ to continue.
  5. Enter scheduledCustomWksImgCopy in the ‘Name’ field, optionally add a description.
  6. Choose ‘Create rule.’

You can learn more in the user guide about what is Amazon CloudWatch Events.

Step 4: Test function and view logs

This step validates the results of your work to make sure that the logs are created.

  1. Return to Lambda in the AWS Management Console and select the hyperlink for copyCustomWorkSpaceImage.
  2. Choose ‘Test‘ and select ‘Create new test event.’
  3. Provide an ‘Event name‘ and keep the event defaults.
  4. Choose ‘Create.’

Learn more about testing AWS Lambda functions.

Successful code results in status 200. Select the hyperlink for ‘(logs)’ to open a new tab, opening CloudWatch Logs to the LogGroup /aws/lambda/copyCustomWorkSpaceImage. Note the message that is logged between the rows for START and END. Python code is written to print all output to these logs, and if there is an error it will be displayed here. If a log group for your Lambda function was not created, review Step 1. Ensure that there is no syntax issue with the IAM policy, especially if the CloudWatch log group was explicitly defined in the Resources section.

If there is nothing to copy, this will be shown in the log. If there is something to copy, the log will show which Image Id is being copied to the destination Region. A metric filter can be created from the CloudWatch log and a subsequent CloudWatch Metric Alarm that will notify administrators using an Amazon Simple Notification Service (Amazon SNS) topic should the automation continually fail: for example, more than two times in a 24-hour period. For more information, review using Amazon CloudWatch alarms.

NOTE: For a more detailed view of the automation, in the destination AWS Region, an Amazon CloudWatch Event rule can be created for WorkSpaces API calls via AWS CloudTrail with a Target specified for a CloudWatch log group. Using CloudWatch Logs enables the search function with the following query:

{ $.detail.eventName = "CopyWorkspaceImage" }


In this blog, you automated copying Amazon WorkSpaces images between Regions. If you are new to AWS Lambda and Python, but familiar with serverless technologies, I hope you found this useful. I encourage you to build upon it for your organization.

How can I use this to help in a design for Disaster Recovery (DR)?

When designing your organization’s DR for Amazon WorkSpaces, consider the following:

  • Cross-Region redirection simplifies DR failover for your users. This is accomplished by creating a Public DNS Record that resolves the Amazon WorkSpaces registration code for the Amazon WorkSpaces client. The fully qualified domain name (FQDN) is used as the registration code.
  • Your organization may have to copy user persona and data to the DR (destination) AWS Region. How this is solved varies from organization to organization. For example, if your Amazon WorkSpaces deployment includes file and folder redirection to a Windows file share, you can use AWS DataSync with an Amazon FSx Windows file server.
  • If AWS Managed Microsoft Active Directory ‘Enterprise’ edition is the Amazon WorkSpaces directory in the primary AWS Region, it is recommended to use the multi-Region replication feature to the DR AWS Region. Otherwise, ensure that your Active Directory Connector is properly configured.
  • In your DR AWS Region, ensure that there is network connectivity and application access equality to all base infrastructure components that your production Amazon WorkSpaces use (for example, Active Directory, DNS, file servers, application servers, etc.).
  • Review the business continuity and DR with Amazon WorkSpaces blog for more information.

Let me know how it goes in the comments!