Desktop and Application Streaming
Automate copy of Amazon WorkSpaces tags to hybrid activation resources in AWS Systems Manager
AWS Systems Manager allows customers to manager their Amazon WorkSpaces using hybrid activation managed nodes. Systems Manager provides software inventories, OS patches, and configuration of Windows and Linux WorkSpaces, but it is difficult to identify and map managed node to the corresponding WorkSpaces without any tags. This is a time-consuming process in large organizations where IT Admins manually create these tags for each managed node in Systems Manager. This additional repetitive task leads to inconsistencies and wasted administrative time. The inconsistency in Systems Manager tags can lead to operational errors and other issues.
This blog describes how to implement an automation to copy tags from Amazon WorkSpaces to their corresponding managed node in Systems Manager, deployed using an AWS CloudFormation template.
Time to read | 15 minutes |
Time to complete | 5 minutes |
Learning level | Expert(400) |
Cost to complete (estimated) | $5 (can vary with interval rate) |
Services used | Amazon WorkSpaces AWS Systems Manager AWS CloudFormation AWS Lambda Amazon EventBridge |
Overview of solution
In this solution, we will demonstrate how you can reduce operational burden of manually creating tags for the WorkSpaces managed nodes. To implement this solution, you will use AWS CloudFormation to automatically configure all the required AWS services.
This solution uses Amazon EventBridge to invoke an AWS Lambda function on specified interval. The Lambda function then collects the WorkSpaces and managed nodes in Systems Manager. The Lambda Function matches both resources using the computer name, and then copies the tags of each WorkSpace to its matched managed node. In addition, the Lambda function creates the following tags for identification: Name, WorkspaceID, UserID, BundleID, DirectoryID, DirectoryName, and RegistrationCode.
Walkthrough
In this article, you will perform following activities:
- Use CloudFormation to deploy the solution to automatically copy WorkSpaces tags to their managed node in Systems Manager.
- Cleanup resources to prevent unwanted AWS usage charges.
Prerequisites
For this walkthrough, you need the following:
- An AWS account.
- An Amazon WorkSpaces deployment
- An AWS Systems Manager hybrid activation deployment.
- Permissions to create following service components:
- AWS Identity and Access Management (IAM) roles and policies
- AWS Lambda functions
- Amazon EventBridge rule
- Permissions to run AWS CloudFormation templates.
- Basic familiarity with AWS CloudFormation, AWS Systems Manager, Amazon WorkSpaces, and Amazon EventBridge.
Step 1: Deployment of solution via AWS CloudFormation
You will use the provided CloudFormation template to deploy and configure all the required AWS services of this solution. This template cannot be used for WorkSpaces and managed nodes in different accounts or AWS Regions. This deployment is Region specific, and must run in the AWS Region that contains your Amazon WorkSpaces and hybrid activated managed nodes.
Use the following steps to deploy the solution via AWS CloudFormation:
- Open a text editor on your local machine.
- Copy the below CloudFormation template to your text editor.
AWSTemplateFormatVersion: '2010-09-09' Description: >- This automation copies user tags from Amazon WorkSpace to AWS Systems Manager in the same account. It runs as a scheduled cron job in AWS EventBridge. Metadata: 'AWS::CloudFormation::Interface': ParameterGroups: - Label: default: IAM role Parameters: - IAMRoleName - Label: default: Lambda function Parameters: - LambdaFunctionName - Timeout - Architecture - Label: default: EventBrdige function Parameters: - EventBridgeRuleName - IntervalRate ParameterLabels: IAMRoleName: default: Provides name of IAM role LambdaFunctionName: default: Provides name of Lambda function Timeout: default: Timeout value of Lambda function Architecture: default: Architecture of Lambda function EventBridgeRuleName: default: Provides name of EventBridge function IntervalRate: default: Interval rate of EventBridge function Parameters: IntervalRate: Type: String Description: Interval rate of Amazon Event Bridge Rule. Default: rate(24 hours) EventBridgeRuleName: Type: String Description: >- Provide name of the Eventbridge rule. Name of the region will be added as suffix. Default: Rule-Automation-WS-Tags-Collector-And-Registrar LambdaFunctionName: Type: String Description: >- Provide name of the lambda function which will copy the tags from Amazon WorkSpaces to Systems Manager. Name of the region will be added as suffix. Default: Fn-Automation-WS-Tags-Collector-And-Registrar Architecture: Type: String Description: >- x86_64 is supported in all AWS Regions. arm64 costs less, but is not supported in all AWS Regions. Default: x86_64 AllowedValues: - arm64 - x86_64 Timeout: Type: Number Description: >- The amount of time (in seconds) that Lambda allows the function to run before stopping it. Default: 5 MinValue: 1 MaxValue: 900 ConstraintDescription: Must be an integer between 1 and 900. IAMRoleName: Type: String Description: >- Provide name of the IAM role used by Lambda function to perform task. Name of the region will be added as suffix. Default: Role-Automation-WS-Tags-Collector-And-Registrar Resources: cronWSTagsCollector: Type: 'AWS::Events::Rule' DependsOn: fnWSTagsCollector Properties: Name: !Sub - '${Name}-${AWS::Region}' - Name: !Ref EventBridgeRuleName ScheduleExpression: !Ref IntervalRate State: ENABLED Targets: - Arn: !GetAtt - fnWSTagsCollector - Arn Id: fnWSTagsCollector permCronForWSTagCollectorPermission: Type: 'AWS::Lambda::Permission' DependsOn: fnWSTagsCollector Properties: Action: 'lambda:InvokeFunction' FunctionName: !GetAtt - fnWSTagsCollector - Arn Principal: events.amazonaws.com rWSTagsCollectorRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub - '${Name}-${AWS::Region}' - Name: !Ref IAMRoleName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: /aws/ Policies: - PolicyName: LambdaInvoke PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'lambda:InvokeFunction' Resource: !Sub 'arn:${AWS::Partition}:lambda:${AWS::Region}:${AWS::AccountId}:function:*' - PolicyName: LogCreation PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'logs:CreateLogGroup' - 'logs:CreateLogStream' - 'logs:PutLogEvents' Resource: !Sub 'arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:*' - PolicyName: WorkspaceDescribe PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'workspaces:DescribeWorkspaces' - 'workspaces:DescribeTags' Resource: - !Sub 'arn:${AWS::Partition}:workspaces:${AWS::Region}:${AWS::AccountId}:workspace/*' - Effect: Allow Action: - 'workspaces:DescribeWorkspaceDirectories' Resource: - !Sub 'arn:${AWS::Partition}:workspaces:${AWS::Region}:${AWS::AccountId}:directory/*' - PolicyName: SSMTagPolicy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'ssm:AddTagsToResource' - 'ssm:ListTagsForResource' Resource: !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:managed-instance/*' - Effect: Allow Action: - 'ssm:DescribeInstanceInformation' Resource: !Sub 'arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:*' fnWSTagsCollector: Type: 'AWS::Lambda::Function' Properties: FunctionName: !Sub - '${Name}-${AWS::Region}' - Name: !Ref LambdaFunctionName Handler: index.lambda_handler Architectures: - !Ref Architecture ReservedConcurrentExecutions: 1 Role: !GetAtt - rWSTagsCollectorRole - Arn Code: ZipFile: !Sub |+ """ Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. SPDX-License-Identifier: MIT-0 Collects tags from the Amazon WorkSpaces and assign the same tags to managed instances in AWS Systems Manager. """ import logging import boto3 LOGGER = logging.getLogger() LOGGER.setLevel(logging.INFO) #defines the connections for Workspaces and SSM agent CLIENT = boto3.client('workspaces') SSMCLIENT = boto3.client('ssm') def lambda_handler(event, context): """declare global variables""" ssm_data = [] workspaces_data = [] ds_data = [] tag_data = [] #Collecting the information about directories dscollection = CLIENT.describe_workspace_directories() LOGGER.info(dscollection) while dscollection: ds_data += dscollection['Directories'] dscollection = CLIENT.describe_workspace_directories( NextToken=dscollection['NextToken']) if 'NextToken' in dscollection else None #Collecting the information of SSM managed instances ssmcollection = SSMCLIENT.describe_instance_information() LOGGER.info(ssmcollection) while ssmcollection: ssm_data += ssmcollection['InstanceInformationList'] ssmcollection = SSMCLIENT.describe_instance_information( NextToken=ssmcollection['NextToken']) if 'NextToken' in ssmcollection else None #Collecting the information of WorkSpaces wscollection = CLIENT.describe_workspaces() while wscollection: workspaces_data += wscollection['Workspaces'] wscollection = CLIENT.describe_workspaces( NextToken=wscollection['NextToken']) if 'NextToken' in wscollection else None for ssminfo in ssm_data: if 'ComputerName' in ssminfo and 'mi-' in ssminfo['InstanceId']: for workspace in workspaces_data: if workspace['ComputerName'] in ssminfo['ComputerName']: #name_id = workspace['ComputerName'] #workspace_id = workspace['WorkspaceId'] #user_id = workspace['UserName'] #bundle_id = workspace['BundleId'] LOGGER.info("Running Task for:") LOGGER.info(workspace['WorkspaceId']) tags = CLIENT.describe_tags(ResourceId=workspace['WorkspaceId']) tag_data += tags['TagList'] LOGGER.info(tag_data) for taginfo in tag_data: SSMCLIENT.add_tags_to_resource( ResourceType='ManagedInstance', ResourceId=ssminfo['InstanceId'], Tags=[taginfo]) tag_data = [] for ds_id in ds_data: if ds_id['DirectoryId'] == workspace['DirectoryId']: #directory_id = ds_id['DirectoryId'] #directory_name = ds_id['DirectoryName'] #registration_code = ds_id['RegistrationCode'] SSMCLIENT.add_tags_to_resource( ResourceType='ManagedInstance', ResourceId=ssminfo['InstanceId'], Tags=[ { 'Key': 'DirectoryID', 'Value': ds_id['DirectoryId'] }, { 'Key': 'DirectoryName', 'Value': ds_id['DirectoryName'] }, { 'Key': 'RegistrationCode', 'Value': ds_id['RegistrationCode'] }, ]) SSMCLIENT.add_tags_to_resource( ResourceType='ManagedInstance', ResourceId=ssminfo['InstanceId'], Tags=[ { 'Key': 'Name', 'Value': workspace['ComputerName'] }, { 'Key': 'WorkspaceID', 'Value': workspace['WorkspaceId'] }, { 'Key': 'UserID', 'Value': workspace['UserName'] }, { 'Key': 'BundleID', 'Value': workspace['BundleId'] }, ]) Runtime: python3.11 Timeout: !Ref Timeout
- Save notepad file with YAML file extension.(<filename>.yaml).
- Open the AWS CloudFormation console.
- Select the AWS Region of your WorkSpaces deployment.
- In the navigation pane, choose Stacks.
- Choose Create stack, then choose With new resources (standard).
- On the Create stack page, select Upload a Template File.
- Select Choose File, choose template file that you saved in step 3.
- Choose Next.
- In the Stack name section, enter a stack name.
- In the Parameters section, enter the following values:
- For EventBridgeRuleName, enter a unique name for the EventBridge rule.
- For IAMRoleName, enter a unique name for the IAM Role.
- For IntervalRate, enter an interval rate in the Rate Expression format. Amazon EventBridge will run this automation at interval rate specified.
- For LambdaFunctionName, enter a unique name for the Lambda function.
- Choose Next
- On the Configure stack options page, leave all the defaults, and choose Next.
- Review the configuration options and acknowledge the IAM checkbox.
- Choose Submit.
- Verify that the stack has a status of CREATE_COMPLETE.
The stack deploys in approximately 2 minutes and creates the following resources:
- AWS Lambda function
- Amazon EventBridge Rule
- IAM Role
Step 2: Validate the creation of new Tags for hybrid activated managed node in AWS Systems Manager.
You now have an Amazon EventBridge Rule and AWS Lambda function configured. Tags are created for the managed nodes after the interval specified during the creation of the AWS CloudFormation Stack. Use the following steps to validate the tags in Systems Manager:
- Open the AWS Systems Manager console.
- Select the AWS Region of your managed nodes.
- In the navigation pane, choose Fleet Manager from Node Management.
- Select any of the Managed Nodes created for WorkSpaces.
- Verify the created tags in Tags section.
Cleaning up
It is important to clean up unused resource to avoid unexpected usage fees. To clean up the environment, delete AWS CloudFormation stacks you created in the walkthrough. Deletion of AWS CloudFormation will delete Lambda function, EventBridge rules and associated IAM roles. You must manually delete the tags created for managed nodes in Systems Manager via console or API.
Conclusion
In this blog, you configured Amazon EventBridge with AWS Lambda functions to automatically copy AWS WorkSpace’s tags to their corresponding Systems Manager managed nodes.
To learn more about Amazon WorkSpaces, please review the administration guide. You can get more information about hybrid activation in AWS Systems Manager using this link.
If you would like to discuss how to configure this solution described in this blog for your specific use case, we would love to hear from you. Please reach out to your account team.
-
Ajay Saini is a End User Compute Specialist Solution Architect. He works with his customer to help them understand the best practices, accelerate their architecture design, migrate and modernize their existing Virtual Desktop Infrastructure (VDI) to AWS. In his spare time, he enjoys travel and spending time with his family Brandon Mahtani is an EUC Specialist Solutions Architect who joined AWS in December of 2018 with over 20 years experience deploying desktop virtualization solutions within Higher Education as well as the Life Sciences industries.