How to spin 2 Node SQL Servers and 1 Node Domain Controller in AWS using Terraform

Using Terraform to Deploy 3 AMI(2 SQL Server & 1 Windows Server 2016)   on AWS



Here I am creating 2 Node SQL Server and 1 Node Domain Controller in AWS using Terraform


Below code will create
 3 Windows Server, in these 3 Node,  2 Node will be SQL Server and 1 Node local Windows Server
  All Windows VMs will have a public IP.

it will also create below components:-

 1 VPC
 1 Subnet
 1 Network ACL
 1 Route table
 1 Internet Gateway
 1 Security Group
 1 Route table association with Subnet
 1 DHCP For Domain Controller


Breaking up my Terraform Script to deploy my infrastructure I wrote 2 files:

Main.tf — This would hold the codes of what I am building, my servers and configuration.
Variables.tf — This holds all the variables used by my Main.tf to use, allowing me to change just a value in one file instead of sifting through my main.tf


In order to execute this code launch Visual Studio code and copy below content in the editor.
save the file as main.tf and at terminal window execute

    1. Terraform  init
    2. Terraform plan
    3. Terraform apply

provider "aws" {
    version = "~> 2.0"
    access_key = "AKIATB3BRJJCP64XTFUG"
    secret_key = "Vs7mLuXXXXnTcbiTmggr+XXXXbfx/OP56WT8x"
    region = "us-east-2"
}

resource "aws_key_pair" "mykeypair" {
  key_name   = "mykeypair"
  public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCSxqu/VK5OMl2NdKexN1+qE1qB1zAr2oMDxofJdEUxdp9LCtTG5VhcESLpj76N2UW+MDO0u9fcURVcgRSh3qW8rF6xWS6BXO9Ek5iQ5l+Jfen3P0ZAZxTUEDW4KUWE0VNjcPx8MIZdYWLH1bwlURBZgqxeb7W3Sl3d4QypQPDu/Ejv+N4+g94f7RadL0FqH0mlf1Z5Lp3FQEQdpp8TUy+b85WXvqRVhMubEGW9ALSdKFCmnAIgVC5rSjq2LG6AZeIWYlwqVx4S0PrlKuQhUYpX9FW6t7Bn8aZhh9fglrpW6XKo2zwmGccP4ixWcMf/jKVkZNtbyw4n++X/dwwCM0K/ imported-openssh-key"
}

/*
assign_generated_ipv6_cidr_block : This property is set to false, which means that Terraform will not automatically assign an IPv6 
CIDR block to the VPC.
cidr_block : This property is set to "${var.vpc_cidr}" which means that the CIDR block of the VPC will be taken from the variable "vpc_cidr".
enable_dns_hostnames : This property is set to false, which means that the VPC will not have the ability to resolve public DNS hostnames to private IP addresses.
enable_dns_support : This property is set to true, which means that the VPC will have the ability to resolve public DNS hostnames
 to public IP addresses.
instance_tenancy : This property is set to "default", which means that instances launched in this VPC will be launched with the 
default tenancy (shared tenancy).
tags : This property is set to {"Name" = "myFirstVPC"} which means that the VPC will be tagged with a "Name" tag with the 
value "myFirstVPC".
*/

resource "aws_vpc" "vpc-0d4f967dea9597b10" {
      assign_generated_ipv6_cidr_block = false
      cidr_block                       = "${var.vpc_cidr}"
      enable_dns_hostnames             = false
      enable_dns_support               = true
      instance_tenancy                 = "default"
      tags                             = {
         "Name" = "myFirstVPC"
    }
   
}
/*
This Terraform code block creates a new subnet in AWS using the "aws_subnet" resource type. It creates a subnet with the name "subnet-0ac0cef9ba555e985" using the following properties:

assign_ipv6_address_on_creation : This property is set to false, which means that Terraform will not automatically assign 
   an IPv6 address to the subnet.
availability_zone : This property is set to "${var.availabilityzone}" which means that the availability zone of the subnet 
   will be taken from the
 variable "availabilityzone". 
 This variable should be defined previously in the Terraform configuration file.
cidr_block : This property is set to "${var.subnet_cidr}" which means that the CIDR block of the subnet will be taken from the
 variable "subnet_cidr". This variable should be defined previously in the Terraform configuration file.
map_public_ip_on_launch : This property is set to false, which means that instances launched in this subnet will not automatically 
be assigned a public IP address.
tags : This property is set to {"Name" = "dbsubnet"} which means that the subnet will be tagged with a "Name" tag with the value "dbsubnet".
vpc_id: This property is set to "${aws_vpc.vpc-0d4f967dea9597b10.id}" which means that the vpc_id of the subnet
   will be taken from the VPC created previously with id "vpc-0d4f967dea9597b10"
timeouts: This block allows you to specify timeouts for certain actions:

*/

