Desktop and Application Streaming

Design considerations in highly regulated environments for Certificate Based Authentication with AppStream 2.0 and WorkSpaces

Increasingly organizations are standardizing on SAML 2.0 Identity Providers such as AWS IAM Identity Center and OKTA as their identity solution to access end user computing (EUC) services in AWS. With Certificate-based authentication (CBA), organizations can provide seamless authentication for our EUC services. Traditionally, the logon experience to a virtual desktop works by using the provided username & password during the sign-on process to logon to Windows. When SAML is used for the initial authentication, the operating system never receives the credentials provided to the SAML provider. This is because Windows Active Directory (AD) Domain Controllers natively do not understand SAML and another feature, CBA, is required to provide single sign-on to the operating system. Without CBA, users are prompted for their password again to complete the logon process when using SAML. CBA removes this additional password prompt by performing a certificate-based logon using a virtual smartcard.

When designing a solution using CBA, AWS understands some organizations adhere to more stringent regulations that require them to operate in regions such as AWS GovCloud. Standardizing on AWS GovCloud allows organizations to inherit security controls and use native AWS services that meet their required compliance standards. These organizations must also be able to understand and articulate the security related design decisions to complete audit reviews more deeply. In this blog, I will discuss some of the design considerations that have arisen when working with customers implementing CBA in highly regulated environments. Of course, all organizations may use the design considerations in this blog to make the best-informed decisions for their Amazon AppStream 2.0 or Amazon WorkSpaces deployment. The topics discussed include:

  • Explaining why you need Certificate Revocation Lists (CRL) when using CBA.
  • Alternatives for hosting the CRL file besides using AWS CloudFront, which is the default recommended option. Highly regulated industries may not be able to use CloudFront since it is not available on AWS GovCloud.
  • Situations where physical smartcards and CBA function together to enhance the user experience.


The architecture below provides an overview of the environment that was used to validate the solutions discussed in this blog. It’s typical that the AppStream 2.0 provisioned fleet instances are in a separate VPC from the infrastructure components such as Windows AD Domain Controllers. Communication is made possible with an AWS Transit Gateway providing routing between all services. In the architecture, the Application Load Balancer (ALB) has an Elastic Network Interfaces (ENI) placed in the infrastructure VPC. This allows the ALB to be accessed from both the infrastructure and AppStream 2.0 VPCs. AWS Private CA service is responsible for generating the certificates required for the CBA feature. All components for the solution must be placed in the same AWS Account for it to function. This architecture is the same for both AWS Commercial and AWS GovCloud regions. For the purposes of example in this blog, AWS GovCloud is used. To allow the solution to work in AWS Commercial regions the ARN value should be modified from “aws-us-gov” to “arn:aws”.

For detailed steps on CBA configuration, be sure to read these blogs: How to configure certificate-based authentication for Amazon AppStream 2.0 and How to configure certificate-based authentication for Amazon WorkSpaces.

Diagram of an example AppStream 2.0 architecture with the CRL file being front-ended by AWS Lambda and an Application Load Balancer. It includes multiple VPCs that separate the infrastructure components such as Active Directory and the AppStream 2.0 virtual desktops.

Figure 1. Architecture with the ALB and Lambda CRL solution

Why is a Certificate Revocation List (CRL) Needed?

Typically, CRLs would be an integral piece of security for smartcard logons to webservers and other systems such as Windows desktops. If you have unfamiliar with CRLs, they are cryptographically signed files that provide a list of certificates that have been invalidated by the issuing certificate authority (CA). The certificates that CRLs invalidate are commonly long-lived certificates such as those placed on physical devices that cannot easily be updated. However, AWS Private CA provides an ephemeral “short-lived” certificate for smartcard logons that is valid for one day. With short-lived certificates, AWS does not even recommend using Certificate Revocation Lists (CRLs).

While not using a CRL would seem to be the answer, using a CRL for smartcard logons is activated by default on Windows. Windows does not understand the difference between short- and long-lived certificates for smartcard logons so it treats them all the same. Windows does provide the ability to deactivate CRL validation via registry keys, however the updates must be implemented on both the virtual desktops and Domain Controllers. Disabling CRL validation is not recommended as the Domain Controllers may provide services to other use cases outside of AppStream 2.0 and WorkSpaces. Now that I cleared that up, where should you store the CRL?

How to Host the CRL Securely when not using CloudFront

You may have already read another AWS blog that discusses using CloudFront to host the CRL when leveraging CBA. While this is a great option, using CloudFront may not be the optimal solution for your organization. Before I get into the other options available, let’s first discuss how AWS Private CA interacts with Amazon S3 to host the CRL.

By default AWS Private CA places the CRL on an S3 Bucket that must be made “publicly accessible”. What this means is that the bucket must be made available without any authentication configured. This is in contradiction to AWS best practices where S3 Buckets are recommended to be made “private” by enabling the “Block Public Access” settings. This requires authentication using AWS Identity Access Management (IAM) to provide security in validating the permissions for who can read or write data in S3 buckets.

