4

I hope you can help me with my problem. I am trying to automatically let my ec2 instance joins an ad domain with my terraform script. Since Terraform does not support any "Domain join directory" option I wanted to try to create an SSM Document to let Systems Manager make that for me. Actually I got the following Code:

resource "aws_directory_service_directory" "ad" {
  name     = "active-directory-service.com"
  password = "${var.ad-password}"
  edition  = "Standard"
  size     = "Small"
  type     = "MicrosoftAD"

  vpc_settings {
    vpc_id     = "${aws_vpc.vpc.id}"
    subnet_ids = ["${aws_subnet.ds-subnet.0.id}", 
                  "${aws_subnet.ds-subnet.1.id}"
                  ]
  }

}

resource "aws_vpc_dhcp_options" "vpc-dhcp-options" {
  domain_name          = "${var.dir_domain_name}"
  domain_name_servers  = aws_directory_service_directory.ad.dns_ip_addresses

}
resource "aws_vpc_dhcp_options_association" "dns_resolver" {
   vpc_id          =  aws_vpc.vpc.id
   dhcp_options_id = aws_vpc_dhcp_options.vpc-dhcp-options.id
}

resource "aws_ssm_document" "ad-server-domain-join-document" {
    name  = "myapp_dir_default_doc"
    document_type = "Command"

content = <<DOC
{
        "schemaVersion": "1.0",
        "description": "Join an instance to a domain",
        "runtimeConfig": {
           "aws:domainJoin": {
               "properties": {
                  "directoryId": "${aws_directory_service_directory.ad.id}",
                  "directoryName": "${var.dir_domain_name}",
                  "directoryOU": "${var.dir_computer_ou}",
                  "dnsIpAddresses": [
                     "${aws_directory_service_directory.ad.dns_ip_addresses[0]}",
                     "${aws_directory_service_directory.ad.dns_ip_addresses[1]}"
               }
           }
        }
}
DOC
}

resource "aws_ssm_association" "ad-server-association" {
    name = "dir_default_doc"
    instance_id = aws_instance.ec2-ad-instance.id
}

I get the following error message:

This value does not have any indices. Can someone please tell me how to fix this issue?

ve05ribu
  • 71
  • 1
  • 2
  • 5
  • 1
    Can you edit your question to include the full error with the surrounding syntax bit? It's hard to tell from what you have in your question without running your example. Also, ideally your question should include a [mcve] which allows people to fully reproduce what you see. Right now this is too minimal and missing bits that would allow someone to reproduce it (eg the vpc and subnet bits). – ydaetskcoR Jan 30 '20 at 16:39

5 Answers5

10

If the AMI you are using does not have SSM, this is how you do it:

user_data = <<EOF
<powershell>
Add-Computer -DomainName 'NAME_OF_THE_DOMAIN' -NewName 'NEW_NAME_OF_THE_MACHINE' -Credential (New-Object -TypeName PSCredential -ArgumentList "DOMAIN_USERNAME",(ConvertTo-SecureString -String 'DOMAIN_PASSWORD' -AsPlainText -Force)[0]) -Restart
</powershell>
EOF

Or, if you want to use SSM, using the new Terraform 12/13 syntax and the latest schema version, here is a ready to copy and paste snippet:


data "aws_directory_service_directory" "my_domain_controller" {
  directory_id = "d-XXXXXXXXXXXXX"
}

resource "aws_ssm_document" "ad-join-domain" {
  name          = "ad-join-domain"
  document_type = "Command"
  content = jsonencode(
    {
      "schemaVersion" = "2.2"
      "description"   = "aws:domainJoin"
      "mainSteps" = [
        {
          "action" = "aws:domainJoin",
          "name"   = "domainJoin",
          "inputs" = {
            "directoryId" : data.aws_directory_service_directory.my_domain_controller.id,
            "directoryName" : data.aws_directory_service_directory.my_domain_controller.name
            "dnsIpAddresses" : sort(data.aws_directory_service_directory.my_domain_controller.dns_ip_addresses)
          }
        }
      ]
    }
  )
}

resource "aws_ssm_association" "windows_server" {
  name = aws_ssm_document.ad-join-domain.name
  targets {
    key    = "InstanceIds"
    values = ["i-XXXXXXXXXXXX"]
  }
}

You will need to specify an instance profile when creating the ec2 instance which has the required permissions for this snippet to work.

Mark Iannucci
  • 135
  • 3
  • 11
Marcos Diez
  • 181
  • 3
  • 4
3

As mentioned in the comment, reproducible examples will accelerate anyone's ability to help :)

I assumed terraform 0.12 is in use.

aws_directory_service_directory.ad.dns_ip_addresses is not a list, it is a set. Conceptually, this means it is unordered. As a result, access it like:

sort(aws_directory_service_directory.ad.dns_ip_addresses)[0]

The sort will order it and allow you to access it with an index. The following issue explains this, albeit in regards to attempting to verbosely use element to access https://github.com/hashicorp/terraform/issues/22392

The documentation for this resource calls it a list which is incorrect in practice it seems: https://www.terraform.io/docs/providers/aws/r/directory_service_directory.html

nick2
  • 31
  • 1
0

As per https://aws.amazon.com/blogs/security/how-to-configure-your-ec2-instances-to-automatically-join-a-microsoft-active-directory-domain/

dnsIpAddresses expects list in json format

                 "dnsIpAddresses": [
                 "198.51.100.1",
                 "198.51.100.2"
              ]

convert aws_directory_service_directory.ad.dns_ip_addresses to json format

"dnsIpAddresses": [ "${join("\", \"",aws_directory_service_directory.ad.dns_ip_addresses)}" ]
notmyitblog
  • 99
  • 1
  • 1
