AWS Security Blog

How to use Amazon AppStream 2.0 to reduce your bastion host attack surface

To help protect their assets, many security-conscious enterprises require their system administrators to go through a “bastion” (or “jump”) host to gain administrative access to backend systems in protected or sensitive network segments.

A bastion host is a special-purpose instance that hosts a minimal number of administrative applications, such as RDP for Windows or Putty for Linux-based distributions. All other unnecessary services are removed. The host is typically placed in a segregated network (or “DMZ”), and is often protected with multi-factor authentication (MFA) and monitored with auditing tools. And most enterprises require that the access trail to the bastion host be auditable.

In this post, I demonstrate the use of Amazon AppStream 2.0 as a hardened and auto-scaled bastion host solution, and show how it could reduce the attack surface by stripping away the underlying OS and exposing only the necessary tools to system administrators that need access to protected network segments.

Prerequisites

  • A Virtual Private Cloud (VPC) with a dedicated subnet for AppStream 2.0.
  • An existing Active Directory (AD) domain. This may be on premises, on AWS EC2 for Windows, or AWS Directory Service for Microsoft Active Directory used as a user directory.
  • Active Directory Federation Services (ADFS).
  • A Linux or Windows instance for which AppStream 2.0 will be acting as a bastion host.

Solution overview

Amazon AppStream 2.0 is a fully managed application streaming service that provides users instant access to their desktop applications from anywhere by using an HTML5-compatible desktop browser. When a user requests access to an application, AppStream 2.0 uses a base image to deploy a streaming instance and destroys the instance after the user closes their session. This ensures the same consistent experience during each logon.

You can use AppStream 2.0 as a bastion solution to enable your system administrators to manage their environment without giving them a full bastion host. Because AppStream 2.0 freshly builds instances each time a user requests access, a compromised instance will only last for the duration of a user session. As soon as the user closes their session and the Disconnect Timeout period is reached, AppStream 2.0 terminates the instance and, with it, you’ve reduced your risks of compromised instances.

You will also potentially reduce your costs because AppStream 2.0 has built-in auto-scaling to increase and decrease capacity based on user demand. It allows you to take advantage of the pay-as-you-go model, where you only pay for what you use.

High-level AppStream 2.0 architecture

The diagram below depicts a high-level AppStream 2.0 architecture used as a bastion host for servers in another VPC.

There are three VPCs shown: AppStream 2.0 VPC, Bastion host VPC, and application VPC. The AppStream 2.0 VPC is an AWS-owned VPC where the AppStream 2.0 maintains its infrastructure. Customers are not responsible for this VPC and have no access to it. AppStream 2.0 builds each streaming instance with two Elastic Network Interfaces (ENI); one in the AppStream 2.0 VPC and one in the VPC where you choose to deploy your AppStream 2.0 instances. The third VPC is the application VPC where you would typically keep your backend servers.

The diagram also depicts the end-user process to access the AppStream 2.0 environment, which works as follow:

  1. Using an HTML5 desktop browser the user logs on to a Single Sign-On URL. This authenticates the user against the corporate directory using SAML 2.0 federation and with optional MFA.
  2. After successful authentication, the user will see a list of provisioned applications.
  3. The user can launch applications, such as RDP and Putty, which are only visible within the browser and with its underlying OS hidden. The user is then able to connect to the backend systems over the ports that were opened through security groups. The user logs off and AppStream 2.0 destroys the instance used for the session.

 

Architecture diagram

Figure 1: Architecture diagram

Step-by-step instructions

This walk-through assumes you have created the following resources as prerequisites.

  • A single VPC with a /23 CIDR range and two private subnets in two AZs.

    Note: “private” subnet refers to a subnet that has no internet gateway (IGW) attached.

    • Bastion Subnets — used for the AppStream 2.0 instances that will be hosting the bastion applications.
    • Apps Subnets — used for the servers for which the AppStream 2.0 instances will be acting as a bastion host.
       
      Screen shot of bastion and apps subnets

      Figure 2: Screen shot of bastion and apps subnets

  • A peering connection to a VPC where the corporate Active Directory resides and with updated routing tables. This is only necessary if your AD resides in a different VPC.
  • Two EC2 instances with private IP addresses in the app subnet.

