Deploying Windows EC2 instance using Terraform

Posted: January 8, 2018 in Amazon Web Services (AWS), AWS, Linux, terraform

In one of previous posts we deployed Linux Amazon instance using Terraform, now we’ll deploy Windows Server. Unlike previous approach, now we’ll store AWS Access Keys in separate file.

I created terraform.tfvars and stored keys there

AWS_ACCESS_KEY="some key"
AWS_SECRET_KEY="some keys"

There i also put Windows Server password

File contains variable and AMIs

variable "AWS_ACCESS_KEY" {}
variable "AWS_SECRET_KEY" {}
variable "AWS_REGION" { 
default = "eu-west-1" 
variable "WIN_AMIS" {
type = "map" default = { 
us-east-1 = "ami-30540427"
us-west-2 = "ami-9f5efbff"
eu-west-1 = "ami-0f26101934dec146b" 
variable "PATH_TO_PRIVATE_KEY" { default = "mykey" } 
variable "PATH_TO_PUBLIC_KEY" { default = "" 
variable "INSTANCE_USERNAME" { default = "admin" } 
variable "INSTANCE_PASSWORD" { }

In order to find out Window server AMI in AWS console go to EC2-Launch instance-Community AMIs, in search box type Windows, scroll until you find desired image and locate AMI-put that value into


in i put reference to terraform.tfvars

provider "aws" { 
access_key = "${var.AWS_ACCESS_KEY}"
secret_key = "${var.AWS_SECRET_KEY}"
region = "${var.AWS_REGION}" }

terraform {
  required_version = ">= 0.12"

In is code for deploying Windows server:

resource "aws_key_pair" "mykey" {
  key_name   = "mykey"
  public_key = file(var.PATH_TO_PUBLIC_KEY)

data "template_file" "userdata_win" {
  template = <<EOF
echo "" > _INIT_STARTED_
net user ${var.INSTANCE_USERNAME} /add /y
net localgroup administrators ${var.INSTANCE_USERNAME} /add
echo ${base64encode(file("./test.txt"))} > tmp2.b64 && certutil -decode tmp2.b64 C:/test.txt
echo "" > _INIT_COMPLETE_

resource "aws_instance" "win-example" {
  ami           = var.WIN_AMIS[var.AWS_REGION]
  instance_type = "t2.micro"
  key_name      = aws_key_pair.mykey.key_name
  user_data = data.template_file.userdata_win.rendered

  tags = {
    Name = "Windows_Server"


output "ip" {



It will create key pair, set AMI, create security group and add EC2 instance to it.

In template_file section, new local windows user will be created named terraform, and added to local administrators group, also local file test.txt will be copied to ec2 instance to C drive.

File contain security group definition, i just allowed traffic to all ports from anywhere (not a good security practice)

resource "aws_security_group" "allow-all" {
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = [""]
ingress {
from_port = 0
to_port = 6556
protocol = "tcp"
cidr_blocks = [""]

tags = {
    Name = "allow_RDP"


Create key pair:

ssh-keygen -f mykey

Now test for errors and apply configuration :

 terraform init && terraform plan && terraform apply
  1. santhosh kumar says:

    hi i follwed this code as it is but i could not spin up up an instance please guide me how to connect to this instance also

    Liked by 1 person

  2. Kent says:

    Error: Unknown root level key: user_data

    Liked by 1 person

  3. Luk says:

    It does not work for me, well at least not completely. Still creating… (9m30s elapsed) Still creating… (9m40s elapsed) Still creating… (9m50s elapsed) Still creating… (10m0s elapsed) Still creating… (10m10s elapsed) Still creating… (10m20s elapsed)

    Error: Error applying plan:

    1 error(s) occurred:

    * timeout – last error: unknown error Post dial tcp i/o timeout

    It deploys win server though. When I log in using aws console I see that win instance is there but not configured because of that error.
    The only difference in my code is region “us-west-2” and of course ami “ami-c9deafb1” (win 2k16 server)
    Any advice?

    Liked by 1 person

  4. Kraemer says:

    i think it is nice but i search , how to join to a windows domain with Terraform.
    Have anybody an idea?


  5. Anish says:

    Error: Error applying plan:

    1 error(s) occurred:

    * 1 error(s) occurred:

    * unknown error Post dial tcp i/o timeout

    Terraform does not automatically rollback in the face of errors.
    Instead, your Terraform state file has been partially updated with
    any resources that successfully completed. Please address the error
    above and apply again to incrementally change your infrastructure.

    Any help is greatly appreciated


  6. JC says:
    type = “map” default = {
    (was throwing an error, changed default ={ to be on a separate line)
    tags {
    (throwing an error, changed to tags = {)

    Liked by 1 person

  7. RS says:

    I am trying to get the password of the ec2 instance once it is launched like the way you have described. How can I get it ? I am trying to do this command
    `aws ec2 get-password-data –instance-id “id” –priv-launch-key ~/Downloads/.pem` How can I provide the .pem file for authorization?


  8. Chris Topinka says:

    In aws instance launch it states “requires vpc”. Does this provisioner assume vpc exists?


  9. Justin Rousseau says:

    Is there a clean way to specify a version of Windows Server (say Windows Server 2019 for instance) and just always use the latest released/patched version available instead of indicating a specific AMI?


  10. kirupakaran says:

    I am working on terraform script for creating windows VM by having “C” & “D” Drive
    Any sample repo for this


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s