Archive for January, 2018

In one of previous posts we created multiple EC2 instances using modules, instead of using modules, we can just add following line instance.tf file

count=X (where X is number of instances
tags {
Name="${format("test-%01d",count.index+1)}"
}

01d is number of “zero” prefixes-1 (test-01) if we want more zeros change number in front of d (test-%03d would be test002,for example).For the sake of simplicity i created just one terraform file

provider "aws" {
access_key="access keys here"
secret_key="secret keys here"
region = "eu-west-1"
}

variable "count" {
default=2
}


resource "aws_instance" "example" {
count="${var.count}"
ami = "ami-d834aba1"
instance_type = "t2.micro"
tags { Name="${format("test-%01d",count.index+1)}" }
}

output "ip" {
    value = "${aws_instance.example.*.public_ip}"
}

In this case 2 instances were created, with test-1/2 tags

1

Advertisements

Creating key pair on Ansible server

ssh-keygen

Private/public key will be created

1.PNG

Copy content of pub file to clipboard, make ssh connection to remote machine which will be managed by Ansible

ssh root@10.0.0.5

copy public key to ~/.ssh/authorized_keys from clipboard

[root@web .ssh]# cat authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDLIXNj9M0GsRJMml6VqH0eN0krM0O6A83D5V2PK0V/Qib6YPUcq9W5kq89BDIub86owmTQZ8pQwKqvQNPkZ/+MmIxdBE2Dfa7/dSsSpmP7EKs5HLHsd9KRapbzk3tSgAtX9dkcs2MioZbTjxA2P1r2N3nIxTjyYzkorUvBQX+unPLqSS5l9t+ByP7LJYOFZdlrkvtbICnsp4dOzW7+f0E+HKMYLpT/KerN245ot//COoVTjxshbcRcry4Olv3qO2yvKZBlRx5zZAWJcUXlNCm5axNTGUBP+ohcHEois5nBSXf9VrIEPF+hpk4XeBEAMAnIe+MTTxlKqBafGTv2SvNN root@ansible

Connecting to Amazon EC2 instance

We need first to copy key pair from Amazon to Ansible server (with pem extension)

1.PNG

Add following lines to /etc/ansible/hosts (create it if don’t exists)

[aws_server]
aws_instance ansible_host='public ip' ansible_user='ec2-user' ansible_ssh_private_key_file='/myproject/test.pem'

 

In previous post we collected Subscription ID, tenant ID,Client ID and Client secret.Now it’s time to use it.

terraform.tfvars (all sensitive data are stored in this file, it shouldn’t be publicly accessible, here are stored credentials for virtual machine

AZURE_SUBSCRIPTION_ID="some ID"
AZURE_CLIENT_ID="client id"
AZURE_CLIENT_SECRET="secret"
AZURE_TENANT_ID="tenant id"
VM_ADMIN="ja"
VM_PASSWORD="Passw0rd01234!"

vars.tf  (variables are declared in this file)

variable "AZURE_SUBSCRIPTION_ID" {}
variable "AZURE_CLIENT_ID" {}
variable "AZURE_CLIENT_SECRET" {}
variable "AZURE_TENANT_ID" {} 

#to get all sizes:https://docs.microsoft.com/en-us/azure/virtual-machines/windows/sizes-general

variable "vm_size" {
// Get-AzureRmVMSize -Location 'uksouth' | select name, NumberOfCores, MemoryInMB, ResourceDiskSizeInMB | ft
//https://azure.microsoft.com/en-us/documentation/articles/cloud-services-sizes-specs/
//https://azure.microsoft.com/en-gb/documentation/articles/virtual-machines-windows-sizes/
//https://azure.microsoft.com/en-us/pricing/details/virtual-machines/windows/
description = "VM instance size"
default = "Standard_B1ms"
}

variable "vm_image_publisher" {
// Get-AzureRmVMImagePublisher -Location 'uksouth' | Select PublisherName
description = "vm image vendor"
default = "MicrosoftWindowsServer"
}
variable "vm_image_offer" {
//Get-AzureRMVMImageOffer -Location 'uksouth' -Publisher 'MicrosoftWindowsServer' | Select Offer
description = "vm image vendor's VM offering"
default = "WindowsServer"
}

variable "vm_image_sku" {
default = "2016-Datacenter"
}

variable "vm_image_version" {
description = "vm image version"
default = "latest"
}
variable "VM_ADMIN" {
//Disallowed values: "administrator", "admin", "user", "user1", "test", "user2", "test1", "user3", "admin1", "1", "123", "a", "actuser", "adm", "admin2", "aspnet", "backup", "console", "david", "guest", "john", "owner", "root", "server", "sql", "support", "support_388945a0", "sys", "test2", "test3", "user4", "user5".
}

variable "VM_PASSWORD" {
}

provider.tf (used to connect and authorize terraform agains Azure)

provider "azurerm" {
subscription_id="${var.AZURE_SUBSCRIPTION_ID}"
client_id="${var.AZURE_CLIENT_ID}"
client_secret="${var.AZURE_CLIENT_SECRET}"
tenant_id="${var.AZURE_TENANT_ID}"
}

storage.tf (storage account is defined here)

resource "azurerm_storage_account" "storage_acc" {
name = "mystorageaccount201801"
resource_group_name = "${azurerm_resource_group.res_group.name}"
location = "${azurerm_resource_group.res_group.location}"
account_tier = "Standard"
account_replication_type = "LRS"

tags {
environment = "Storage-Acount-Test"
}
}

rg.tf (resource group is specified here)

resource "azurerm_resource_group" "res_group" {
  name     = "myrg1"
  location = "West Europe"
}

virtual_network.tf-in this file virtual network,public IP and subnets are specified

#Create Public IP

resource "azurerm_public_ip" "datasourceip" {
name = "testPublicIp"
location="${azurerm_resource_group.res_group.location}"
resource_group_name = "${azurerm_resource_group.res_group.name}"
public_ip_address_allocation="dynamic"
}

 

# Create a virtual network within the resource group
resource "azurerm_virtual_network" "my_virt_net" {
name = "production-network"
address_space = ["10.0.0.0/16"]
location = "${azurerm_resource_group.res_group.location}"
resource_group_name = "${azurerm_resource_group.res_group.name}"

}

#create subnets
resource "azurerm_subnet" "test1" {
name = "subnet1"
resource_group_name = "${azurerm_resource_group.res_group.name}"
virtual_network_name="${azurerm_virtual_network.my_virt_net.name}"
address_prefix = "10.0.1.0/24"
}

resource "azurerm_subnet" "test2" {
name = "subnet2"
resource_group_name = "${azurerm_resource_group.res_group.name}"
virtual_network_name="${azurerm_virtual_network.my_virt_net.name}"
address_prefix = "10.0.2.0/24"
}

resource "azurerm_subnet" "test3" {
name = "subnet3"
resource_group_name = "${azurerm_resource_group.res_group.name}"
virtual_network_name="${azurerm_virtual_network.my_virt_net.name}"
address_prefix = "10.0.3.0/24"
}

 

#Create network interface

resource "azurerm_network_interface" "my_int" {
name = "myWindowsServer_NIC"
location = "${azurerm_resource_group.res_group.location}"
resource_group_name = "${azurerm_resource_group.res_group.name}"
#network_security_group_id = "${var.vm_security_group_id}"
ip_configuration {
name = "Server2016"
subnet_id = "${azurerm_subnet.test1.id}"
private_ip_address_allocation = "dynamic"
public_ip_address_id = "${azurerm_public_ip.datasourceip.id}"
}
}

vm.tf – Virtual machine details are specified here, 2 additional disks will be attached

resource "azurerm_managed_disk" "test" {
name = "datadisk_existing"
location="${azurerm_resource_group.res_group.location}"
resource_group_name = "${azurerm_resource_group.res_group.name}"
storage_account_type = "Standard_LRS"
create_option = "Empty"
disk_size_gb = "1023"
}

resource "azurerm_virtual_machine" "test" {
name = "myvm"
location="${azurerm_resource_group.res_group.location}"
resource_group_name = "${azurerm_resource_group.res_group.name}"
network_interface_ids = ["${azurerm_network_interface.my_int.id}"]
vm_size = "Standard_DS1_v2"
delete_os_disk_on_termination = "true"
delete_data_disks_on_termination = "true"

storage_image_reference {
publisher = "${var.vm_image_publisher}"
offer = "${var.vm_image_offer}"
sku = "${var.vm_image_sku}"
version = "${var.vm_image_version}"
}

storage_os_disk {
name = "datadisk_new_2018_01"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type="Standard_LRS"
}

# Adding additional disk 1

storage_data_disk {
name = "datadisk_new"
managed_disk_type = "Standard_LRS"
create_option = "Empty"
lun = 0
disk_size_gb = "1023"
}

#Additional disk 2

storage_data_disk {
name = "${azurerm_managed_disk.test.name}"
managed_disk_id = "${azurerm_managed_disk.test.id}"
create_option = "Attach"
lun = 1
disk_size_gb = "${azurerm_managed_disk.test.disk_size_gb}"
}

#define credentials
os_profile {
computer_name = "SERVER2016"
admin_username = "${var.VM_ADMIN}"
admin_password = "${var.VM_PASSWORD}"
}

os_profile_windows_config {
provision_vm_agent = "true"
enable_automatic_upgrades = "true"
winrm {
protocol = "http"
certificate_url =""
}
}

}

#get public IP
data "azurerm_public_ip" "test" {
name = "${azurerm_public_ip.datasourceip.name}"
resource_group_name = "${azurerm_resource_group.res_group.name}"
depends_on = ["azurerm_virtual_machine.test"]
}

output "ip_address" {
value = "${data.azurerm_public_ip.test.ip_address}"
}

 

1.PNG

 

2.PNG

 

In order for terraform to deploy resources to Azure, it has to be authenticated

Creating Application registration

In Azure portal click Azure Active Directory-App registration-New Application registration

 

1.png

 

Give it name and specify URL

 

2.PNG

After application is created,click on it-settings-Required permissions

 

3.png

Click Add-in Step 1 click on Windows Azure Service Management API

 

4.png

In step 2 click on Access Azure Service Management as organization users (preview)

 

5.PNG

 

Assigning a Role for Terraform App

 

Cost management+Billing-Subscription

 

8.png

 

Click on subscription ID-Access control (IAM)-Add

 

9.png

For role specify Contributor-Assign access to Azure AD user,group,or application-Select terraform application-Save

 

10.PNG

 

Get Azure Subscription ID

Cost management+Billing-Subscription-locate and copy Subscription ID to file

 

11.png

 

Get Azure Client ID

Client ID is in fact Application ID

Azure Active Directory-Enterprise applications-locate terraform application and get ID (copy it to file)

 

 

12.png

 

13.png

 

Get Azure Client Secret

Client Secret is Application key,to get it click Azure Active Directory-App registration-click on terraform application (of you don’t see anything, from drop-down menu select All apps and click on Terraform application

 

14.PNG

Give key a name and select duration-click Save

 

16.PNG

Copy key to file

 

17.PNG

Get Azure Tenant ID

Azure Active Directory-Properties-Directory ID

 

18.png

 

  • Subscription ID
  • Client ID
  • Client Secret
  • and Tenant ID is needed for terraform to connect and authenticate in Azure

Auto Scaling helps you maintain application availability and allows to dynamically scale Amazon instances capacity up or down automatically according to defined conditions. Auto Scaling detects impaired Amazon EC2 instances and unhealthy applications, and replace the instances without user intervention.

key.tf

Creating key pair

lifecycle {
ignore_changes = [“public_key”]
}

don’t recreate key pair if public key/path to public key changes

resource "aws_key_pair" "mykeypair" { 
key_name = "mykeypair"
public_key = "${file("${var.PATH_TO_PUBLIC_KEY}")}"
lifecycle { 
ignore_changes = ["public_key"]
} 
}

sg.tf

Define security group which will allow ssh traffic from everywhere

resource "aws_security_group" "allow-ssh" {
vpc_id = "${aws_vpc.main.id}"
name = "allow-ssh"
description = "security group that allows ssh and all egress traffic"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
tags {
Name = "allow-ssh"
}
}

vars.tf

Define variables for Access keys,Private and public keys as well as AWS regions and AMIs

variable "AWS_ACCESS_KEY" {}
variable "AWS_SECRET_KEY" {}
variable "AWS_REGION" {
default = "eu-west-1"
}
variable "PATH_TO_PRIVATE_KEY" {
default = "mykey"
}
variable "PATH_TO_PUBLIC_KEY" {
default = "mykey.pub"
}
variable "AMIS" {
type = "map"
default = {
us-east-1 = "ami-13be557e"
us-west-2 = "ami-06b94666"
eu-west-1 = "ami-844e0bf7"
}
}

terraform.tfvars

specify AWS access keys

AWS_ACCESS_KEY="key"
AWS_SECRET_KEY="key"

provider.tf

point to variable in vars.tf and terraform.tfvars

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

vpc.tf

Creates Virtual Private Cloud (subnets, internet gateway and modifies default route

# Internet VPC
resource "aws_vpc" "main" {
    cidr_block = "10.0.0.0/16"
    instance_tenancy = "default"
    enable_dns_support = "true"
    enable_dns_hostnames = "true"
    enable_classiclink = "false"
    tags {
        Name = "main"
    }
}


# Subnets
resource "aws_subnet" "main-public-1" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.1.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-1a"

    tags {
        Name = "main-public-1"
    }
}
resource "aws_subnet" "main-public-2" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.2.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-1b"

    tags {
        Name = "main-public-2"
    }
}
resource "aws_subnet" "main-public-3" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.3.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-1c"

    tags {
        Name = "main-public-3"
    }
}
resource "aws_subnet" "main-private-1" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.4.0/24"
    map_public_ip_on_launch = "false"
    availability_zone = "eu-west-1a"

    tags {
        Name = "main-private-1"
    }
}
resource "aws_subnet" "main-private-2" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.5.0/24"
    map_public_ip_on_launch = "false"
    availability_zone = "eu-west-1b"

    tags {
        Name = "main-private-2"
    }
}
resource "aws_subnet" "main-private-3" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.6.0/24"
    map_public_ip_on_launch = "false"
    availability_zone = "eu-west-1c"

    tags {
        Name = "main-private-3"
    }
}