resource "aws_subnet" "subnet-0ac0cef9ba555e985" {

    
    assign_ipv6_address_on_creation = false
    availability_zone               = "${var.availabilityzone}"
    cidr_block                      = "${var.subnet_cidr}"
    map_public_ip_on_launch         = false
    tags                            = {
        "Name" = "dbsubnet"
    }
    vpc_id                          = "${aws_vpc.vpc-0d4f967dea9597b10.id}"

    timeouts {}
}

/*
This Terraform code block creates an Internet Gateway resource in AWS using the "aws_internet_gateway" resource type. 
It creates an Internet Gateway with the name "igw-098cd8c812e91b474" using the following properties:

vpc_id : This property is set to "${aws_vpc.vpc-0d4f967dea9597b10.id}", which means that the Internet Gateway will be associated 
with the
 VPC created previously with id "vpc-0d4f967dea9597b10".
tags : This property is set to {"Name" = "Myinternetgw"} which means that the Internet Gateway will be tagged with a "Name" tag
 with the value "Myinternetgw".

An Internet Gateway is a VPC component that allows communication between instances in your VPC and the Internet. 
It therefore allows resources in the VPC to access the Internet, and also allows Internet users to access resources in the VPC
 using public IPs. 
This Internet Gateway will be associated with the specified VPC and will be identified by the "Name" tag "Myinternetgw" 
in the AWS management console.
*/

resource "aws_internet_gateway" "igw-098cd8c812e91b474" {
    vpc_id = "${aws_vpc.vpc-0d4f967dea9597b10.id}"
    tags     = {
        "Name" = "Myinternetgw"
    }
}

resource "aws_route_table" "rtb-0641e8c147988a411" {
    propagating_vgws = []
    route            = [
        {
            /*
In the "route" block of the aws_route_table resource, the cidr_block parameter is used to specify the destination IP address
range for a route. The value "0.0.0.0/0" is a CIDR notation that represents all possible IP addresses.
 It means that this route is a default route and it will match all the traffic that is not matched by other routes in the route table.
CIDR (Classless Inter-Domain Routing) notation is a standard syntax for representing IP address ranges.
 It consists of an IP address followed by a slash ("/") and the number of bits used for the network prefix. 
 In the case of "0.0.0.0/0", the IP address "0.0.0.0" is the network address, and the number "0" after the slash indicates that all bits are used for the network prefix, making it match all IP addresses.
When a VPC resource wants to access the internet, it sends the traffic to the Internet Gateway associated with the VPC.
 The traffic that is sent to the internet gateway is then directed to the Internet Service Provider (ISP) via the default 
 route (0.0.0.0/0) that is present in the Route Table.
 */
            cidr_block                = "0.0.0.0/0"
            egress_only_gateway_id    = ""
            gateway_id                = "${aws_internet_gateway.igw-098cd8c812e91b474.id}"
            instance_id               = ""
            ipv6_cidr_block           = ""
            nat_gateway_id            = ""
            network_interface_id      = ""
            /*
 The transit_gateway_id parameter in the route block of the aws_route_table resource is used to specify the ID of a Transit Gateway to
  which network traffic should be directed.
   A Transit Gateway is a service provided by AWS that enables communication between VPCs and on-premises networks, using a central hub. It allows to establish a connection between VPCs and on-premises data centers over VPN or AWS Direct Connect. By specifying a Transit Gateway ID in the transit_gateway_id parameter, the route table will send traffic to that Transit Gateway, allowing the traffic to be routed between VPCs and on-premises networks via the Transit Gateway.
If the transit_gateway_id is not specified or it is set to an empty string, the traffic will not be directed to any Transit Gateway.
            */
            transit_gateway_id        = ""
            vpc_peering_connection_id = ""
        },
    ]
    tags             = {
        "Name" = "customroutetable"
    }
 
   vpc_id             = "${aws_vpc.vpc-0d4f967dea9597b10.id}"
}

