Scripts: Windows DomainJoin using AWS Secrets Manager PowerShell Script
DomainJoin Script Description
This script was designed to run on a freshly deployed Windows EC2 instance. Its function is to make a request to the AWS Secrets Manager to get the proper Active Directory Service Account credentials of a user that has delegated control to perform domain join operations. This negates the necessity of having hard coded username and password values sitting in the unattend.xml or the accompanying windows domain join powerShell script saved within the base AMI. The script performs the following actions:
1. Set Script Variables:
When the Windows EC2 instance is instantiated, the windows_domainjoin.ps1 script executes the following actions:
Change Values
These variables should be modified in your script to reflect your proper domain settings.
$domain_name = "starfleet".ToUpper() $domain_tld = "aws" $secrets_manager_secret_id = "Windows/ServiceAccounts/DomainJoin"
The purpose of these variables is to reference the Active Directory domain name (STARFLEET), and the domain's top level domain (aws) in various parts of the domain join script. When combined together the $domain_name.$domain_tld should equate to your Active Directory domains FQDN (STARFLEET.aws). Finally set the $secrets_manager_secret_id, which contains the name of the secret to be retrieved from the Secrets Manager Service.
1. Get Creds:
Once executed the first operation that the script performs is to make a request to the Secrets Manager.
# Make a request to the secret manager $secret_manager = Get-SECSecretValue -SecretId $secrets_manager_secret_id
This cmdlet will make the actual request to the Secrets Manager Service to retrieve the credentials object and store the entire returned object in the $secret_manager variable. At the end of this execution the $secret_manager variable would contain the following value.
ARN : arn:aws:secretsmanager:us-east-1:123456789012:secret:Windows/ServiceAccounts/DomainJoin CreatedDate : 8/8/2018 5:59:00 PM Name : Windows/ServiceAccounts/DomainJoin SecretBinary : SecretString : {"ServiceAccount":"service_account_user","Password":"service_account_password"} VersionId : ad607fe0-45c6-42f6-857c-f56b634c9e4c VersionStages : {AWSCURRENT}
2. Strip Away the Meta-Data:
Next, the script will parse the returned $secret_manager value, and extract just the SecretString. It will turn that key:value payload into its own object containing just the returned secret values.
# Parse the response and convert the Secret String JSON into an object $secret = $secret_manager.SecretString | ConvertFrom-Json
This cmdlet will create a new variable that contains just the SecretString data. After it runs, the $secret variable will contain the following value:
{ "ServiceAccount":"service_account_user", "Password":"service_account_password" }
$secret.ServiceAccount would contain just the service account user value being service_account_user
, and $secret.Password would contain secret_password_value
. These values all correlate back to the object that is stored in the Secrets Manager Service
3. Set Username and Password:
Next, the script will parse the $secret object and extract the service account user and password from the variable and store those values in the $username and $password variables in their proper formats.
# Construct the domain credentials $username = $domain_name.ToUpper() + "\" + $secret.ServiceAccount $password = $secret.Password | ConvertTo-SecureString -AsPlainText -Force
Once this section of the script has executed, $username will contain the value of STARFLEET\service_account_user
, and $password will contain the value of secret_password_value
. $password will also be converted and stored as a SecureString.
4. Set Auth Credentials:
Next, the script will set the $credential variable that will be used to authenticate against Active Directory to perform the actual domain join operation.
# Set PS credentials $credential = New-Object System.Management.Automation.PSCredential($username,$password)
5. Set Computer Name to the Instance ID:
Next, the script will make a query to the AWS Meta-data service and retrieve the instances ID value. This value will be used to set the computer name during the domain join process.
# Get the Instance ID from the metadata store, we will use this as our computer name during domain registration. $instanceID = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/instance-id
6. Perform the Domain Join Operation:
The last step that the script will complete is the actual domain join operation.
OU Change
In most cases new computers joined to an AD domain are added to the Computers OU. If you wish for your newly joined computers/servers to be added to a different OU, then add the "OU=Computers,DC=$domain_name,DC=$domain_tld"
line with the -OUPath flag before the -NewName flag. Be sure to change the OU=Computers
to the OU={YOUR_NEW_LOCATION}
prior to saving this script.
# Perform the domain join Add-Computer -DomainName "$domain_name.$domain_tld" -NewName "$instanceID" -Credential $credential -Passthru -Verbose -Force -Restart
This cmdlet will contact Active Directory and join the computer/server running this script to the Active Directory domain. The computer/server will be registered with the computer name set to the instance ID. It will optionally also be added to the Active Directory OU specified in the command, in this case being the Computers OU, provided that you specified an -OUPath. By default all new computer objects are added to the Computers OU.
PowerShell Script
# Domain name and the tld. In this example the domain is starfleet.aws $domain_name = "starfleet".ToUpper() $domain_tld = "aws" $secrets_manager_secret_id = "Windows/ServiceAccounts/DomainJoin" # Make a request to the secret manager $secret_manager = Get-SECSecretValue -SecretId $secrets_manager_secret_id # Parse the response and convert the Secret String JSON into an object $secret = $secret_manager.SecretString | ConvertFrom-Json # Construct the domain credentials $username = $domain_name.ToUpper() + "\" + $secret.ServiceAccount $password = $secret.Password | ConvertTo-SecureString -AsPlainText -Force # Set PS credentials $credential = New-Object System.Management.Automation.PSCredential($username,$password) # Get the Instance ID from the metadata store, we will use this as our computer name during domain registration. $instanceID = invoke-restmethod -uri http://169.254.169.254/latest/meta-data/instance-id # Perform the domain join # Add-Computer -DomainName "$domain_name.$domain_tld" -OUPath "DN=Computers,DC=$domain_name,DC=$domain_tld" -NewName "$instanceID" -Credential $credential -Passthru -Verbose -Force -Restart Add-Computer -DomainName "$domain_name.$domain_tld" -NewName "$instanceID" -Credential $credential -Passthru -Verbose -Force -Restart # Script Tests # Write-Output $username # Write-Output $password # Write-Output "Add-Computer -domainname '$domain_name.$domain_tld' -OUPath 'CN=Computers,DC=$domain_name,DC=$domain_tld' -NewName '$instanceID' -Credential $credential -Passthru -Verbose -Force -Restart"