# Internet GW
resource "aws_internet_gateway" "main-gw" {
    vpc_id = "${aws_vpc.main.id}"

    tags {
        Name = "main"
    }
}

# route tables
resource "aws_route_table" "main-public" {
    vpc_id = "${aws_vpc.main.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.main-gw.id}"
    }

    tags {
        Name = "main-public-1"
    }
}

# route associations public
resource "aws_route_table_association" "main-public-1-a" {
    subnet_id = "${aws_subnet.main-public-1.id}"
    route_table_id = "${aws_route_table.main-public.id}"
}
resource "aws_route_table_association" "main-public-2-a" {
    subnet_id = "${aws_subnet.main-public-2.id}"
    route_table_id = "${aws_route_table.main-public.id}"
}
resource "aws_route_table_association" "main-public-3-a" {
    subnet_id = "${aws_subnet.main-public-3.id}"
    route_table_id = "${aws_route_table.main-public.id}"
}

 

autoscaling.tf

contains definition for launch configuration and auto scaling group

launch configuration is a template that an Auto Scaling group uses to launch EC2 instances.

An Auto Scaling group contains a collection of EC2 instances that share similar characteristics and are treated as a logical grouping for the purposes of instance scaling and management.

File defines launch configuration first (instance AMI and type) and keypair,

