The aws:directoryservice/directory:Directory resource, part of the Pulumi AWS provider, provisions AWS Directory Service directories: SimpleAD for basic LDAP/Kerberos, MicrosoftAD for full Windows Server AD, or ADConnector to proxy to on-premises directories. This guide focuses on three capabilities: SimpleAD for lightweight authentication, MicrosoftAD for enterprise AD features, and ADConnector for hybrid on-premises integration.
All directory types require VPC placement with subnets in two availability zones. ADConnector additionally requires network connectivity to on-premises AD via VPN or Direct Connect. The examples are intentionally small. Combine them with your own VPC infrastructure and security configuration.
Create a SimpleAD directory for basic authentication
Teams needing lightweight directory services for user authentication and group management often start with SimpleAD, which provides Samba 4-based Active Directory compatibility without the overhead of a full Microsoft AD deployment.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const main = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const foo = new aws.ec2.Subnet("foo", {
vpcId: main.id,
availabilityZone: "us-west-2a",
cidrBlock: "10.0.1.0/24",
});
const barSubnet = new aws.ec2.Subnet("bar", {
vpcId: main.id,
availabilityZone: "us-west-2b",
cidrBlock: "10.0.2.0/24",
});
const bar = new aws.directoryservice.Directory("bar", {
name: "corp.notexample.com",
password: "SuperSecretPassw0rd",
size: "Small",
vpcSettings: {
vpcId: main.id,
subnetIds: [
foo.id,
barSubnet.id,
],
},
tags: {
Project: "foo",
},
});
import pulumi
import pulumi_aws as aws
main = aws.ec2.Vpc("main", cidr_block="10.0.0.0/16")
foo = aws.ec2.Subnet("foo",
vpc_id=main.id,
availability_zone="us-west-2a",
cidr_block="10.0.1.0/24")
bar_subnet = aws.ec2.Subnet("bar",
vpc_id=main.id,
availability_zone="us-west-2b",
cidr_block="10.0.2.0/24")
bar = aws.directoryservice.Directory("bar",
name="corp.notexample.com",
password="SuperSecretPassw0rd",
size="Small",
vpc_settings={
"vpc_id": main.id,
"subnet_ids": [
foo.id,
bar_subnet.id,
],
},
tags={
"Project": "foo",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directoryservice"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
main, err := ec2.NewVpc(ctx, "main", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
foo, err := ec2.NewSubnet(ctx, "foo", &ec2.SubnetArgs{
VpcId: main.ID(),
AvailabilityZone: pulumi.String("us-west-2a"),
CidrBlock: pulumi.String("10.0.1.0/24"),
})
if err != nil {
return err
}
barSubnet, err := ec2.NewSubnet(ctx, "bar", &ec2.SubnetArgs{
VpcId: main.ID(),
AvailabilityZone: pulumi.String("us-west-2b"),
CidrBlock: pulumi.String("10.0.2.0/24"),
})
if err != nil {
return err
}
_, err = directoryservice.NewDirectory(ctx, "bar", &directoryservice.DirectoryArgs{
Name: pulumi.String("corp.notexample.com"),
Password: pulumi.String("SuperSecretPassw0rd"),
Size: pulumi.String("Small"),
VpcSettings: &directoryservice.DirectoryVpcSettingsArgs{
VpcId: main.ID(),
SubnetIds: pulumi.StringArray{
foo.ID(),
barSubnet.ID(),
},
},
Tags: pulumi.StringMap{
"Project": pulumi.String("foo"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var main = new Aws.Ec2.Vpc("main", new()
{
CidrBlock = "10.0.0.0/16",
});
var foo = new Aws.Ec2.Subnet("foo", new()
{
VpcId = main.Id,
AvailabilityZone = "us-west-2a",
CidrBlock = "10.0.1.0/24",
});
var barSubnet = new Aws.Ec2.Subnet("bar", new()
{
VpcId = main.Id,
AvailabilityZone = "us-west-2b",
CidrBlock = "10.0.2.0/24",
});
var bar = new Aws.DirectoryService.Directory("bar", new()
{
Name = "corp.notexample.com",
Password = "SuperSecretPassw0rd",
Size = "Small",
VpcSettings = new Aws.DirectoryService.Inputs.DirectoryVpcSettingsArgs
{
VpcId = main.Id,
SubnetIds = new[]
{
foo.Id,
barSubnet.Id,
},
},
Tags =
{
{ "Project", "foo" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.directoryservice.Directory;
import com.pulumi.aws.directoryservice.DirectoryArgs;
import com.pulumi.aws.directoryservice.inputs.DirectoryVpcSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var main = new Vpc("main", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var foo = new Subnet("foo", SubnetArgs.builder()
.vpcId(main.id())
.availabilityZone("us-west-2a")
.cidrBlock("10.0.1.0/24")
.build());
var barSubnet = new Subnet("barSubnet", SubnetArgs.builder()
.vpcId(main.id())
.availabilityZone("us-west-2b")
.cidrBlock("10.0.2.0/24")
.build());
var bar = new Directory("bar", DirectoryArgs.builder()
.name("corp.notexample.com")
.password("SuperSecretPassw0rd")
.size("Small")
.vpcSettings(DirectoryVpcSettingsArgs.builder()
.vpcId(main.id())
.subnetIds(
foo.id(),
barSubnet.id())
.build())
.tags(Map.of("Project", "foo"))
.build());
}
}
resources:
bar:
type: aws:directoryservice:Directory
properties:
name: corp.notexample.com
password: SuperSecretPassw0rd
size: Small
vpcSettings:
vpcId: ${main.id}
subnetIds:
- ${foo.id}
- ${barSubnet.id}
tags:
Project: foo
main:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
foo:
type: aws:ec2:Subnet
properties:
vpcId: ${main.id}
availabilityZone: us-west-2a
cidrBlock: 10.0.1.0/24
barSubnet:
type: aws:ec2:Subnet
name: bar
properties:
vpcId: ${main.id}
availabilityZone: us-west-2b
cidrBlock: 10.0.2.0/24
When you create the directory, AWS deploys domain controllers into the specified subnets across two availability zones. The name property sets the fully qualified domain name (e.g., “corp.notexample.com”), and the size property controls capacity (“Small” or “Large”). The vpcSettings block places the directory in your VPC, and subnetIds must reference subnets in different availability zones for high availability.
Deploy managed Microsoft Active Directory
Applications requiring full Microsoft AD features like Group Policy, trusts, or schema extensions need MicrosoftAD, which runs actual Windows Server domain controllers managed by AWS.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const main = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const foo = new aws.ec2.Subnet("foo", {
vpcId: main.id,
availabilityZone: "us-west-2a",
cidrBlock: "10.0.1.0/24",
});
const barSubnet = new aws.ec2.Subnet("bar", {
vpcId: main.id,
availabilityZone: "us-west-2b",
cidrBlock: "10.0.2.0/24",
});
const bar = new aws.directoryservice.Directory("bar", {
name: "corp.notexample.com",
password: "SuperSecretPassw0rd",
edition: "Standard",
type: "MicrosoftAD",
vpcSettings: {
vpcId: main.id,
subnetIds: [
foo.id,
barSubnet.id,
],
},
tags: {
Project: "foo",
},
});
import pulumi
import pulumi_aws as aws
main = aws.ec2.Vpc("main", cidr_block="10.0.0.0/16")
foo = aws.ec2.Subnet("foo",
vpc_id=main.id,
availability_zone="us-west-2a",
cidr_block="10.0.1.0/24")
bar_subnet = aws.ec2.Subnet("bar",
vpc_id=main.id,
availability_zone="us-west-2b",
cidr_block="10.0.2.0/24")
bar = aws.directoryservice.Directory("bar",
name="corp.notexample.com",
password="SuperSecretPassw0rd",
edition="Standard",
type="MicrosoftAD",
vpc_settings={
"vpc_id": main.id,
"subnet_ids": [
foo.id,
bar_subnet.id,
],
},
tags={
"Project": "foo",
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directoryservice"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
main, err := ec2.NewVpc(ctx, "main", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
foo, err := ec2.NewSubnet(ctx, "foo", &ec2.SubnetArgs{
VpcId: main.ID(),
AvailabilityZone: pulumi.String("us-west-2a"),
CidrBlock: pulumi.String("10.0.1.0/24"),
})
if err != nil {
return err
}
barSubnet, err := ec2.NewSubnet(ctx, "bar", &ec2.SubnetArgs{
VpcId: main.ID(),
AvailabilityZone: pulumi.String("us-west-2b"),
CidrBlock: pulumi.String("10.0.2.0/24"),
})
if err != nil {
return err
}
_, err = directoryservice.NewDirectory(ctx, "bar", &directoryservice.DirectoryArgs{
Name: pulumi.String("corp.notexample.com"),
Password: pulumi.String("SuperSecretPassw0rd"),
Edition: pulumi.String("Standard"),
Type: pulumi.String("MicrosoftAD"),
VpcSettings: &directoryservice.DirectoryVpcSettingsArgs{
VpcId: main.ID(),
SubnetIds: pulumi.StringArray{
foo.ID(),
barSubnet.ID(),
},
},
Tags: pulumi.StringMap{
"Project": pulumi.String("foo"),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var main = new Aws.Ec2.Vpc("main", new()
{
CidrBlock = "10.0.0.0/16",
});
var foo = new Aws.Ec2.Subnet("foo", new()
{
VpcId = main.Id,
AvailabilityZone = "us-west-2a",
CidrBlock = "10.0.1.0/24",
});
var barSubnet = new Aws.Ec2.Subnet("bar", new()
{
VpcId = main.Id,
AvailabilityZone = "us-west-2b",
CidrBlock = "10.0.2.0/24",
});
var bar = new Aws.DirectoryService.Directory("bar", new()
{
Name = "corp.notexample.com",
Password = "SuperSecretPassw0rd",
Edition = "Standard",
Type = "MicrosoftAD",
VpcSettings = new Aws.DirectoryService.Inputs.DirectoryVpcSettingsArgs
{
VpcId = main.Id,
SubnetIds = new[]
{
foo.Id,
barSubnet.Id,
},
},
Tags =
{
{ "Project", "foo" },
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.directoryservice.Directory;
import com.pulumi.aws.directoryservice.DirectoryArgs;
import com.pulumi.aws.directoryservice.inputs.DirectoryVpcSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var main = new Vpc("main", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var foo = new Subnet("foo", SubnetArgs.builder()
.vpcId(main.id())
.availabilityZone("us-west-2a")
.cidrBlock("10.0.1.0/24")
.build());
var barSubnet = new Subnet("barSubnet", SubnetArgs.builder()
.vpcId(main.id())
.availabilityZone("us-west-2b")
.cidrBlock("10.0.2.0/24")
.build());
var bar = new Directory("bar", DirectoryArgs.builder()
.name("corp.notexample.com")
.password("SuperSecretPassw0rd")
.edition("Standard")
.type("MicrosoftAD")
.vpcSettings(DirectoryVpcSettingsArgs.builder()
.vpcId(main.id())
.subnetIds(
foo.id(),
barSubnet.id())
.build())
.tags(Map.of("Project", "foo"))
.build());
}
}
resources:
bar:
type: aws:directoryservice:Directory
properties:
name: corp.notexample.com
password: SuperSecretPassw0rd
edition: Standard
type: MicrosoftAD
vpcSettings:
vpcId: ${main.id}
subnetIds:
- ${foo.id}
- ${barSubnet.id}
tags:
Project: foo
main:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
foo:
type: aws:ec2:Subnet
properties:
vpcId: ${main.id}
availabilityZone: us-west-2a
cidrBlock: 10.0.1.0/24
barSubnet:
type: aws:ec2:Subnet
name: bar
properties:
vpcId: ${main.id}
availabilityZone: us-west-2b
cidrBlock: 10.0.2.0/24
The type property switches from SimpleAD to MicrosoftAD, and the edition property selects “Standard” or “Enterprise” (defaults to “Enterprise”). MicrosoftAD provides full Windows Server AD compatibility, including schema extensions and trust relationships. Like SimpleAD, it requires VPC placement with multi-AZ subnets.
Connect to an existing on-premises Active Directory
Organizations with existing on-premises AD infrastructure use ADConnector to proxy authentication requests from AWS to their domain controllers without replicating the directory.
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
const main = new aws.ec2.Vpc("main", {cidrBlock: "10.0.0.0/16"});
const foo = new aws.ec2.Subnet("foo", {
vpcId: main.id,
availabilityZone: "us-west-2a",
cidrBlock: "10.0.1.0/24",
});
const bar = new aws.ec2.Subnet("bar", {
vpcId: main.id,
availabilityZone: "us-west-2b",
cidrBlock: "10.0.2.0/24",
});
const connector = new aws.directoryservice.Directory("connector", {
name: "corp.notexample.com",
password: "SuperSecretPassw0rd",
size: "Small",
type: "ADConnector",
connectSettings: {
customerDnsIps: ["A.B.C.D"],
customerUsername: "Admin",
subnetIds: [
foo.id,
bar.id,
],
vpcId: main.id,
},
});
import pulumi
import pulumi_aws as aws
main = aws.ec2.Vpc("main", cidr_block="10.0.0.0/16")
foo = aws.ec2.Subnet("foo",
vpc_id=main.id,
availability_zone="us-west-2a",
cidr_block="10.0.1.0/24")
bar = aws.ec2.Subnet("bar",
vpc_id=main.id,
availability_zone="us-west-2b",
cidr_block="10.0.2.0/24")
connector = aws.directoryservice.Directory("connector",
name="corp.notexample.com",
password="SuperSecretPassw0rd",
size="Small",
type="ADConnector",
connect_settings={
"customer_dns_ips": ["A.B.C.D"],
"customer_username": "Admin",
"subnet_ids": [
foo.id,
bar.id,
],
"vpc_id": main.id,
})
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/directoryservice"
"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/ec2"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
main, err := ec2.NewVpc(ctx, "main", &ec2.VpcArgs{
CidrBlock: pulumi.String("10.0.0.0/16"),
})
if err != nil {
return err
}
foo, err := ec2.NewSubnet(ctx, "foo", &ec2.SubnetArgs{
VpcId: main.ID(),
AvailabilityZone: pulumi.String("us-west-2a"),
CidrBlock: pulumi.String("10.0.1.0/24"),
})
if err != nil {
return err
}
bar, err := ec2.NewSubnet(ctx, "bar", &ec2.SubnetArgs{
VpcId: main.ID(),
AvailabilityZone: pulumi.String("us-west-2b"),
CidrBlock: pulumi.String("10.0.2.0/24"),
})
if err != nil {
return err
}
_, err = directoryservice.NewDirectory(ctx, "connector", &directoryservice.DirectoryArgs{
Name: pulumi.String("corp.notexample.com"),
Password: pulumi.String("SuperSecretPassw0rd"),
Size: pulumi.String("Small"),
Type: pulumi.String("ADConnector"),
ConnectSettings: &directoryservice.DirectoryConnectSettingsArgs{
CustomerDnsIps: pulumi.StringArray{
pulumi.String("A.B.C.D"),
},
CustomerUsername: pulumi.String("Admin"),
SubnetIds: pulumi.StringArray{
foo.ID(),
bar.ID(),
},
VpcId: main.ID(),
},
})
if err != nil {
return err
}
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using Pulumi;
using Aws = Pulumi.Aws;
return await Deployment.RunAsync(() =>
{
var main = new Aws.Ec2.Vpc("main", new()
{
CidrBlock = "10.0.0.0/16",
});
var foo = new Aws.Ec2.Subnet("foo", new()
{
VpcId = main.Id,
AvailabilityZone = "us-west-2a",
CidrBlock = "10.0.1.0/24",
});
var bar = new Aws.Ec2.Subnet("bar", new()
{
VpcId = main.Id,
AvailabilityZone = "us-west-2b",
CidrBlock = "10.0.2.0/24",
});
var connector = new Aws.DirectoryService.Directory("connector", new()
{
Name = "corp.notexample.com",
Password = "SuperSecretPassw0rd",
Size = "Small",
Type = "ADConnector",
ConnectSettings = new Aws.DirectoryService.Inputs.DirectoryConnectSettingsArgs
{
CustomerDnsIps = new[]
{
"A.B.C.D",
},
CustomerUsername = "Admin",
SubnetIds = new[]
{
foo.Id,
bar.Id,
},
VpcId = main.Id,
},
});
});
package generated_program;
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.ec2.Vpc;
import com.pulumi.aws.ec2.VpcArgs;
import com.pulumi.aws.ec2.Subnet;
import com.pulumi.aws.ec2.SubnetArgs;
import com.pulumi.aws.directoryservice.Directory;
import com.pulumi.aws.directoryservice.DirectoryArgs;
import com.pulumi.aws.directoryservice.inputs.DirectoryConnectSettingsArgs;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;
public class App {
public static void main(String[] args) {
Pulumi.run(App::stack);
}
public static void stack(Context ctx) {
var main = new Vpc("main", VpcArgs.builder()
.cidrBlock("10.0.0.0/16")
.build());
var foo = new Subnet("foo", SubnetArgs.builder()
.vpcId(main.id())
.availabilityZone("us-west-2a")
.cidrBlock("10.0.1.0/24")
.build());
var bar = new Subnet("bar", SubnetArgs.builder()
.vpcId(main.id())
.availabilityZone("us-west-2b")
.cidrBlock("10.0.2.0/24")
.build());
var connector = new Directory("connector", DirectoryArgs.builder()
.name("corp.notexample.com")
.password("SuperSecretPassw0rd")
.size("Small")
.type("ADConnector")
.connectSettings(DirectoryConnectSettingsArgs.builder()
.customerDnsIps("A.B.C.D")
.customerUsername("Admin")
.subnetIds(
foo.id(),
bar.id())
.vpcId(main.id())
.build())
.build());
}
}
resources:
connector:
type: aws:directoryservice:Directory
properties:
name: corp.notexample.com
password: SuperSecretPassw0rd
size: Small
type: ADConnector
connectSettings:
customerDnsIps:
- A.B.C.D
customerUsername: Admin
subnetIds:
- ${foo.id}
- ${bar.id}
vpcId: ${main.id}
main:
type: aws:ec2:Vpc
properties:
cidrBlock: 10.0.0.0/16
foo:
type: aws:ec2:Subnet
properties:
vpcId: ${main.id}
availabilityZone: us-west-2a
cidrBlock: 10.0.1.0/24
bar:
type: aws:ec2:Subnet
properties:
vpcId: ${main.id}
availabilityZone: us-west-2b
cidrBlock: 10.0.2.0/24
ADConnector uses connectSettings instead of vpcSettings. The customerDnsIps property points to your on-premises domain controllers, and customerUsername specifies an AD account with permissions to join computers to the domain. AWS routes authentication requests through the connector to your existing directory, requiring VPN or Direct Connect connectivity between your VPC and on-premises network.
Beyond these examples
These snippets focus on specific directory-level features: SimpleAD, MicrosoftAD, and ADConnector deployment, and VPC placement and multi-AZ configuration. They’re intentionally minimal rather than full identity management solutions.
The examples may reference pre-existing infrastructure such as VPC and subnets (examples create inline but users typically reference existing), on-premises Active Directory (for ADConnector), and network connectivity (VPN/Direct Connect for ADConnector). They focus on configuring the directory rather than provisioning everything around it.
To keep things focused, common directory patterns are omitted, including:
- Single sign-on configuration (enableSso, alias)
- Domain controller scaling (desiredNumberOfDomainControllers)
- Directory sharing and trust relationships
- Conditional forwarders and DNS integration
These omissions are intentional: the goal is to illustrate how each directory type is wired, not provide drop-in identity modules. See the Directory Service Directory resource reference for all available configuration options.
Let's create AWS Directory Service Directories
Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.
Try Pulumi Cloud for FREEFrequently Asked Questions
Directory Types & Configuration
SimpleAD (default), ADConnector, or MicrosoftAD directories using the type property.SimpleAD and ADConnector support Small or Large sizes (defaults to Large). MicrosoftAD doesn’t use the size property.MicrosoftAD supports Standard or Enterprise editions (defaults to Enterprise). Other directory types don’t use the edition property.Networking & VPC Setup
vpcSettings for SimpleAD and MicrosoftAD directories. Use connectSettings for ADConnector directories, which includes customerDnsIps and customerUsername.Immutability & Limitations
alias, edition, name, password, shortName, size, type, connectSettings, description, and vpcSettings.MicrosoftAD directories support scaling domain controllers using desiredNumberOfDomainControllers (minimum value of 2).Authentication & Access
enableSso to true and provide an alias property. SSO requires the alias to be configured.corp.example.com for the name property, as shown in all examples.