AWS Directory Service is a managed Microsoft Active Directory solution. Using this service, you can manage the identities for your organization, and by joining EC2 instances to your directory domain, authorize access to your AWS resources.
AWS Elastic Beanstalk is a deployment service for your web applications. By configuring your Elastic Beanstalk environment, AWS can manage the scaling and high-availability for your web application. Supported environments include NodeJS, Ruby, and .NET, among others.
If you have an existing .NET application, or are building one that utilizes “Windows Authentication”, you can deploy your application using Elastic Beanstalk, and use Directory Service as your Windows authentication directory.
Ideally, we would implement this combination using off-the-shelf Elastic Beanstalk AMI images. However, due to an issue with Elastic Beanstalk hostnames being re-used, we’ll need to create a custom AMI image to be used by our Elastic Beanstalk applications.
The custom AMI will only address the hostname issue. This way, once AWS fixes it on their end, the custom AMI can be done away with.
We have employed these techniques in our own internal applications and we wanted to share them with anyone else who wanted to do the same.
This article will walk you through these steps:
The first requirement for this setup is to have a directory created using AWS Directory Service. In this example, I have setup a “small” Simple AD directory.
Unfortunately, AWS does not include a built-in method to manage users in your directory. So once you have your directory, you will need to connect an EC2 instance to your directory to manage users using the traditional Active Directory management tools.
For more information about this, please see the following articles in the AWS documentation:
In order to join an EC2 instance to an AWS directory, you need to have an SSM document that’s designed to do that.
If you join an EC2 instance to an AWS directory using the AWS Management Console, then the Launch Instance wizard will create one for you automatically. That document may be good enough for your purposes.
You can look in the AWS Management Console to see if you already have one defined. Go to the EC2 Management Console, and go to “Documents” page under the “Commands” section in the left navigation bar. You should see a list of SSM documents with names such as “AWS-RunPowerShellScript”.
If you already have a document with a name such as “awsconfig_Domain_d-906723588a_corp.example.com”, then you can use that. Otherwise, you will need to create a new document with the following contents.
{
"schemaVersion": "1.0",
"description": "Sample configuration to join an instance to a domain",
"runtimeConfig": {
"aws:domainJoin": {
"properties": {
"directoryId": "d-906723588a",
"directoryName": "corp.example.com",
"dnsIpAddresses": [
"172.31.12.42",
"172.31.59.123"
]
}
}
}
}
You will need to populate the directoryId
, directoryName
, and dnsIpAddresses
values from those from your AWS directory.
Once you have your JSON file, you can create the document using the AWS Management Console, or you can use the AWS CLI:
$ aws ssm create-document --content file://path/to/file.json --name "My_Custom_Config_File"
References:
We will use mechanisms built-in to Elastic Beanstalk to customize the EC2 instance as part of our deployment process. Your ASP.NET / MVC application will need to have some preparations done to perform these customizations.
First off, make sure that your web application has Windows authentication enabled. For many ASP.NET or MVC application, this would be done in the web.config
file.
<system.web>
<authentication mode="Windows" />
</system.web>
To setup Windows Authentication, we are going to use a file in the .ebextensions
folder. Elastic Beanstalk will detect this file and execute the commands inside.
This file will instruct Elastic Beanstalk to execute PowerShell commands to do the following:
.ebxtensions/01-WindowsAuth.config:
commands:
01-install-windows-auth:
command: powershell.exe -ExecutionPolicy RemoteSigned "Add-WindowsFeature Web-Security,Web-Windows-Auth"
ignoreErrors: true
waitAfterCompletion: 5
02-enable-iis-windows-auth:
command: powershell.exe -ExecutionPolicy RemoteSigned "Set-WebConfigurationProperty -Filter '/system.webServer/security/authentication/windowsAuthentication' -Name Enabled -Value True -PSPath 'IIS:\' -Location 'Default Web Site'"
ignoreErrors: true
waitAfterCompletion: 5
If your web application is not being deployed directly to the “Default Web Site” site under IIS, then you will need to adjust the -Location
value.
Next, we’ll use another .ebextensions
file to join the EC2 instance to our AWS Directory Server domain.
To join the instance to our domain, we create an SSM association between the EC2 instance and our SSM document that was created above. You’ll want to use the SSM document name in the placeholder below.
.ebxtensions/02-JoinDomain.config:
files:
"C:\\Scripts\\JoinDomain.ps1":
content: |
Import-Module AWSPowerShell
Start-transcript -Path C:\\JoinDomain-Transcript.txt -Force
$instanceId = Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/instance-id
$availabilityZone = Invoke-RestMethod -uri http://169.254.169.254/latest/meta-data/placement/availability-zone
$region = $AvailabilityZone.Substring(0, $availabilityZone.Length - 1)
Set-DefaultAWSRegion $region
Try
{
New-SSMAssociation -InstanceId $instanceId -Name "your ssm document name"
}
Catch
{
$errorMessage = $_.Exception.Message
"Exception: $errorMessage"
}
Stop-transcript
container_commands:
01-join-domain:
command: powershell.exe -ExecutionPolicy Bypass -File C:\\Scripts\\JoinDomain.ps1
ignoreErrors: true
waitAfterCompletion: 5
Package all of the above together into a deployment package and upload it to Elastic Beanstalk.
When you create your Elastic Beanstalk application, it will need to have an IAM Role for EC2 associated with the EC2 instances.
You will want to attach the AmazonEC2RoleforSSM
Managed Policy to your role. This will allow the EC2 instances to look for and execute the SSM documents.
You’ll also need to give the IAM role permission to execute ssm:CreateAssociation
. This is so that the EC2 instance can join the domain.
IAM Policy:
{
"Version" : "2012-10-17",
"Statement": [ {
"Effect": "Allow",
"Action": [
"ssm:CreateAssociation"
],
"Resource": "*"
} ]
}
AMI images provided by AWS for Elastic Beanstalk have a “quirk” in that all EC2 instances launched will have the same hostname. This prevents all but the first EC2 instance from connecting to the directory correctly.
Until AWS addresses this with fixed AMI images, we’ll need to address it ourself. As a workaround, we’ll create a custom AMI image that will create EC2 instances with unique hostnames.
Sysprep will do some work for a few minutes, then shutdown the EC2 instance automatically.
Once the instance is shutdown, create an AMI image from the EC2 instance.
Finally, you’ll need to create your Elastic Beanstalk application. You can use the Elastic Beanstalk wizard to create it, paying attention to these points:
Once the environment is up and running, there are some post-launch configuration changes that you’ll need to make.
Once your environment is up-and-running, you can check the EC2 instance’s console logs to verify that they have joined the domain correctly. See Getting the Domain Join Status for more information about that. In our experience, it may take a while for the instances to join. In some cases, it took 15 to 30 minutes.
At this point, you should be able to point a browser at your ELB’s endpoint. When required, provide your username/password from your AWS directory. You may need to include your domain’s short name with the username, such as “CORP\myusername”.
As your application scales in/out, new EC2 instances will associate with your domain. There are two places you will want to periodically clean them up:
$ aws ssm list-associations --region us-east-1 --association-filter-list key=Name,value="awsconfig_Domain_d-906723588a_corp.example.com"
Also, since HTTP is being used, rather than HTTPS, you should connect to your web application over a secured VPN rather than over the open internet.
We have put a sample ASP.NET MVC application on GitHub for your reading pleasure. It includes a CloudFormation template you can use to get started. It will create:
The web application:
.ebextensions
file used to setup Windows Authentication..ebextensions
file used to join the domain. You will need to edit this file.The project can be found at https://github.com/eleven41/JoinElasticBeanstalkToAWSDirectoryService.
A big thanks to Shyam K. in the Sydney AWS Support Centre. Shyam was very helpful in working out some troublesome “kinks” in this setup.
Skeddly is the leading scheduling service for your AWS account. Using Skeddly, you can:
Sign-up for our 30 day free trial or sign-in to your Skeddly account to get started.