then defines autoscaling group (deployed in 2 subnets), it will start with one instance, if after 300 seconds instance is unhelathy it will spin-up another one (health_check_type = “EC2”)

resource "aws_launch_configuration" "example-launchconfig" {
name_prefix = "example-launchconfig"
image_id = "${lookup(var.AMIS, var.AWS_REGION)}"
instance_type = "t2.micro"
key_name = "${aws_key_pair.mykeypair.key_name}"
security_groups = ["${aws_security_group.allow-ssh.id}"]
}
resource "aws_autoscaling_group" "example-autoscaling" {
name = "example-autoscaling"
vpc_zone_identifier = ["${aws_subnet.main-public-1.id}", "${aws_subnet.main-public-2.id}"]
launch_configuration = "${aws_launch_configuration.example-launchconfig.name}"
min_size = 1
max_size = 2
health_check_grace_period = 300
health_check_type = "EC2"
force_delete = true
tag {
key = "Name"
value = "ec2 instance"
propagate_at_launch = true
}
}

autoscalingpolicy.tf

This file contains autoscaling policy

Here we define how we want to scale in response to changing demand

We specified increasing instance by 1 (scaling_adjustment = “1”), period without scaling (5 minutes-cooldown), policy type,Simple scaling—Increase or decrease the current capacity of the group based on a single scaling adjustment.Then we created cloudwatch alarm wich triggers autoscaling policy which will compare CPU utilization.If average of CPU utilization is higher than 30 % then new instance will be created