resource "aws_route_table_association" "route_subnet_association" {
  subnet_id      = "${aws_subnet.subnet-0ac0cef9ba555e985.id}"
  route_table_id = "${aws_route_table.rtb-0641e8c147988a411.id}"
}

/*
This Terraform code block creates a DHCP options set resource in AWS using the "aws_vpc_dhcp_options" resource type.
 It creates a DHCP options set with the name "dopt-0ddf5f29b8b640f17" using the following properties:

domain_name: This property is set to "adven.com" which specifies the domain name to be used by instances in the VPC when
 resolving hostnames via the DHCP options set.
domain_name_servers : This property is set to a list of servers "${var.pvtipof3rdinstance}" which specifies the IP addresses of the 
DNS servers that instances in the VPC should use.
tags : This property is set to {"Name" = "rak-dhcp-adven"} which means that the DHCP options set will be tagged with a "Name" tag
 with the value "rak-dhcp-adven".
A DHCP options set is a set of DHCP options that you can associate with a VPC to configure the DHCP settings for the instances in the
 VPC. DHCP options sets are used to configure the Domain Name System (DNS) servers, NTP servers and other DHCP options that are required for the instances to connect to the internet. This DHCP options set will be associated with the specified VPC and will be identified by the "Name" tag "rak-dhcp-adven" in the AWS management console.
It is used to specify the DHCP settings for instances in a VPC, such as domain name, DNS servers and NTP servers.
*/
resource "aws_vpc_dhcp_options" "dopt-0ddf5f29b8b640f17" {
  domain_name         = "adven.com"
    domain_name_servers = [
        "${var.pvtipof3rdinstance}",
    ]
     tags                = {
        "Name" = "rak-dhcp-adven"
    }
}
/*
This Terraform code block creates a Network Access Control List (ACL) resource in AWS using the "aws_network_acl" resource type.
This resource is named "acl-0154d1bf7954ade38" and it is used to control inbound and outbound traffic to a subnet in a Virtual Private Cloud (VPC). 
It is associated with the VPC with the id "${aws_vpc.vpc-0d4f967dea9597b10.id}"
egress: This property is a list of egress (outbound) rules which specify the traffic that is allowed to leave the subnet.
The rule is set to "allow" traffic from any IP address (cidr_block = "0.0.0.0/0") to any port (from_port = 0, to_port = 0) for all protocols (-1) and no ICMP codes or types (icmp_code = 0,
 icmp_type = 0).
ingress: This property is a list of ingress (inbound) rules which specify the traffic that is allowed to enter the subnet.
The rule is set to "allow" traffic from any IP address (cidr_block = "0.0.0.0/0") to any port (from_port = 0, to_port = 0)
 for all protocols (-1) and no ICMP codes or types (icmp_code = 0, icmp_type = 0).
subnet_ids: This property is a list of subnet ids to which this ACL should be associated,
in this case it is associated with "${aws_subnet.subnet-0ac0cef9ba555e985.id}".
tags: This property is used to tag the network ACL with "Name" : "MyVPCNACL"

A Network ACL (NACL) acts as a firewall for controlling traffic in and out of one or more subnets in a VPC.
It provides an additional layer of security for your VPC.
A network ACL contains a list of rules that allow or deny traffic. 
The rules are evaluated in order, and traffic is allowed or denied based on the first rule that matches the traffic.
The rules in this example allow all inbound and outbound traffic, but in a production environment,
 it is typically more secure to have more restrictive rules in place to control traffic.

*/