Private S3 Buckets work great when you are using a service designed to communicate with S3 using IAM. This requires the service to be built using the AWS CLI or SDK and use credentials such as an access/secret key or attaching an IAM role to a service such as Amazon EC2. However, in the case of CRLs, they must be accessed via an unauthenticated HTTP URL. Since the CRL communication occurs using the CytroAPI on Windows over HTTP, access keys or an IAM role do not have the ability to provide the required authentication. To allow communication to the CRL hosted on S3, the S3 Bucket must be made public.

Making a S3 bucket public doesn’t mean the world necessarily has access to read or write to the S3 bucket. Using a Bucket Policy attached to the S3 Bucket provides a secure way to provide unauthenticated access over HTTP to the CRL file hosted on S3. A Bucket Policy can institute a default Deny all and only allow provides from AWS native constructs such as a VPC or Service Endpoint. This limits the ability for access to access to S3 Bucket outside of your AWS private network.

The downside to this approach is that you will have to globally disable Block Public Access (BPA) on S3 for your entire account. While that doesn’t stop you from blocking public access on each individual S3 bucket, global BPA does provide a safeguard so that a bucket isn’t mistakenly made public without the proper security controls. When the global BPA setting is enabled, you cannot make any bucket public and therefore using S3 as the hosting location for the CRL is not possible.

As mentioned earlier, one AWS recommendation to remove public S3 Buckets from being required is to front-end the S3 Bucket hosting the CRL with AWS CloudFront. This removes the requirement for public access to S3 Bucket. However, CloudFront is typically used to reach users on the public Internet, not only inside an AWS VPC. Referring back to the AppStream 2.0 and WorkSpaces documentation, you will notice the CRL only needs to be accessible from inside your VPC. There is no private endpoint for CloudFront so to reach it, you would need to provide AppStream 2.0 and Domain Controller instances access to the public Internet. While this communication can be controlled, for a file that will never be accessed from entities outside of AWS, this may be unacceptable to some highly regulated organizations.

For customers with strict compliance standards, running AppStream 2.0 and WorkSpaces in AWS GovCloud, using CloudFront may not be an option. Since CloudFront is not available in AWS GovCloud it may not be considered by organizations that adhere to compliance standards such as ITAR and FedRamp High which are only available in AWS GovCloud regions. So, what other options are available to host the CRL when CloudFront is not an option?

Frontend S3 Bucket with AWS Lambda Function

The optimal solution is to use an AWS service that provides an internal only URL along with leveraging IAM to securely access files stored in S3. Using an internal facing Application Load Balancer (ALB) with AWS Lambda will allow for connections to be made securely to access the CRL object stored in S3. The Lambda function has an IAM Role attached that allows it to have read-only access to the S3 Bucket where the AWS Private CA places the CRL list. A small amount of Python code reads the CRL file in the S3 bucket based on the path provided. Let’s look at the code and the architecture.

Diagram showing the AWS services required and communication flow for the solution to function.

Figure 2. Application Load Balancer → Lambda → S3

This Python code will allow for files inside the S3 Bucket to be made available for download based on the path provided. It uses the boto3 AWS Python library to securely read the CRL file stored in S3. An IAM role that has read-only permissions to the S3 bucket must be configured with the Lambda function. With the code below, you simple just need to modify the S3 bucket name currently set to “Update me BUCKET NAME”.

import boto3
import botocore
import base64

s3 = boto3.client('s3')

def lambda_handler(event, context):

path = event['path'].split('/')
file_path = '/'.join(path[1:])