# scale up alarm
resource "aws_autoscaling_policy" "example-cpu-policy" {
name = "example-cpu-policy"
autoscaling_group_name = "${aws_autoscaling_group.example-autoscaling.name}"
adjustment_type = "ChangeInCapacity"
scaling_adjustment = "1"
cooldown = "300"
policy_type = "SimpleScaling"
}
resource "aws_cloudwatch_metric_alarm" "example-cpu-alarm" {
alarm_name = "example-cpu-alarm"
alarm_description = "example-cpu-alarm"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "120"
statistic = "Average"
threshold = "30"
dimensions = {
"AutoScalingGroupName" = "${aws_autoscaling_group.example-autoscaling.name}"
}
actions_enabled = true
alarm_actions = ["${aws_autoscaling_policy.example-cpu-policy.arn}"]
}
# scale down alarm
resource "aws_autoscaling_policy" "example-cpu-policy-scaledown" {
name = "example-cpu-policy-scaledown"
autoscaling_group_name = "${aws_autoscaling_group.example-autoscaling.name}"
adjustment_type = "ChangeInCapacity"
scaling_adjustment = "-1"
cooldown = "300"
policy_type = "SimpleScaling"
}
resource "aws_cloudwatch_metric_alarm" "example-cpu-alarm-scaledown" {
alarm_name = "example-cpu-alarm-scaledown"
alarm_description = "example-cpu-alarm-scaledown"
comparison_operator = "LessThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "120"
statistic = "Average"
threshold = "5"
dimensions = {
"AutoScalingGroupName" = "${aws_autoscaling_group.example-autoscaling.name}"
}
actions_enabled = true
alarm_actions = ["${aws_autoscaling_policy.example-cpu-policy-scaledown.arn}"]
}

