Managed Active Directory in the AWS cloud

This is a mini guide how to set up a managed Active Directory (AD) in AWS with Json2Ldap in front of it.

Create a new Active Directory instance

  1. Log into the AWS console.

  2. From the Services menu select "Directory Service".

  3. Click on "Set up directory".

  4. Choose the "AWS Managed Microsoft AD".

  5. Supply the required directory information:

    • The "standard edition" should be sufficient in most cases.
    • Specify a "Directory DNS name", e.g. ad.c2id.com. This will result in the creation of an admin user with the Distinguished Name (DN) CN=admin,OU=users,OU=ad,DC=ad,DC=c2id,DC=com. The last four components of the DN reflect the chosen domain.
    • Generate a suitable admin password, e.g. with pwgen -y 16: ieYu_a3ooFeilah7
    • The remaining details are optional.
  6. Choose a VPC and two subnets for the networking:

    • Use the default VPC or create a new one, e.g. vpc-c35a0bab (172.31.0.0/16).
    • Use two existing subnets within the VPC, or create two new ones, for example:
      • subnet-d26e09a8 (172.31.16.0/20, eu-west-2a)
      • subnet-4e00aa02 (172.31.32.0/20, eu-west-2b)
  7. Click on "Create directory". In about 30 minutes the directory status will appear as "active".

  8. Note the two IP addresses within the VPN where the AD instance can be reached, for example:

    • 172.31.18.178
    • 172.31.43.108

Network access

The ports of the AD instance, such as the default LDAP port 389 and the LDAPS port 636, can be freely accessed from other hosts within the same VPC.

To allow external access the VPC must be configured with a suitable policy.

Json2Ldap within the VPC

If the Json2Ldap web service is deployed within the same VPC, within an AWS BeanStalk Tomcat pod, it will receive a public IP address and host name allowing API calls from the Internet.

Example Json2Ldap URL in a BeanStalk deployment:

http://json2ldap-env.eba-ni3xmp2e.eu-west-2.elasticbeanstalk.com/

Make sure you provision the web service with TLS/HTTPS to secure all data and credentials passed between clients and the Json2Ldap URL.

The underlying LDAP connections with ldap.connect is made directly to one of the private IP addresses of the AD instance.

JSON-RPC 2.0 > ldap.connect { "host":"172.31.18.178" }
{ "CID" : "GoYfh9EFOTqZLMnok7Zicy2jDR7i79KFqihd7GiDA8Q" }
JSON-RPC 2.0 > ldap.simpleBind { "DN":"CN=admin,OU=users,DC=ad,DC=c2id,DC=com", "password":"qua8Oikaib_iuF8f", "CID":"GoYfh9EFOTqZLMnok7Zicy2jDR7i79KFqihd7GiDA8Q" }
{}

Example root DSE for an AD instance

Example output from the ldap.getRootDSE call:

JSON-RPC 2.0 > ldap.getRootDSE { "CID" : "GoYfh9EFOTqZLMnok7Zicy2jDR7i79KFqihd7GiDA8Q" }
{ "currentTime"                   : [ "20201020111724.0Z" ],
 "subschemaSubentry"             : [ "CN=Aggregate,CN=Schema,CN=Configuration,DC=ad,DC=c2id,DC=com" ],
 "dsServiceName"                 : [ "CN=NTDS Settings,CN=WIN-EG3MF9UQC68,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=c2id,DC=com" ],
 "namingContexts"                : [ "DC=ad,DC=c2id,DC=com",
                                     "CN=Configuration,DC=ad,DC=c2id,DC=com",
                                     "CN=Schema,CN=Configuration,DC=ad,DC=c2id,DC=com",
                                     "DC=DomainDnsZones,DC=ad,DC=c2id,DC=com",
                                     "DC=ForestDnsZones,DC=ad,DC=c2id,DC=com" ],
 "defaultNamingContext"          : [ "DC=ad,DC=c2id,DC=com" ],
 "schemaNamingContext"           : [ "CN=Schema,CN=Configuration,DC=ad,DC=c2id,DC=com" ],
 "configurationNamingContext"    : [ "CN=Configuration,DC=ad,DC=c2id,DC=com" ],
 "rootDomainNamingContext"       : [ "DC=ad,DC=c2id,DC=com" ],
 "supportedControl"              : [ "1.2.840.113556.1.4.319",
                                     "1.2.840.113556.1.4.801",
                                     "1.2.840.113556.1.4.473",
                                     "1.2.840.113556.1.4.528",
                                     "1.2.840.113556.1.4.417",
                                     "1.2.840.113556.1.4.619",
                                     "1.2.840.113556.1.4.841",
                                     "1.2.840.113556.1.4.529",
                                     "1.2.840.113556.1.4.805",
                                     "1.2.840.113556.1.4.521",
                                     "1.2.840.113556.1.4.970",
                                     "1.2.840.113556.1.4.1338",
                                     "1.2.840.113556.1.4.474",
                                     "1.2.840.113556.1.4.1339",
                                     "1.2.840.113556.1.4.1340",
                                     "1.2.840.113556.1.4.1413",
                                     "2.16.840.1.113730.3.4.9",
                                     "2.16.840.1.113730.3.4.10",
                                     "1.2.840.113556.1.4.1504",
                                     "1.2.840.113556.1.4.1852",
                                     "1.2.840.113556.1.4.802",
                                     "1.2.840.113556.1.4.1907",
                                     "1.2.840.113556.1.4.1948",
                                     "1.2.840.113556.1.4.1974",
                                     "1.2.840.113556.1.4.1341",
                                     "1.2.840.113556.1.4.2026",
                                     "1.2.840.113556.1.4.2064",
                                     "1.2.840.113556.1.4.2065",
                                     "1.2.840.113556.1.4.2066",
                                     "1.2.840.113556.1.4.2090",
                                     "1.2.840.113556.1.4.2205",
                                     "1.2.840.113556.1.4.2204",
                                     "1.2.840.113556.1.4.2206",
                                     "1.2.840.113556.1.4.2211",
                                     "1.2.840.113556.1.4.2239",
                                     "1.2.840.113556.1.4.2255",
                                     "1.2.840.113556.1.4.2256" ],
 "supportedLDAPVersion"          : [ "3", "2" ],
 "supportedLDAPPolicies"         : [ "MaxPoolThreads",
                                     "MaxPercentDirSyncRequests",
                                     "MaxDatagramRecv",
                                     "MaxReceiveBuffer",
                                     "InitRecvTimeout",
                                     "MaxConnections",
                                     "MaxConnIdleTime",
                                     "MaxPageSize",
                                     "MaxBatchReturnMessages",
                                     "MaxQueryDuration",
                                     "MaxTempTableSize",
                                     "MaxResultSetSize",
                                     "MinResultSets",
                                     "MaxResultSetsPerConn",
                                     "MaxNotificationPerConn",
                                     "MaxValRange",
                                     "MaxValRangeTransitive",
                                     "ThreadMemoryLimit",
                                     "SystemMemoryLimitPercent" ],
 "highestCommittedUSN"           : [ "13737" ],
 "supportedSASLMechanisms"       : [ "GSSAPI",
                                     "GSS-SPNEGO",
                                     "EXTERNAL",
                                     "DIGEST-MD5" ],
 "dnsHostName"                   : [ "WIN-EG3MF9UQC68.test.c2id.com" ],
 "ldapServiceName"               : [ "test.c2id.com:[email protected]" ],
 "serverName"                    : [ "CN=WIN-EG3MF9UQC68,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=ad,DC=c2id,DC=com" ],
 "supportedCapabilities"         : [ "1.2.840.113556.1.4.800",
                                     "1.2.840.113556.1.4.1670",
                                     "1.2.840.113556.1.4.1791",
                                     "1.2.840.113556.1.4.1935",
                                     "1.2.840.113556.1.4.2080",
                                     "1.2.840.113556.1.4.2237" ],
 "isSynchronized"                : [ "TRUE" ],
 "isGlobalCatalogReady"          : [ "TRUE" ],
 "supportedExtension"            : [ "1.3.6.1.4.1.1466.20037",
                                     "1.3.6.1.4.1.1466.101.119.1",
                                     "1.2.840.113556.1.4.1781",
                                     "1.3.6.1.4.1.4203.1.11.3",
                                     "1.2.840.113556.1.4.2212" ],
 "domainFunctionality"           : [ "6" ],
 "forestFunctionality"           : [ "6" ],
 "domainControllerFunctionality" : [ "6" ] }