response = s3.get_object(
    Bucket='Update me BUCKET NAME',

crl_file = response['Body'].read()

return {
'statusCode': 200,
'statusDescription': '200 OK',
'isBase64Encoded': True,
'headers': {
'Content-Type': 'application/pkix-crl'
'body': base64.b64encode(crl_file).decode('utf-8')

The bucket policy configured on the S3 bucket where the CRL file is located should be configured similar to the example below. This policy provides access to the AWS Private CA to update the CRL along with allowing ready-only permissions from the IAM role assigned to previously mentioned Lambda function.

"Version": "2012-10-17",
"Id": "Policy",
"Statement": [
"Effect": "Allow",
"Principal": {
"Service": ""
"Action": [
"Resource": [
"arn:aws-us-gov:s3:::<BUCKET NAME>/*",
"arn:aws-us-gov:s3:::<BUCKET NAME>"
"Condition": {
"StringEquals": {
"aws:SourceArn": "<PRIVATE CA ARN>"
"Sid": "statement",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws-us-gov:iam::<Account ID>:role/service-role/<LAMBDA ROLE TO READ S3>"
"Action": "s3:GetObject",
"Resource": [
"arn:aws-us-gov:s3:::<BUCKET NAME>/*",
"arn:aws-us-gov:s3:::<BUCKET NAME>"

To allow AWS Private CA to use the ALB URL for the CRL, the command below must be run from the AWS CLI. Before executing the command, update the CLI command and the crl.txt file with your specific details. The “CustomCName” must be updated with your ALB URL and “S3BucketName” must match the S3 bucket where the CRL file is located. This step is required due to recent changes in S3 security. Be sure to check out the following blog to understand the recent changes with S3 security: Heads-Up: Amazon S3 Security Changes Are Coming in April of 2023 | AWS News Blog.

aws acm-pca update-certificate-authority —certificate-authority-arn “arn:aws-us-gov:acm-pca:us-gov-west-1:<Account ID>:certificate-authority/<ID>” —revocation-configuration “file://crl.txt”


“CrlConfiguration”: {
“Enabled”: true,
“ExpirationInDays”: 1,
“S3BucketName”: “<BUCKET_NAME>”,
“CustomCname”: “<Update to ALB URL example:>”

Can I use my physical Smartcard and CBA together?

When it comes to using CBA along with a physical smartcard, it is first important to understand the different stages of the authentication process: pre-session, session logon, and in-session.

  • Pre-Session. This is the stage that occurs before directly gaining access to the Windows desktop. CBA is only utilized for the session logon phase and never involved in the pre-session stage. Native Smartcard authentication options differ between AppStream 2.0 and WorkSpaces. WorkSpaces provides the ability to natively offer physical smartcard authentication at this stage without using a SAML iDP. To provide pre-session smartcard authentication with AppStream 2.0, a SAML IdP is required.
  • Session Logon. This stage is the authentication that occurs for a user to logon to their Windows session. When CBA is enabled, it will take ownership of this authentication stage. CBA does allow for fallback authentication to username/password. We will discuss later in this blog the pros and cons of using that fallback feature.
  • In-Session. This stage is defined as the ability to use a smartcard to authenticate to other services such as websites while inside a virtual desktop session. CBA does not allow the certificate used for the Windows logon to be used for authentication to other services while in a AppStream 2.0 or WorkSpaces session.

Below are some common scenarios when using a physical smartcard along with CBA works for both AppStream 2.0 & WorkSpaces.

AppStream 2.0

  • Domain Joined Fleet and Full AppStream Client. In the AppStream 2.0 client, you can use a physical Smart Card for both pre-authentication to AppStream 2.0 at the SAML IdP and in-session using smartcard pass-through. If you are standardized on using the full AppStream 2.0 client and end users are required to authenticate to services inside their session with their provided Smartcard, enabling CBA will provide minimal benefits. Its sole benefit would be to remove the second smartcard PIN prompt that occurs when logging into Windows. Although a smartcard PIN prompt appeared when authenticating at the SAML IdP, the AppStream 2.0 client will again prompt the user to enter their PIN. This additional prompt occurs since the browser and AppStream 2.0 client are separate Windows processes. This reason alone may be enough for some organizations to implement CBA.If the fleet is not joined to Active Directory, CBA does not factor into the architecture. CBA’s sole purpose is to provide authentication for Active Directory users with a virtual smart card. When the AppStream fleet is not domain joined, users are already automatically logged into their Windows desktop session with the default proton user account.
  • Web Based AppStream Client. It’s important to know that physical Smartcards are unable to be passed into virtual desktops from a browser based client due to HTML5 restrictions. Since authentication to the SAML Identity Provider occurs outside of the AppStream 2.0 session, you will still be able to authenticate with your provided physical smartcard. You will not however be able to use your physical smartcard inside the AppStream 2.0 session to authenticate to other resources such as websites. Depending on the applications you are accessing inside AppStream 2.0, this may or may not be a problem.


  • Full WorkSpaces Client & SAML IdP. The only viable design that involves WorkSpaces and CBA is when a SAML IdP is used as the primary authentication method. As with AppStream 2.0, physical smartcards can only be used in-session when using the Windows full client. When using the Smartcard authentication with WorkSpaces, it performs both the pre-session, and session logon stages. This essentially replaces the function that CBA performs during the session logon process. WorkSpaces accomplishes this by using Kerberos constrained delegation that allows a seamless logon to Windows without any additional prompts. Be sure to review the WorkSpaces Certificate Based Authentication documentation for known limitations.


In this blog, you learned how using Lambda and an internal Application Load Balancer (ALB) can provide secure HTTP access to CRL hosted on an S3 Bucket. This architecture allows access to the CRL file without network traffic leaving your VPC. Additionally, you learned how physical smart cards can be used along with CBA in certain situations. Using CBA with physical smart cards provides key benefits such as fewer PIN prompts when using the full desktop clients on AppStream 2.0. I encourage everyone beginning to implement CBA or already has it production to begin testing this solution and see how it can improve your architecture.

Roger LaMarca is a Solutions Architect on the Worldwide Public Sector U.S. Army team. He has over 12 years of customer facing experience designing and implementing user computing and cloud networking solutions in strategic government and private sector organizations.