As usual, test it first:

terraform init && terraform plan

In one of the previous posts we  deployed blank Amazon VM without any software,in this one we’ll launch EC2 instance with some software installed.We’ll update ubuntu VM and install ans start nginx.To accomplish it, we’ll copy script to Amazon VM

script.sh

#!/bin/bash
# sleep until instance is ready
until [[ -f /var/lib/cloud/instance/boot-finished ]]; do
  sleep 1
done
# install nginx
apt-get update
apt-get -y install nginx
# make sure nginx is started
service nginx start

Declaring varibles:

vars.tf:

variable "AWS_ACCESS_KEY" {}
variable "AWS_SECRET_KEY" {}
variable "AWS_REGION" {
default = "eu-west-1"
}

variable "PATH_TO_PRIVATE_KEY" {
default = "mykey"
}
variable "PATH_TO_PUBLIC_KEY" {
default = "mykey.pub"
}
variable "AMIS" {
type = "map"
default = {
us-east-1 = "ami-13be557e"
us-west-2 = "ami-06b94666"
eu-west-1 = "ami-844e0bf7"
}
}

variable "INSTANCE_USERNAME" {
default = "ubuntu"
}

provider.tf (how to connect to AWS)

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

terraform.tfvars

File where AWS access keys are stored

AWS_ACCESS_KEY="keys"
AWS_SECRET_KEY="keys"

  

