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 whose default rules are 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 add rules for those networks or the instances cannot communicate with the domain controllers even if network connectivity exists. Use the security_group_rules.allow_ad_ports_from option on the directory to grant a network the full AD port set in one entry — see Managed Active Directory.

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"
    # Admin password comes from the "ad_password" secret by default
    # (TF_VAR_ad_password); override with admin_password_key
    edition  = "Standard"
    type     = "MicrosoftAD"
    vpc      = "SharedInfra"
    subnets = [
      "SharedInfraPrivateAZ1",
      "SharedInfraPrivateAZ2"
    ]
  }
}

See Managed Active Directory for the full managed_ads schema and defaults.

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