Skip to content

AWS Managed AD Domain Join

Join EC2 instances to an AWS Managed Microsoft AD directory using the built-in aws:domainJoin SSM action.

Prerequisites

  • AWS Managed Microsoft AD directory already created
  • EC2 instances running Windows Server with SSM agent
  • Instance IAM role with AmazonSSMManagedInstanceCore policy
  • Security groups allowing AD traffic between instances and AD (ports 389, 636, 88, 445, etc.)

Cross-VPC Security Group Configuration

AWS Managed AD automatically creates a security group that is scoped only to the VPC where the directory is deployed. If you have instances to domain-join in other VPCs (spoke accounts, peered VPCs, Transit Gateway-connected VPCs), you must manually update the Managed AD security group after directory creation to include CIDR blocks from those VPCs. Without this, instances in other VPCs cannot communicate with the domain controllers even if network connectivity exists.

Configuration

Step 1: Define the Domain Join Document

domain_join = {
  AWS_AD_Domain_Join = {
    ad_type = "managed"  # Optional, defaults to "managed"
    content = {
      mainSteps = [{
        inputs = {
          directory = "epic"  # References managed_ads key
        }
      }]
    }
    tags = {
      Environment = "production"
    }
  }
}

Step 2: Reference Managed AD Directory

The directory input must match a key in your managed_ads variable:

managed_ads = {
  epic = {
    name     = "epic.local"
    password = var.ad_password  # Use environment variable TF_VAR_ad_password
    edition  = "Standard"
    type     = "MicrosoftAD"
    vpc      = "SharedInfra"
    subnets = [
      "SharedInfraPrivateAZ1",
      "SharedInfraPrivateAZ2"
    ]
  }
}

Step 3: Associate with EC2 Instances

Reference the domain join document in your instance configuration:

instances = {
  AppServer01 = {
    vpc                  = "SharedInfra"
    ami                  = "ami-0c55b159cbfafe1f0"
    instance_type        = "t3.medium"
    subnet               = "SharedInfraPrivateAZ1"
    instance_profile     = "SSMInstanceProfile"
    domain_join          = "AWS_AD_Domain_Join"
    tags = {
      Name = "AppServer01"
    }
  }
}

How It Works

  1. Terraform creates an SSM document using the AWS-provided aws:domainJoin action
  2. The document automatically retrieves directory details from the AWS Directory Service
  3. When the instance launches, SSM executes the domain join
  4. The instance joins the domain and reboots automatically

Behind the Scenes

The module translates your configuration into an SSM document that looks like:

{
  "schemaVersion": "2.2",
  "description": "aws:domainJoin",
  "mainSteps": [{
    "action": "aws:domainJoin",
    "name": "domainJoin",
    "inputs": {
      "directoryId": "d-1234567890",
      "directoryName": "epic.local",
      "dnsIpAddresses": ["10.0.1.10", "10.0.1.11"]
    }
  }]
}

Advantages

  • Simple Configuration - AWS handles most of the complexity
  • No Credential Management - AWS manages domain credentials internally
  • Automatic DNS - Directory Service provides DNS automatically
  • Built-in Support - Uses AWS-native SSM action

Limitations

  • Only works with AWS Managed Microsoft AD (not Simple AD or AD Connector)
  • Cannot specify custom OU placement with managed AD
  • Directory must be in the same AWS account and region

Troubleshooting

Instance Not Joining Domain

  1. Verify SSM agent is running: Check SSM Fleet Manager
  2. Check IAM permissions: Instance profile must have SSM policies
  3. Verify network connectivity: Security groups must allow AD ports
  4. Review SSM command history: Look for execution errors

Finding SSM Execution Logs

  1. Navigate to AWS Systems ManagerRun Command
  2. Find the command execution for your instance
  3. View output to see detailed error messages