instance.tf

In this file we’ll define instance, security group and key pair,copy script to it, make connection (using key pair),make it executable and run

resource "aws_instance" "example" {
ami = "${lookup(var.AMIS, var.AWS_REGION)}"
instance_type = "t2.micro"
# the VPC subnet
subnet_id = "${aws_subnet.main-public-1.id}"
# the security group
vpc_security_group_ids = ["${aws_security_group.allow-ssh.id}"]
# the public SSH key
key_name = "${aws_key_pair.mykeypair.key_name}"
provisioner "file" {
source="script.sh"
destination="/tmp/script.sh"
}
provisioner "remote-exec" {
inline=[
"chmod +x /tmp/script.sh",
"sudo /tmp/script.sh"
]
}
connection {
user="${var.INSTANCE_USERNAME}"
private_key="${file("${var.PATH_TO_PRIVATE_KEY}")}"
}

securitygroup.tf

Creating security group (allow ingress traffic on port 22 and 80

resource "aws_security_group" "allow-ssh" {
vpc_id = "${aws_vpc.main.id}"
name = "allow-ssh"
description = "security group that allows ssh and all egress traffic"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
} 
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

ingress {

from_port=80
to_port =80
protocol="tcp"
cidr_blocks=["0.0.0.0/0"]
}
tags {
Name = "allow-ssh_HTTP"
}
}

vpc.tf

Creating Virtual Private Cloud (subnets,internet gateway and route table)

# Internet VPC
resource "aws_vpc" "main" {
    cidr_block = "10.0.0.0/16"
    instance_tenancy = "default"
    enable_dns_support = "true"
    enable_dns_hostnames = "true"
    enable_classiclink = "false"
    tags {
        Name = "main"
    }
}


# Subnets
resource "aws_subnet" "main-public-1" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.1.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-1a"

    tags {
        Name = "main-public-1"
    }
}
resource "aws_subnet" "main-public-2" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.2.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-1b"

    tags {
        Name = "main-public-2"
    }
}
resource "aws_subnet" "main-public-3" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.3.0/24"
    map_public_ip_on_launch = "true"
    availability_zone = "eu-west-1c"

    tags {
        Name = "main-public-3"
    }
}
resource "aws_subnet" "main-private-1" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.4.0/24"
    map_public_ip_on_launch = "false"
    availability_zone = "eu-west-1a"

    tags {
        Name = "main-private-1"
    }
}
resource "aws_subnet" "main-private-2" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.5.0/24"
    map_public_ip_on_launch = "false"
    availability_zone = "eu-west-1b"

    tags {
        Name = "main-private-2"
    }
}
resource "aws_subnet" "main-private-3" {
    vpc_id = "${aws_vpc.main.id}"
    cidr_block = "10.0.6.0/24"
    map_public_ip_on_launch = "false"
    availability_zone = "eu-west-1c"

    tags {
        Name = "main-private-3"
    }
}