resource "aws_network_acl" "acl-0154d1bf7954ade38" {
  egress     = [
        {
            action          = "allow"
            cidr_block      = "0.0.0.0/0"
            from_port       = 0
            icmp_code       = 0
            icmp_type       = 0
            ipv6_cidr_block = ""
            protocol        = "-1"
            rule_no         = 100
            to_port         = 0
        },
    ]
/*
n the example you provided, the "protocol" field is being used to specify the protocol for a Network Access Control List (ACL) rule in AWS. The value "-1" refers to "All Traffic" or "All Protocols".

In AWS, a network ACL is a stateful firewall for Amazon VPC that controls inbound and outbound traffic at the subnet level. A network ACL is composed of a list of rules, and each rule specifies a protocol, a range of ports, and an action to take (allow or deny) for traffic that matches the rule.

The "protocol" field in the example you provided is being used to specify the protocol for the rule. The value "-1" means that the rule applies to all traffic, regardless of the protocol used. This is a common default configuration for network ACLs, as it allows all traffic by default.

It's worth noting that this is not the only option for protocol, you can use different protocol values like tcp, udp, icmp etc. Also, there are other fields in the rule like from_port, to_port, cidr_block etc, which can be used to specify the range of ports and IP addresses for the traffic that the rule applies to.
*/
/*
In the example you provided, the "to_port" field is being used to specify the upper range of the port number for a Network Access Control List (ACL) rule in AWS. The value "0" means that the rule applies to all ports, regardless of the port number.

In AWS, a network ACL is a stateful firewall for Amazon VPC that controls inbound and outbound traffic at the subnet level. A network ACL is composed of a list of rules, and each rule specifies a protocol, a range of ports, and an action to take (allow or deny) for traffic that matches the rule.

The "to_port" field in the example you provided is being used to specify the upper range of the port number for the rule. The value "0" means that the rule applies to all ports, regardless of the port number. This is a common default configuration for network ACLs, as it allows all ports by default.

It's worth noting that this is not the only option for the to_port, you can use different values as well, it depends on the requirement of the network access control. Also, there are other fields in the rule like from_port, protocol, cidr_block etc, which can be used to specify the range of ports and IP addresses for the traffic that the rule applies to.

*/

    ingress    = [
        {
            action          = "allow"
            cidr_block      = "0.0.0.0/0"
            from_port       = 0
            icmp_code       = 0
            icmp_type       = 0
            ipv6_cidr_block = ""
            protocol        = "-1"
            rule_no         = 100
            to_port         = 0
        },
    ]
 
    subnet_ids = [
        "${aws_subnet.subnet-0ac0cef9ba555e985.id}",
    ]
    tags       = {
        "Name" = "MyVPCNACL" 
    }
    vpc_id     = "${aws_vpc.vpc-0d4f967dea9597b10.id}"
   
}