Phase 1: Create the DHCP Options Set

For the AppStream 2.0 instances to be able to join the corporate domain, they need to have their DNS entries point to the corporate domain controller(s). To accomplish this, you need to create a DHCP Options Set and assign it to the VPC:

  1. Sign in to the AWS console, and then select VPC Dashboard > DHCP Option Sets > Create DHCP options set.
  2. Give the DHCP Options Set a name, enter the domain name and DNS server(s) of your corporate domain controller(s), and then select Yes, Create.
  3. Select your VPC Dashboard > your VPC > Actions > Edit DHCP Options Set.
  4. Select the DHCP Options Set created in the previous step, and then select Save.
     
    The "Edit DHCP Options Set" dialog

    Figure 3: The “Edit DHCP Options Set” dialog

Phase 2: Create the AppStream 2.0 Stack

An AppStream 2.0 stack consists of a fleet, user access policies, and storage configuration. To create a stack, follow these steps:

  1. Sign in to the AWS console and select AppStream 2.0 > Stack > Create Stack.
  2. Give the stack a name, and then select Next.
  3. Enable Home Folders, if you want persistent storage, and then select Review.
     
    The "Enable Home Folders" dialog

    Figure 4: The “Enable Home Folders” dialog

  4. Select Create.

Phase 3: Create the AppsStream 2.0 Directory Configuration

First create a directory configuration so you can join the AppStream 2.0 instances to an Organizational Unit (OU) in your corporate directory.

Note: AppStream 2.0 instances must be placed in an OU and can’t reside in the Computer Container.

To create a directory configuration, follow these steps:

  1. Sign in to the AWS console and select AppStream 2.0 > Directory Configs > Create Directory Config.
  2. Enter the following Directory Config information:
    • Directory name: The FQDN of your corporate domain.
    • Service Account Name: The account AppStream 2.0 uses to join the instances to the corporate domain. The required service account privileges are documented here.
    • Organizational Unit (OU): The OUs where AppStream 2.0 will create your instances. You can add additional OUs by clicking the plus (+) sign.
  3. Select Next, and then select Create.

Create Security Groups

Now, create AWS security groups for your AppStream 2.0 instances and backend servers.

BastionHostSecurityGroup

For your AppStream 2.0 instances, you must attach a “BastionHostSecurityGroup” in order to communicate to the backend servers. This security group is only used as a “source” by the security groups the backend servers are attached to and, therefore, they don’t require any inbound ports to be opened.

To create a security group, follow these steps:

  1. Sign in to the AWS console and select VPC > Security Groups > Create Security Group.
  2. Give your “BastionHostSecurityGroup” Security Group a name, select the VPC where you will place the AppStream 2.0 instances, and then select Yes, Create.

BastionHostAccessSecurityGroup

For your backend servers, you must attach a “BastionHostAccessSecurityGroup” that allows incoming traffic from the AppStream 2.0 instance. Unlike the “BastionHostSecurityGroup”, this one requires open inbound ports.

  1. Sign in to the AWS console and select VPC > Security Groups > Create Security Group.
  2. Give your “BastionHostAccessSecurityGroup” security group a name, select the correct VPC, and then select Yes, Create.
  3. In the Security Group console, select the newly created security group, select the Inbound Rule tab, and then select Edit.
  4. Add rules to open port 3389 and 22, use the previously-created security group as the source, and then select Save.
     
    Opening ports 3389 and 22

    Figure 5: Opening ports 3389 and 22

    Note: In addition to security groups, you can place Network ACLs (NACLs) around the subnet you use for AppStream 2.0 as an additional layer of security. The main differences between security groups and NACLs are that security groups are mandatory and you apply them to the instance level, while you apply NACLs to the subnet level and are optional. Another difference worth pointing out is that NACLs are “stateless” while security groups are “stateful.” This means that any port allowed inbound via NACLs will need a corresponding outbound rule. For more information on NACLs, refer to this documentation.