# Internet GW
resource "aws_internet_gateway" "main-gw" {
    vpc_id = "${aws_vpc.main.id}"

    tags {
        Name = "main"
    }
}

# route tables
resource "aws_route_table" "main-public" {
    vpc_id = "${aws_vpc.main.id}"
    route {
        cidr_block = "0.0.0.0/0"
        gateway_id = "${aws_internet_gateway.main-gw.id}"
    }

    tags {
        Name = "main-public-1"
    }
}

# route associations public
resource "aws_route_table_association" "main-public-1-a" {
    subnet_id = "${aws_subnet.main-public-1.id}"
    route_table_id = "${aws_route_table.main-public.id}"
}
resource "aws_route_table_association" "main-public-2-a" {
    subnet_id = "${aws_subnet.main-public-2.id}"
    route_table_id = "${aws_route_table.main-public.id}"
}
resource "aws_route_table_association" "main-public-3-a" {
    subnet_id = "${aws_subnet.main-public-3.id}"
    route_table_id = "${aws_route_table.main-public.id}"
}

Create key pair:

ssh-keygen -f mykey

test configuration

terraform init & terrform plan

execute it

echo "yes" | terraform apply

Capture

1

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"
INSTANCE_PASSWORD="Passw0rd012345"

There i also put Windows Server password

File vars.tf 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-cddc5bb4" 
} 
} 
variable "PATH_TO_PRIVATE_KEY" { default = "mykey" } 
variable "PATH_TO_PUBLIC_KEY" { default = "mykey.pub" 
} 
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 vars.tf

1.png

in provider.tf i put reference to terraform.tfvars

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

In windows-instance.tf is code for deploying Windows server:

 

It will create key pair, set AMI, and WinRM, copy local file to new instance and create security group and add EC2 instance to it

 

 

 

resource “aws_key_pair” “mykey” {
key_name = “mykey”
public_key = “${file(“${var.PATH_TO_PUBLIC_KEY}”)}”
}

resource “aws_instance” “win-example” {
ami = “${lookup(var.WIN_AMIS, var.AWS_REGION)}”
instance_type = “t2.micro”
key_name = “${aws_key_pair.mykey.key_name}”
user_data = <<EOF
<powershell>
net user ${var.INSTANCE_USERNAME} ‘${var.INSTANCE_PASSWORD}’ /add /y
net localgroup administrators ${var.INSTANCE_USERNAME} /add

winrm quickconfig -q
winrm set winrm/config/winrs ‘@{MaxMemoryPerShellMB=”300″}’
winrm set winrm/config ‘@{MaxTimeoutms=”1800000″}’
winrm set winrm/config/service ‘@{AllowUnencrypted=”true”}’
winrm set winrm/config/service/auth ‘@{Basic=”true”}’

netsh advfirewall firewall add rule name=”WinRM 5985″ protocol=TCP dir=in localport=5985 action=allow
netsh advfirewall firewall add rule name=”WinRM 5986″ protocol=TCP dir=in localport=5986 action=allow

net stop winrm
sc.exe config winrm start=auto
net start winrm
</powershell>
EOF

provisioner “file” {
source = “test.txt”
destination = “C:/test.txt”
}
connection {
type = “winrm”
timeout = “10m”
user = “${var.INSTANCE_USERNAME}”
password = “${var.INSTANCE_PASSWORD}”
}
vpc_security_group_ids=[“${aws_security_group.allow-all.id}”]

}

output “ip” {

value=”${aws_instance.win-example.public_ip}”

}

 

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

resource "aws_security_group" "allow-all" {
name="allow-all"
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 0
to_port = 6556
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
tags {
Name = "allow-RDP"
}
}

Create key pair:

ssh-keygen -f mykey

Now test for errors and apply configuration :

 terraform init && terraform plan && terraform apply

2.png

Capture.PNG