Desktop and Application Streaming
Use Amazon CloudWatch Events with Amazon WorkSpaces and AWS Lambda for greater fleet visibility
Amazon WorkSpaces is a managed, secure cloud desktop service. You can use Amazon WorkSpaces to provision either Windows or Linux desktops, and quickly scale to provide thousands of desktops to workers across the globe. With Amazon WorkSpaces, users can connect securely from anywhere using a software client or a supported web browser. Administrators have full control of the platforms their users can connect from, and any additional factors that are needed. They also have access to 11 Amazon CloudWatch metrics in two dimensions providing visibility into their Amazon WorkSpaces fleets. For more information about these metrics, see Monitor Your WorkSpaces Using CloudWatch Metrics.
In this post, we log all successful Amazon WorkSpaces connections in an AWS Region by using two recent releases: Amazon CloudWatch Events for Amazon WorkSpaces and PowerShell Core 6.0 for AWS Lambda. For each connection, we use the AWS Tools for PowerShell to retrieve additional data about the target WorkSpaces, and geolocation data about the connection. We then store this data in Amazon DynamoDB, where we can perform a query at any time.
Prerequisites
To follow the steps in this post, you need the following:
- A virtual private cloud (VPC) with at least one private subnet, and internet access.
- Access to AWS Identity and Access Management (IAM), with permissions to create roles.
- An IAM user with programmatic access, and permissions to create new Lambda functions.
- AWS Tools for Windows PowerShell or AWS Tools for PowerShell Core.
- The AWSPowerShell.NetCore PowerShellModule.
- The AWSLambdaPSCore module PowerShell Module.
- .NET Core 2.1 SDK installed.
- An account with ipinfo.io or another service that provides a geolocation API.
Step 1: Create an IAM role for your Lambda function
To grant our Lambda function permissions to access multiple services, create a role and a policy in IAM by doing the following:
- Open the IAM console at https://console.aws.amazon.com/iam/
- In the navigation pane, choose Roles.
- Choose Create Role.
- Select AWS Service, Lambda.
- Choose Next: Permissions.
- In the filter dialog box, enter AWS Lambda.
- Select AWSLambdaExecute and AWSLambdaVPCAccessExecutionRole.
- Choose Next: Tags.
- Choose Next: Review.
- Provide a name and description for your role.
- Choose Create role.
- Open the service role that you just created.
- Choose the Permissions tab, then choose Add inline policy.
- Choose the JSON tab.
- Enter the following syntax. For the highlighted portion in the syntax, change the 123456789012:table to the AWS account number this is to be deployed in. Change wsaccess to match the name of the DynamoDB table, which you create in the next step, Create your DynamoDB table.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"workspaces:DescribeWorkspacesConnectionStatus",
"dynamodb:ListTables",
"workspaces:DescribeWorkspaces"
],
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:PutItem",
"dynamodb:DescribeTable",
"dynamodb:GetItem",
"dynamodb:UpdateItem"
],
"Resource": "arn:aws:dynamodb:*:123456789012:table/wsaccess"
}
]
}
16. Choose Review policy.
17. Provide a name for your policy.
18. Choose Create policy.
Step 2: Create your DynamoDB table
In this step, we use Amazon DynamoDB as the central repository for all connection events. This lets administrators query and visualize connection patterns for a given IP, user, workspace ID, and more.
We use a table with a primary sort key. This lets us have multiple unique entries with the same primary partition key, which in our case, is workspaceId. The sort key is a timestamp of the login date and time.
Create a new DynamoDB table by doing the following:
- Open the DynamoDB console at https://console.aws.amazon.com/dynamodb/
- In the navigation pane, choose Tables.
- Choose Create table.
- In the Create DynamoDB Table screen:
- Name your table; for example, wsaccess.
- For Primary Partition Key, enter workspaceId. Keep String as the default entry.
- Choose Add sort key.
- For Sort key, enter loginTime. Keep String as the default entry.
- Choose Create.
Note
If you want to deploy this solution in multiple AWS Regions, add the Regions on the Global Tables tab before implementing.
Step 3: Create your Lambda function
In this step, we create the Lambda function that will run at each login.
Create the job by doing the following:
- Open your PowerShell editor of choice, and create a new script, naming it something like wsaccess-lambda.ps1.
- Enter the following code:
#Requires -Modules @{ModuleName='AWSPowerShell.NetCore';ModuleVersion='3.3.343.0'}
# Defaults
$region = "us-east-1"
$tableName = $env:tableName
# Functions
function Put-DDBItem{
param (
[string]$tableName,
$inputobj
)
$req = New-Object Amazon.DynamoDBv2.Model.PutItemRequest
$req.TableName = $tableName
$req.Item = New-Object 'system.collections.generic.dictionary[string,Amazon.DynamoDBv2.Model.AttributeValue]'
foreach($item in $inputobj.keys){
$valObj = New-Object Amazon.DynamoDBv2.Model.AttributeValue
$valObj.S = $inputobj[$item]
$req.Item.Add($item, $valObj)
}
$dbClient.PutItemAsync($req)
}
# Find Dynamo DLL
$modulepath = get-module AWSPowerShell.NetCore |Select-Object -ExpandProperty Path |Split-Path
$dllPath = ls "$modulepath/AWSSDK.DynamoDBv2.dll"
# Enable DynamoDB class
Add-Type -Path $dllPath
# Create Dynamo Client
$regionEndpoint=[Amazon.RegionEndPoint]::GetBySystemName($region)
$dbClient = New-Object Amazon.DynamoDBv2.AmazonDynamoDBClient($regionEndpoint)
#Capture Geo Data
$ipAddress = $LambdaInput.detail.clientIpAddress
$ipLocations = $null
$ipLocations = Invoke-RestMethod http://ipinfo.io/$ipAddress/json/
# Workspace Details
$wksDetails = Get-WKSWorkspace -WorkspaceId $($LambdaInput.detail.workspaceId)
# Create hash object to upload to Dynamo
$data = @{
account = $LambdaInput.account;
region = $LambdaInput.region;
clientIpAddress = $ipAddress;
actionType = $LambdaInput.detail.actionType;
workspacesClientProductName = $LambdaInput.detail.workspacesClientProductName;
loginTime = $LambdaInput.detail.loginTime; #returns UTC
clientPlatform = $LambdaInput.detail.clientPlatform;
directoryId = ($LambdaInput.detail.directoryId).tostring().split("/")[1]
workspaceId = $LambdaInput.detail.workspaceId;
username = $wksDetails.UserName;
computername = $wksDetails.ComputerName;
hostname = $ipLocations.hostname;
city = $ipLocations.city;
state = $ipLocations.region;
county = $ipLocations.country;
org = $ipLocations.org;
location = $ipLocations.loc
}
# Create DynamoDB entry
Put-DDBItem -tableName $tableName -input $data
3. Open a PowerShell terminal.
4. Import the AWSLambdaPSCore module by typing the following:
Import-Module AWSLambdaPSCore
5. Create a new Lambda job from your code by typing the following:
Publish-AWSPowerShellLambda -ScriptPath .\wsaccess-lambda.ps1 -Name wsaccess-lambda -Region us-east-1
6. When prompted, select the IAM role that you created earlier in Step 1.
Step 4: Create a new EC2 Security Group
The Lambda function above will have access to your VPC. To control access to and from the instances we will create a security group.
Create a new EC2 security group by doing the following:
- Open the EC2 console at https://console.aws.amazon.com/ec2/.
- Under Network & Security, from the section menu on the left, select Security Groups.
- Choose Create Security Group.
- Enter a name and description for the new group.
- Select the VPC to use for the Lambda function.
- Choose Create.
Step 5: Modify your Lambda function
The Lambda function above uses Environment Variables to identify the DynamoDB table it should write to. It also uses you VPC to access the geolocation api. In this section we will modify the Lambda function configuration to allow these.
Modify your Lambda job by doing the following:
- Open the Lambda console at https://console.aws.amazon.com/lambda/.
- Select the function that you just created.
- Go to the Environment variables section.
- Create a new environment variable, and name it tableName.
- Change the value for tableName to name of the table that you created earlier in Step 2.
- Go to the VPC section.
- Select a VPC that has internet access.
- Select at least one subnet in the VPC that has a route to the internet. Preferably, use two subnets.
- Select the security group that you created earlier in Step 4.
Step 6: Create an event listener in CloudWatch
Now that the Lambda function is configured, CloudWatch must be configured to trigger the function at each login.
- Open the CloudWatch console at https://console.aws.amazon.com/cloudwatch/.
- In the navigation pane, choose Events.
- Choose Create rule.
- For Event Source, do the following:
- Choose Event Pattern. Keep Build event pattern to match events by service as the default.
- For Service Name, choose WorkSpaces.
- For Event Type, choose WorkSpaces Access.
- For Targets, choose Add target, then choose the service that is to act when an Amazon WorkSpaces event is detected. Provide any information required by this service.
- Choose Configure details. For Rule definition, type a name and description.
- Choose Create rule.
For more information about CloudWatch events for Amazon WorkSpaces, see Monitor Your WorkSpaces Using CloudWatch Events.
Conclusion
In this post, we created a job to combine telemetry data, provided by the WorkSpaces service, with geographic information and details from the WorkSpaces API operation. With this job in place, we now have a record of when and from where users are connecting to their Amazon WorkSpaces.