Import Terraform Modules
Leverage the module ecosystem
Pulumi can directly use existing Terraform modules from the Terraform Registry, private registries, or local sources. This allows you to access thousands of existing modules without rewriting them in Pulumi.
Add Terraform modules
Use the pulumi package add
command to add Terraform modules to your project:
# Add a module from the Terraform Registry
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
# Add a local module
$ pulumi package add terraform-module ./path/to/module localmod
Example: AWS VPC module
Let’s use the popular AWS vpc
module to create a VPC with subnets, and then deploy an EC2 instance in that VPC:
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test
$ pulumi new aws-typescript --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as vpc from "@pulumi/vpc";
// Use the Terraform VPC module
const myVpc = new vpc.Module("my-vpc", {
name: "my-vpc",
cidr: "10.0.0.0/16",
azs: ["us-west-2a", "us-west-2b", "us-west-2c"],
public_subnets: ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"],
private_subnets: ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"],
enable_nat_gateway: true,
enable_vpn_gateway: true,
tags: {
Terraform: "true",
Environment: "dev",
},
});
// Create a security group
const webSg = new aws.ec2.SecurityGroup("web-sg", {
name: "web-sg",
description: "Security group for web servers",
vpcId: myVpc.vpc_id.apply(id => id!),
ingress: [
{
description: "HTTP",
fromPort: 80,
toPort: 80,
protocol: "tcp",
cidrBlocks: ["0.0.0.0/0"],
},
{
description: "SSH",
fromPort: 22,
toPort: 22,
protocol: "tcp",
cidrBlocks: ["0.0.0.0/0"],
},
],
egress: [
{
fromPort: 0,
toPort: 0,
protocol: "-1",
cidrBlocks: ["0.0.0.0/0"],
},
],
});
// Get the latest Amazon Linux 2 AMI
const amazonLinux = aws.ec2.getAmiOutput({
mostRecent: true,
owners: ["amazon"],
filters: [
{
name: "name",
values: ["amzn2-ami-hvm-*-x86_64-gp2"],
},
],
});
// Create an EC2 instance in the VPC
const webServer = new aws.ec2.Instance("web-server", {
ami: amazonLinux.id,
instanceType: "t3.micro",
subnetId: myVpc.public_subnets.apply(subnets => subnets![0]),
vpcSecurityGroupIds: [webSg.id],
associatePublicIpAddress: true,
userData: `#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html
`,
tags: {
Name: "web-server",
Environment: "dev",
},
});
// Output important information
export const vpcId = myVpc.vpc_id;
export const instanceId = webServer.id;
export const publicIp = webServer.publicIp;
export const websiteUrl = pulumi.interpolate`http://${webServer.publicIp}`;
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test
$ pulumi new aws-python --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
import pulumi
import pulumi_aws as aws
import pulumi_vpc as vpc
# Use the Terraform VPC module
my_vpc = vpc.Module("my-vpc",
name="my-vpc",
cidr="10.0.0.0/16",
azs=["us-west-2a", "us-west-2b", "us-west-2c"],
public_subnets=["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"],
private_subnets=["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"],
enable_nat_gateway=True,
enable_vpn_gateway=True,
tags={
"Terraform": "true",
"Environment": "dev",
}
)
# Create a security group
web_sg = aws.ec2.SecurityGroup("web-sg",
name="web-sg",
description="Security group for web servers",
vpc_id=my_vpc.vpc_id.apply(lambda id: id),
ingress=[
{
"description": "HTTP",
"from_port": 80,
"to_port": 80,
"protocol": "tcp",
"cidr_blocks": ["0.0.0.0/0"],
},
{
"description": "SSH",
"from_port": 22,
"to_port": 22,
"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"],
}
]
)
# Get the latest Amazon Linux 2 AMI
amazon_linux = aws.ec2.get_ami(
most_recent=True,
owners=["amazon"],
filters=[
{
"name": "name",
"values": ["amzn2-ami-hvm-*-x86_64-gp2"],
}
]
)
# Create an EC2 instance in the VPC
web_server = aws.ec2.Instance("web-server",
ami=amazon_linux.id,
instance_type="t3.micro",
subnet_id=my_vpc.public_subnets.apply(lambda subnets: subnets[0]),
vpc_security_group_ids=[web_sg.id],
associate_public_ip_address=True,
user_data="""#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html
""",
tags={
"Name": "web-server",
"Environment": "dev",
}
)
# Output important information
pulumi.export("vpcId", my_vpc.vpc_id)
pulumi.export("instanceId", web_server.id)
pulumi.export("publicIp", web_server.public_ip)
pulumi.export("websiteUrl", pulumi.Output.format("http://{0}", web_server.public_ip))
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test
$ pulumi new aws-go --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"
vpc "github.com/pulumi/pulumi-terraform-module/sdks/go/vpc/v6/vpc"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Use the Terraform VPC module
myVpc, err := vpc.NewModule(ctx, "my-vpc", &vpc.ModuleArgs{
Name: pulumi.String("my-vpc"),
Cidr: pulumi.String("10.0.0.0/16"),
Azs: pulumi.StringArray{pulumi.String("us-west-2a"), pulumi.String("us-west-2b"), pulumi.String("us-west-2c")},
Private_subnets: pulumi.StringArray{pulumi.String("10.0.1.0/24"), pulumi.String("10.0.2.0/24"), pulumi.String("10.0.3.0/24")},
Public_subnets: pulumi.StringArray{pulumi.String("10.0.10.0/24"), pulumi.String("10.0.11.0/24"), pulumi.String("10.0.12.0/24")},
Enable_nat_gateway: pulumi.Bool(true),
Enable_vpn_gateway: pulumi.Bool(true),
Tags: pulumi.StringMap{
"Terraform": pulumi.String("true"),
"Environment": pulumi.String("dev"),
},
})
if err != nil {
return err
}
// Get the latest Amazon Linux 2 AMI
amazonLinux, err := ec2.LookupAmi(ctx, &ec2.LookupAmiArgs{
MostRecent: pulumi.BoolRef(true),
Owners: []string{"amazon"},
Filters: []ec2.GetAmiFilter{
{
Name: "name",
Values: []string{"amzn2-ami-hvm-*-x86_64-gp2"},
},
},
})
if err != nil {
return err
}
// Create a security group
webSg, err := ec2.NewSecurityGroup(ctx, "web-sg", &ec2.SecurityGroupArgs{
Name: pulumi.String("web-sg"),
Description: pulumi.String("Security group for web servers"),
VpcId: myVpc.Vpc_id,
Ingress: ec2.SecurityGroupIngressArray{
&ec2.SecurityGroupIngressArgs{
Description: pulumi.String("HTTP"),
FromPort: pulumi.Int(80),
ToPort: pulumi.Int(80),
Protocol: pulumi.String("tcp"),
CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
},
&ec2.SecurityGroupIngressArgs{
Description: pulumi.String("SSH"),
FromPort: pulumi.Int(22),
ToPort: pulumi.Int(22),
Protocol: pulumi.String("tcp"),
CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
},
},
Egress: ec2.SecurityGroupEgressArray{
&ec2.SecurityGroupEgressArgs{
FromPort: pulumi.Int(0),
ToPort: pulumi.Int(0),
Protocol: pulumi.String("-1"),
CidrBlocks: pulumi.StringArray{pulumi.String("0.0.0.0/0")},
},
},
})
if err != nil {
return err
}
// Create an EC2 instance in the VPC
webServer, err := ec2.NewInstance(ctx, "web-server", &ec2.InstanceArgs{
Ami: pulumi.String(amazonLinux.Id),
InstanceType: pulumi.String("t3.micro"),
SubnetId: myVpc.Public_subnets.ApplyT(func(subnets []string) string {
return subnets[0]
}).(pulumi.StringOutput),
VpcSecurityGroupIds: pulumi.StringArray{webSg.ID()},
AssociatePublicIpAddress: pulumi.Bool(true),
UserData: pulumi.String(`#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html
`),
Tags: pulumi.StringMap{
"Name": pulumi.String("web-server"),
"Environment": pulumi.String("dev"),
},
})
if err != nil {
return err
}
// Output important information
ctx.Export("vpcId", myVpc.Vpc_id)
ctx.Export("instanceId", webServer.ID())
ctx.Export("publicIp", webServer.PublicIp)
ctx.Export("websiteUrl", pulumi.Sprintf("http://%s", webServer.PublicIp))
return nil
})
}
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test
$ pulumi new aws-csharp --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
The pulumi package add ...
command will add the required dependencies to the solution file, but you’ll need to manually add the following directive:
<PropertyGroup>
<!-- ... -->
<DefaultItemExcludes>$(DefaultItemExcludes);sdks/**/*.cs</DefaultItemExcludes>
</PropertyGroup>
Then use it in your Pulumi program:
using System.Collections.Generic;
using Pulumi;
using Pulumi.Aws.Ec2;
using Pulumi.Vpc;
return await Deployment.RunAsync(() =>
{
// Use the Terraform VPC module
var myVpc = new Vpc("my-vpc", new VpcArgs
{
Name = "my-vpc",
Cidr = "10.0.0.0/16",
Azs = new[] { "us-west-2a", "us-west-2b", "us-west-2c" },
PrivateSubnets = new[] { "10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24" },
PublicSubnets = new[] { "10.0.101.0/24", "10.0.102.0/24", "10.0.103.0/24" },
EnableNatGateway = true,
EnableVpnGateway = true,
Tags = new Dictionary<string, string>
{
["Terraform"] = "true",
["Environment"] = "dev",
},
});
// Get the latest Amazon Linux 2 AMI
var amazonLinux = GetAmi.Invoke(new GetAmiInvokeArgs
{
MostRecent = true,
Owners = new[] { "amazon" },
Filters = new[]
{
new GetAmiFilterInputArgs
{
Name = "name",
Values = new[] { "amzn2-ami-hvm-*-x86_64-gp2" },
},
},
});
// Create a security group
var webSg = new SecurityGroup("web-sg", new SecurityGroupArgs
{
Name = "web-sg",
Description = "Security group for web servers",
VpcId = myVpc.VpcId,
Ingress = new[]
{
new SecurityGroupIngressArgs
{
Description = "HTTP",
FromPort = 80,
ToPort = 80,
Protocol = "tcp",
CidrBlocks = new[] { "0.0.0.0/0" },
},
new SecurityGroupIngressArgs
{
Description = "SSH",
FromPort = 22,
ToPort = 22,
Protocol = "tcp",
CidrBlocks = new[] { "0.0.0.0/0" },
},
},
Egress = new[]
{
new SecurityGroupEgressArgs
{
FromPort = 0,
ToPort = 0,
Protocol = "-1",
CidrBlocks = new[] { "0.0.0.0/0" },
},
},
});
// Create an EC2 instance in the VPC
var webServer = new Instance("web-server", new InstanceArgs
{
Ami = amazonLinux.Apply(ami => ami.Id),
InstanceType = "t3.micro",
SubnetId = myVpc.PublicSubnets.Apply(subnets => subnets[0]),
VpcSecurityGroupIds = new[] { webSg.Id },
AssociatePublicIpAddress = true,
UserData = @"#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo ""<h1>Hello from Pulumi and Terraform modules!</h1>"" > /var/www/html/index.html
",
Tags = new Dictionary<string, string>
{
["Name"] = "web-server",
["Environment"] = "dev",
},
});
return new Dictionary<string, object?>
{
["vpcId"] = myVpc.VpcId,
["publicSubnets"] = myVpc.PublicSubnets,
["privateSubnets"] = myVpc.PrivateSubnets,
["instanceId"] = webServer.Id,
["publicIp"] = webServer.PublicIp,
["websiteUrl"] = webServer.PublicIp.Apply(ip => $"http://{ip}"),
};
});
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test
$ pulumi new aws-java --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
The pulumi package add ...
command will output some important instructions. There are two steps you must perform manually: copy the contents of the generated SDK to your Java project, and add the dependencies to pom.xml
:
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>
</dependencies>
Then use it in your Pulumi program, by replacing the contents of src/main/java/myproject/App.java
with:
package myproject;
import com.pulumi.Pulumi;
import com.pulumi.aws.ec2.Ec2Functions;
import com.pulumi.aws.ec2.Instance;
import com.pulumi.aws.ec2.InstanceArgs;
import com.pulumi.aws.ec2.SecurityGroup;
import com.pulumi.aws.ec2.SecurityGroupArgs;
import com.pulumi.aws.ec2.inputs.GetAmiArgs;
import com.pulumi.aws.ec2.inputs.GetAmiFilterArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupEgressArgs;
import com.pulumi.aws.ec2.inputs.SecurityGroupIngressArgs;
import java.util.Collections;
import java.util.Map;
public class App {
public static void main(String[] args) {
Pulumi.run(ctx -> {
// Use the Terraform VPC module
var myVpc = new com.pulumi.vpc.Module("my-vpc", com.pulumi.vpc.ModuleArgs.builder()
.name("my-vpc")
.cidr("10.0.0.0/16")
.azs("us-west-2a", "us-west-2b", "us-west-2c")
.private_subnets("10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24")
.public_subnets("10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24")
.enable_nat_gateway(true)
.enable_vpn_gateway(true)
.tags(Map.of(
"Terraform", "true",
"Environment", "dev"
))
.build());
// Get the latest Amazon Linux 2 AMI
var amazonLinux = Ec2Functions.getAmi(GetAmiArgs.builder()
.mostRecent(true)
.owners("amazon")
.filters(GetAmiFilterArgs.builder()
.name("name")
.values("amzn2-ami-hvm-*-x86_64-gp2")
.build())
.build());
// Create a security group
var webSg = new SecurityGroup("web-sg", SecurityGroupArgs.builder()
.name("web-sg")
.description("Security group for web servers")
.vpcId(myVpc.vpc_id().applyValue(id->id.get()).applyValue(String::valueOf))
.ingress(
SecurityGroupIngressArgs.builder()
.description("HTTP")
.fromPort(80)
.toPort(80)
.protocol("tcp")
.cidrBlocks("0.0.0.0/0")
.build(),
SecurityGroupIngressArgs.builder()
.description("SSH")
.fromPort(22)
.toPort(22)
.protocol("tcp")
.cidrBlocks("0.0.0.0/0")
.build()
)
.egress(SecurityGroupEgressArgs.builder()
.fromPort(0)
.toPort(0)
.protocol("-1")
.cidrBlocks("0.0.0.0/0")
.build())
.build());
// Output<List<String>> secGrps = webSg.id().applyValue(s -> Collections.singletonList(s));
// Create an EC2 instance in the VPC
var webServer = new Instance("web-server", InstanceArgs.builder()
.ami(amazonLinux.applyValue(ami -> ami.id()))
.instanceType("t3.micro")
.subnetId(myVpc.public_subnets().applyValue(subnets -> subnets.get().get(0)))
.vpcSecurityGroupIds(webSg.id().applyValue(s -> Collections.singletonList(s)))
.associatePublicIpAddress(true)
.userData(String.join("\n",
"#!/bin/bash",
"yum update -y",
"yum install -y httpd",
"systemctl start httpd",
"systemctl enable httpd",
"echo \"<h1>Hello from Pulumi and Terraform modules!</h1>\" > /var/www/html/index.html"
))
.tags(Map.of(
"Name", "web-server",
"Environment", "dev"
))
.build());
// Output important information
ctx.export("vpcId", myVpc.vpc_id());
ctx.export("instanceId", webServer.id());
ctx.export("publicIp", webServer.publicIp());
ctx.export("websiteUrl", webServer.publicIp().applyValue(ip -> String.format("http://%s", ip)));
});
}
}
First, create a new Pulumi program:
$ mkdir pulumi-terraform-modules-test && cd pulumi-terraform-modules-test
$ pulumi new aws-yaml --yes
Next, add the VPC module:
$ pulumi package add terraform-module terraform-aws-modules/vpc/aws 6.0.0 vpc
Then use it in your Pulumi program:
name: pulumi-terraform-modules-example
runtime: yaml
description: Use Terraform modules in Pulumi
variables:
# Get the latest Amazon Linux 2 AMI
amazonLinux:
fn::invoke:
function: aws:ec2:getAmi
arguments:
mostRecent: true
owners: ["amazon"]
filters:
- name: name
values: ["amzn2-ami-hvm-*-x86_64-gp2"]
resources:
# Use the Terraform VPC module
my-vpc:
type: vpc:index:Module
properties:
name: my-vpc
cidr: 10.0.0.0/16
azs: ["us-west-2a", "us-west-2b", "us-west-2c"]
private_subnets: ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets: ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"]
enable_nat_gateway: true
enable_vpn_gateway: true
tags:
Terraform: "true"
Environment: "dev"
# Create a security group
web-sg:
type: aws:ec2:SecurityGroup
properties:
name: web-sg
description: Security group for web servers
vpcId: ${my-vpc.vpc_id}
ingress:
- description: HTTP
fromPort: 80
toPort: 80
protocol: tcp
cidrBlocks: ["0.0.0.0/0"]
- description: SSH
fromPort: 22
toPort: 22
protocol: tcp
cidrBlocks: ["0.0.0.0/0"]
egress:
- fromPort: 0
toPort: 0
protocol: "-1"
cidrBlocks: ["0.0.0.0/0"]
# Create an EC2 instance in the VPC
web-server:
type: aws:ec2:Instance
properties:
ami: ${amazonLinux.id}
instanceType: t3.micro
subnetId: ${my-vpc.public_subnets[0]}
vpcSecurityGroupIds:
- ${web-sg.id}
associatePublicIpAddress: true
userData: |
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html
tags:
Name: web-server
Environment: dev
outputs:
vpcId: ${my-vpc.vpc_id}
instanceId: ${web-server.id}
publicIp: ${web-server.publicIp}
websiteUrl: http://${web-server.publicIp}
# The vpc Terraform module package definition
packages:
vpc:
source: terraform-module
version: 0.1.4
parameters:
- terraform-aws-modules/vpc/aws
- 6.0.0
- vpc
Compare with Terraform
The same functionality in Terraform would look like:
# Terraform equivalent
module "vpc" {
source = "terraform-aws-modules/vpc/aws"
name = "my-vpc"
cidr = "10.0.0.0/16"
azs = ["us-west-2a", "us-west-2b", "us-west-2c"]
private_subnets = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"]
public_subnets = ["10.0.10.0/24", "10.0.11.0/24", "10.0.12.0/24"]
enable_nat_gateway = true
enable_vpn_gateway = true
tags = {
Terraform = "true"
Environment = "dev"
}
}
data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm-*-x86_64-gp2"]
}
}
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Security group for web servers"
vpc_id = module.vpc.vpc_id
ingress {
description = "HTTP"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
description = "SSH"
from_port = 22
to_port = 22
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"]
}
}
resource "aws_instance" "web_server" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
subnet_id = module.vpc.public_subnets[0]
vpc_security_group_ids = [aws_security_group.web_sg.id]
associate_public_ip_address = true
user_data = <<-EOF
#!/bin/bash
yum update -y
yum install -y httpd
systemctl start httpd
systemctl enable httpd
echo "<h1>Hello from Pulumi and Terraform modules!</h1>" > /var/www/html/index.html
EOF
tags = {
Name = "web-server"
Environment = "dev"
}
}
output "vpc_id" {
value = module.vpc.vpc_id
}
output "instance_id" {
value = aws_instance.web_server.id
}
output "public_ip" {
value = aws_instance.web_server.public_ip
}
output "website_url" {
value = "http://${aws_instance.web_server.public_ip}"
}
Best practices
- Pin module versions: Always specify module versions in production
- Review module source: Understand what the module does before using it
- Test module outputs: Verify that module outputs work as expected
- Monitor module updates: Keep track of module updates and breaking changes
- Use reputable sources: Prefer well-maintained modules from trusted sources
- Document module usage: Document why you chose specific modules and their configuration
Clean up
Test your deployment and clean up resources:
# Deploy the stack
$ pulumi up
# Visit the website URL from the output
# When done, destroy the resources
$ pulumi destroy
Thank you for your feedback!
If you have a question about how to use Pulumi, reach out in Community Slack.
Open an issue on GitHub to report a problem or suggest an improvement.