Phase 4: Build the AppStream 2.0 Image

An AppStream 2.0 image contains applications that you can stream to users. AppStream 2.0 uses the image to launch streaming instances that are part of an AppStream 2.0 fleet.

Once you have created the stack, create a custom image to make custom applications available to the users:

  1. Sign in to the AWS console and select AppStream 2.0 > Images > Image Builder > Launch Image Builder.
  2. Choose the image you want to use as a starting point, and then select Next. For this example, I chose a generic image from the General Purpose stock.
     
    Choosing an image

    Figure 6: Choosing an image

  3. Give your image a name, choose the instance family, and then select Next.
  4. Choose the VPC and subnet you want to deploy the AppStream 2.0 instances in.
  5. Select the security group you created for the AppStream 2.0 instances.
  6. Select the directory configuration you created, the OU you want your AppStream 2.0 instances to reside in, and then select Review.
  7. Select Launch.
  8. Once the image is built and in a running state, select the image, and then select Connect. This will open a new browser tab where you’ll be able to connect to and manage the image.
  9. Select Administrator and log in.
     
    Log in as a local administrator

    Figure 7: Log in as a local administrator

  10. Once logged in as administrator, select the Image Assistant shortcut on the desktop.
     
    The Image Assistant shortcut on the desktop

    Figure 8: The Image Assistant shortcut on the desktop

  11. Add all the applications you want to make available to your users for streaming, and then select Next.

    Note: If you need to upload installation or configuration files, you can use the My Files option in the Control menu. Any files uploaded through this method will show up under the X: drive on the Image Builder.

     

    The "Control" menu

    Figure 9: The “Control” menu

  12. If you want to test the applications as a non-privileged user, follow the on-screen instructions to switch the user. Otherwise, select Next.
     
    "Switch User" on-screen instructions

    Figure 10: “Switch User” on-screen instructions

  13. Select Launch to have the Image Assistant optimize the applications.
  14. Give the image a name, and then select Next.
  15. Select Disconnect and Create Image.
  16. Go back to the AppStream 2.0 console and wait for the “snapshotting” to complete and for the image to be in an available state before continuing to the next step.

Phase 5: Create the AppStream 2.0 Fleet

Once you create your Stack and image, you need to create a Fleet and associate it with your Stack.

AppStream 2.0 fleets consist of streaming instances that run the image that you specify. The fleet type determines when your instances run and how you pay for them. You can specify a fleet type when you create a fleet, and you can’t change them once they’ve been created.

To create a fleet, follow these steps:

  1. Sign in to the AWS console and select AppStream 2.0 > Fleets > Create Fleet.
  2. Give your fleet a name, and then select Next.
  3. Select the newly created image, and then select Next.
  4. Choose your preferred settings, and then select Next.

    Important: Pay special attention to the Fleet capacity value. Fleet capacity determines the number of running instances you have at any given time, and it affects your costs.

     

    The "Fleet capacity" dialog

    Figure 11: The “Fleet capacity” dialog

  5. Select your VPC, subnet(s), security Group(s), Active Directory settings, and then select Next.
  6. Review the information, and then select Create.
     
    Review your settings

    Figure 12: Review your settings

Associate the fleet with the stack

Follow these steps:

  1. Sign in to the AWS console and select AppStream 2.0 > Stacks.
  2. Select the stack, select Actions, and then select Associate Fleet.
  3. Select the fleet, and then select Associate.

Phase 6: Configure ADFS for AppStream 2.0

To have users authenticate against the corporate directory prior to accessing AppStream 2.0, use a Single Sign-On solution. For this demo, I use ADFS. If you choose another solution, follow the instructions that come with the solution. For help with setting up ADFS with AppStream 2.0, review Enabling Identify Federation with ADSF and Amazon Appstream 2.0.