The admin account

The details of the admin account can be retrieved with the ldap.getEntry call.

JSON-RPC 2.0 > ldap.getEntry { "DN":"CN=Admin,OU=users,OU=ad,DC=ad,DC=c2id,DC=com", "CID":"GoYfh9EFOTqZLMnok7Zicy2jDR7i79KFqihd7GiDA8Q", "output":"LDIF" }
dn: CN=Admin,OU=users,OU=ad,DC=ad,DC=c2id,DC=com
objectClass: top
objectClass: person
objectClass: organizationalPerson
objectClass: user
cn: Admin
description: DO NOT DELETE:  Provided by AWS for administration of directory objects.  This account has FULL CONTROL over the root OU: 'OU=ad,DC=ad,DC=c2id,DC=com' and group management rights to groups in AWS Delegated Groups OU
distinguishedName: CN=Admin,OU=Users,OU=ad,DC=ad,DC=c2id,DC=com
instanceType: 4
whenCreated: 20201020101908.0Z
whenChanged: 20201020134555.0Z
displayName: Admin
uSNCreated: 12865
memberOf: CN=AWS Delegated Administrators,OU=AWS Delegated Groups,DC=ad,DC=c2id,DC=com
uSNChanged: 14027
name: Admin
objectGUID:: ovSOY/MRj0SOzFMrTJ80uA==
userAccountControl: 512
badPwdCount: 0
codePage: 0
countryCode: 0
badPasswordTime: 0
lastLogoff: 0
lastLogon: 0
pwdLastSet: 132476680560572563
primaryGroupID: 513
objectSid:: AQUAAAAAAAUVAAAAND22ufFCVwI4CdeeWQQAAA==
accountExpires: 9223372036854775807
logonCount: 0
sAMAccountName: Admin
sAMAccountType: 805306368
objectCategory: CN=Person,CN=Schema,CN=Configuration,DC=ad,DC=c2id,DC=com
dSCorePropagationData: 20201020101918.0Z
dSCorePropagationData: 20201020101918.0Z
dSCorePropagationData: 20201020101917.0Z
dSCorePropagationData: 20201020101917.0Z
dSCorePropagationData: 16010714223649.0Z
lastLogonTimestamp: 132476751557996786

The users branch

The users branch is automatically created when the AD instance is provisioned. It contains the admin account.

JSON-RPC 2.0 > ldap.getEntry { "DN":"OU=users,OU=ad,DC=ad,DC=c2id,DC=com", "CID":"-zkJ_BGjncGAzEwQHUs2GkWmqEvnYyRPSjG8x1eGDec", "output":"LDIF" }         
dn: OU=users,OU=ad,DC=ad,DC=c2id,DC=com
objectClass: top
objectClass: organizationalUnit
ou: Users
distinguishedName: OU=Users,OU=ad,DC=ad,DC=c2id,DC=com
instanceType: 4
whenCreated: 20201020101907.0Z
whenChanged: 20201020101908.0Z
uSNCreated: 12850
uSNChanged: 12856
name: Users
objectGUID:: VwSYd8iMQEWTMc6oozBUpg==
systemFlags: -1946157056
objectCategory: CN=Organizational-Unit,CN=Schema,CN=Configuration,DC=ad,DC=c2id,DC=com
isCriticalSystemObject: TRUE
dSCorePropagationData: 20201020101918.0Z
dSCorePropagationData: 20201020101918.0Z
dSCorePropagationData: 20201020101918.0Z
dSCorePropagationData: 20201020101918.0Z
dSCorePropagationData: 16010101000001.0Z

Creating a new branch

To create a new branch, for example to import accounts synced via the LdapSync tool:

JSON-RPC 2.0 > ldap.add { "DN":"OU=sync,OU=ad,DC=ad,DC=c2id,DC=com", "attributes":{"objectClass":["top","organizationalUnit"],"ou":"sync"}, "CID":"GoYfh9EFOTqZLMnok7Zicy2jDR7i79KFqihd7GiDA8Q" }