resource "aws_security_group" "sg-0cfb36fa1b833cd0f" {
     description = "launch-wizard-1 created 2020-03-04T09:54:52.472+05:30"
    egress      = [
        {
            cidr_blocks      = [
                "0.0.0.0/0",
            ]
            description      = ""
            from_port        = 0
            ipv6_cidr_blocks = []
            prefix_list_ids  = []
            protocol         = "-1"
            security_groups  = []
            self             = false
            to_port          = 0
        },
    ]
 
    ingress     = [
        {
            cidr_blocks      = [
                "0.0.0.0/0",
                "10.0.0.0/16",
            ]
            description      = "SQL port"
            from_port        = 1433
            ipv6_cidr_blocks = []
            prefix_list_ids  = []
            protocol         = "tcp"
            security_groups  = []
            self             = false
            to_port          = 1433
        },
        {
            cidr_blocks      = [
                "${var.vpc_cidr}",
            ]
            description      = ""
            from_port        = 0
            ipv6_cidr_blocks = []
            prefix_list_ids  = []
            protocol         = "-1"
            security_groups  = []
            self             = false
            to_port          = 0
        },
        {
            cidr_blocks      = [
                "10.0.0.0/16",
            ]
            description      = ""
            from_port        = 0
            ipv6_cidr_blocks = []
            prefix_list_ids  = []
            protocol         = "tcp"
            security_groups  = []
            self             = false
            to_port          = 65535
        },
        {
            cidr_blocks      = [
                "${var.myIP}",
            ]
            description      = ""
            from_port        = 3389
            ipv6_cidr_blocks = []
            prefix_list_ids  = []
            protocol         = "tcp"
            security_groups  = []
            self             = false
            to_port          = 3389
        },
    ]
    name        = "MySecurityGroup"
 
    tags        = {
        "Name" = "MySecurityGroup"
    }
      vpc_id                          = "${aws_vpc.vpc-0d4f967dea9597b10.id}"
    revoke_rules_on_delete = false

    timeouts {}
}
/*

resource "aws_instance" "i-03d390c2438f94809" {
    ami                          = "ami-03fca6111d64f18b7"
     associate_public_ip_address  = true
     availability_zone            = "${var.availabilityzone}"
     disable_api_termination     = false
     ebs_optimized                = false
     get_password_data            = false
     hibernation                  = false
     instance_type               = "t2.xlarge"
    # key_name                     = "mykeypair"
     monitoring                   = false
     private_ip                  = "${var.pvtipofistinstance}"
     security_groups              = []
     source_dest_check            = true
     subnet_id                    = "${aws_subnet.subnet-0ac0cef9ba555e985.id}"
     tags                         = {
           "Name" = "SQLSERVER01"
                                   }
     tenancy                      = "default"
      volume_tags                  = {}
        vpc_security_group_ids       = [
           "${aws_security_group.sg-0cfb36fa1b833cd0f.id}"
                                       ]

    credit_specification {
        cpu_credits = "standard"
    }

connection {
    type     = "winrm"
    user     = "Administrator"
    password = "${var.admin_password}"
    #host     = "${var.host}"
  }
    root_block_device {
        delete_on_termination = true
        encrypted             = true
        iops                  = 180
        kms_key_id            = "arn:aws:kms:us-east-2:641852541239:key/ae72101e-bb7e-4bce-b3aa-954b23b8aa40"
        volume_size           = 60
        volume_type           = "gp2"
    }

    timeouts {}

    
  
}

 resource "aws_instance" "i-050673f48902d98ee" {
        ami                          = "ami-03fca6111d64f18b7"
        associate_public_ip_address  = true
        availability_zone            = "${var.availabilityzone}"
        disable_api_termination      = false 
        ebs_optimized                = false
        get_password_data            = false
        hibernation                  = false
        instance_type                = "t2.xlarge"
        ipv6_address_count           = 0
        ipv6_addresses               = []
        key_name                     = "mykeypair"
        monitoring                   = false
        private_ip                   = "${var.pvtipof2ndinstance}"
        security_groups              = []
        source_dest_check            = true
        subnet_id                    = "${aws_subnet.subnet-0ac0cef9ba555e985.id}"
          tags                         = {
              "Name" = "SQLSERVER02" 
           }
        tenancy                      = "default"
        volume_tags                  = {}
        vpc_security_group_ids       = [
             "${aws_security_group.sg-0cfb36fa1b833cd0f.id}"
        ]

        credit_specification {
            cpu_credits = "standard"
        }

        root_block_device {
            delete_on_termination = true
            encrypted             = true
            iops                  = 180
            kms_key_id            = "arn:aws:kms:us-east-2:641852541239:key/ae72101e-bb7e-4bce-b3aa-954b23b8aa40"
            volume_size           = 60
            volume_type           = "gp2"
        }

        timeouts {}
    }

     resource  "aws_instance"  "i-0868ec98876580ead" {
        ami                          = "ami-02ec6f788a1f1a739"
        associate_public_ip_address  = true
        availability_zone            = "${var.availabilityzone}"
        disable_api_termination      = false
        ebs_optimized                = false
        get_password_data            = false
        hibernation                  = false
        instance_type                = "t2.large"
        key_name                     = "mykeypair"
        monitoring                   = false
        private_ip                   = "${var.pvtipof3rdinstance}"
        security_groups              = []
        source_dest_check            = true
        subnet_id                    = "${aws_subnet.subnet-0ac0cef9ba555e985.id}"
        tags                         = {
                      "Name" = "DomainDC"
                                       }
        tenancy                      = "default"
        volume_tags                  = {}
        vpc_security_group_ids       = [
               "${aws_security_group.sg-0cfb36fa1b833cd0f.id}"
                                       ]

        credit_specification {
             cpu_credits = "standard"
                             }

        root_block_device {
          delete_on_termination = true
          encrypted             = true
          iops                  = 100
          kms_key_id            = "arn:aws:kms:us-east-2:641852541239:key/ae72101e-bb7e-4bce-b3aa-954b23b8aa40"
          volume_size           = 30
          volume_type           = "gp2"
                    }

    timeouts {}

     }
     */

Comments

Popular posts from this blog

How to use Custom Script Extensions for windows using Azure PowerShell - AZ CLI and from Terraform

How to create a Resource group in Azure using Terraform Part -1

Error inspecting states in the "azurerm" backend: storage: service returned error: StatusCode=403, ErrorCode=AuthenticationFailed