0

you can make the target on your SSM association to be a tag instead of using a specific instance, so any instance you are deploying and has the tag per se adjoin will join the domain

resource "aws_ssm_association" "windows_server" {
  name = aws_ssm_document.ad-join-domain.name
  targets {
    key    = "tag:adjoin"
    values = ["true"]
  }
}
0

I've tried following solution below, which was mentioned here - but unfortunately, the EC2s do not join the Active Directory in an automated way. I've to manually enter the domain and the dns. Any idea what's wrong with that approach? Thank you a lot in advance!

resource "aws_instance" "some-application" {
  ami = "ami-05a60358d5cda31c5"
  instance_type = "t2.micro"
  security_groups = [aws_security_group.sg-license-server.id]
  subnet_id       = module.vpc.public_subnets[0]
  key_name = aws_key_pair.pubkey.key_name

  tags = {
      "Name" = "Some-Application"
  }

  user_data = <<EOF
  <powershell>
  msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi
  Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
  Add-Computer -DomainName   '${aws_directory_service_directory.my_directory_service.name}' -NewName 'Some-Application' -Credential (New-Object -TypeName PSCredential -ArgumentList 'Administrator',(ConvertTo-SecureString -String '${aws_directory_service_directory.my_directory_service.password}' -AsPlainText -Force)[0]) -Restart
  </powershell>
  EOF
}

resource "aws_instance" "license-server" {
  ami = "ami-05a60358d5cda31c5"
  instance_type = "t2.micro"
  security_groups = [aws_security_group.sg-license-server.id]
  subnet_id       = module.vpc.public_subnets[0]
  key_name = aws_key_pair.pubkey.key_name

  tags = {
      "Name" = "License-Server"
  }

  user_data = <<EOF
  <powershell>
  msiexec.exe /i https://awscli.amazonaws.com/AWSCLIV2.msi
  Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine
  Add-Computer -DomainName '${aws_directory_service_directory.my_directory_service.name}' -NewName 'License-Server' -Credential (New-Object -TypeName PSCredential -ArgumentList 'Administrator',(ConvertTo-SecureString -String '${aws_directory_service_directory.my_directory_service.password}' -AsPlainText -Force)[0]) -Restart
  </powershell>
  EOF
}

resource "aws_security_group" "sg-fsx" {
  name        = "SG-FSX"
  vpc_id = module.vpc.vpc_id

 ingress {
  from_port        = 53
  to_port          = 636
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

 ingress {
  from_port        = 3268
  to_port          = 3269
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

 ingress {
  from_port        = 9389
  to_port          = 9389
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

 ingress {
  from_port        = 5985
  to_port          = 5985
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

ingress {
  from_port        = 88
  to_port          = 464
  protocol         = "udp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

  ingress {
  from_port        = 5985
  to_port          = 5985
  protocol         = "udp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

ingress {
  from_port        = 49152
  to_port          = 65535
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
  }

egress {
  from_port        = 0
  to_port          = 0
  protocol         = "-1"
  cidr_blocks      = ["0.0.0.0/0"]
  }

tags = {
    Name = "sg-fsx"
}

}

resource "aws_security_group" "sg-license-server" {
  name        = "SG-License-Server"
  vpc_id = module.vpc.vpc_id

 ingress {
  from_port        = 0
  to_port          = 6556
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
}

ingress {
  from_port        = 27000
  to_port          = 27000
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
}

ingress {
  from_port        = 49152
  to_port          = 65535
  protocol         = "tcp"
  cidr_blocks      = ["0.0.0.0/0"]
}

egress {
  from_port        = 0
  to_port          = 0
  protocol         = "-1"
  cidr_blocks      = ["0.0.0.0/0"]
}

tags = {
    Name = "sg-license-server"
}

}

resource "aws_key_pair" "pubkey" {
    key_name = "aws-cloud"
    public_key = file("key/aws_instance.pub")
}


resource "aws_vpc_dhcp_options" "vpc-dhcp-options" {
  domain_name          = aws_directory_service_directory.my_directory_service.name
  domain_name_servers  =   aws_directory_service_directory.my_directory_service.dns_ip_addresses
}
resource "aws_vpc_dhcp_options_association" "dns_resolver" {
   vpc_id          =  module.vpc.vpc_id
   dhcp_options_id = aws_vpc_dhcp_options.vpc-dhcp-options.id
}

resource "aws_fsx_windows_file_system" "example" {
  active_directory_id = aws_directory_service_directory.my_directory_service.id
  storage_capacity    = 300
  subnet_ids          = [module.vpc.private_subnets[0]]
  throughput_capacity = 1024
  security_group_ids = [aws_security_group.sg-fsx.id]
 }
bianconero
  • 215
  • 1
  • 12