Note: If you use AWS Directory Service for Microsoft AD (AWS Managed Microsoft AD) as your user directory, you can use ADFS by following the ADFS set-up instructions in the blog on How to Enable Your Users to Access Office 365 with AWS Managed Microsoft AD Credentials.

End User Experience

This section shows you what the AppStream 2.0 end user experience is like when connecting to backend Windows and Linux instances.

Note: Make sure you have backend servers to connect to, as indicated in the prerequisites.

Process

  1. Access the ADFS URL that you created as part of the ADFS setup.
  2. Sign in using your corporate credentials.
  3. Select Remote Desktop from the list of applications.
  4. Enter your corporate credentials.
  5. Enter the private IP address of the backend windows instance you want to remote in to.
     
    Enter the private IP address

    Figure 13: Enter the private IP address


    You’re now logged on to the backend Windows instance through AppStream 2.0.
  6. To test in Linux, open putty. Select the Launch app icon in the Control menu, and then select putty.
     
    The "Control" menu showing putty

    Figure 14: The “Control” menu showing putty

  7. Provide the private IP address of a backend Linux host you want to connect to, and then select Open.

    Note: For putty to connect to a Linux instance on AWS, you will need to provide a KeyPair. For information on how to configure putty and KeyPairs, refer to this documentation.

You’re now logged on to a backend Linux host through AppStream 2.0.

Monitoring

You can monitor AppStream 2.0 use by default with the following AWS monitoring services.

  • Amazon CloudWatch is a monitoring service for AWS cloud resources. You can use CloudWatch to collect and track metrics, collect and monitor log files, set alarms, and automatically react to changes in your AWS resources. For more information, refer to this documentation. Here’s a sample CloudWatch metric showing in-use capacity was 100% at 14:30, which indicates the Fleet capacity may need to be adjusted.
     
    An example CoudWatch metric

    Figure 15: An example CloudWatch metric

  • AWS CloudTrail is a service that enables governance, compliance, operational auditing, and risk auditing of your AWS account. With CloudTrail, you can log, continuously monitor, and retain account activity related to actions across your AWS infrastructure. For more information, refer to this documentation. Here’s a sample CloudTrail event. For example, from this event you can see that user Bob logged on to AppStream 2.0 on March 4, 2018, and you can see his source IP.
     
    An example CloudTrail event

    Figure 16: An example CloudTrail event

Summary

Amazon AppStream 2.0 is a cost-effective way to provide administrators with a secure and auditable method to access their backend environments.

The AppStream 2.0 built-in auto-scaling feature offers a pay-as-you-go model, where the number of instances running is based on user demand. This allows you to keep costs down without compromising availability. Another cost-saving benefit of AppStream 2.0 is its underlying infrastructure being managed and maintained by AWS, so you can deploy AppStream 2.0 with minimal effort.

AppStream 2.0 helps with reducing the attack surface by hiding the shell of the streaming OS. This prevents administrators from interacting with executables that haven’t been made available to them through AppStream 2.0.

Another security benefit of AppStream 2.0 is that it destroys streaming instances after each use, reducing risks. This is a good mitigation strategy against compromised instances, as the lifespan of an instance is limited to the length of a user’s session.

AppStream 2.0 support for SAML provides yet another layer of security, allowing you to restrict access to SAML-federated URLs from corporate networks only, as well as the ability to enforce multi-factor authentication (MFA).

You can monitor the AppStream 2.0 environment through the use of AWS CloudTrail and Amazon CloudWatch, allowing you to monitor and trace the usage of AppStream 2.0.

For all of these reasons, AppStream 2.0 makes for a uniquely attractive bastion host solution.

For more information on the technologies mentioned in this blog, see the links below:

If you have comments about this post, submit them in the Comments section below. If you have questions about anything in this post, start a new thread on the Amazon AppStream 2.0 forum or contact AWS Support.

Want more AWS Security news? Follow us on Twitter.