Terraform Syntax

Security Groups

declaration

resource "aws_security_group" "mysg" { 
    vpc_id = "${module.vpc_app.vpc_id}"
    name = "My SG"

    tags {
        Name  = "My SG"
    }
}

Ping from
resource "aws_security_group_rule" "pingfrom" {
    description                      = "Ping from"
    type                               = "ingress"
    from_port                       = -1
    to_port                           = -1
    protocol                          = "icmp"
    source_security_group_id = "${aws_security_group.othersg.id}"
    security_group_id            = "${aws_security_group.mysg.id}"
}

All traffic from another sg

resource "aws_security_group_rule" "all_traffic" {
    description                        = "All traffic from License Server"
    type                                 = "ingress"
    from_port                         = 0
    to_port                             = 0
    protocol                            = "all"
    source_security_group_id  = "${aws_security_group.othersg.id}"
    security_group_id             = "${aws_security_group.mysg.id}"
}

all output
resource "aws_security_group_rule" "app_servers_out_all" {
    type                    = "egress"
    from_port            = 0
    to_port                = 0
    protocol               = "all"
    cidr_blocks           = ["0.0.0.0/0"]
    security_group_id = "${aws_security_group.mysg.id}"
}

Data section

declare in one point

data "aws_caller_identity" "current" {}

you can use in the resources like this
 "arn:aws:logs:eu-west-1:${data.aws_caller_identity.current.account_id}:log-group:*:log-stream:*"

Policy with Data

data "aws_iam_policy_document" "mycloudwatch" {
  statement {
    actions   = [
      "cloudwatch:PutMetricAlarm",
      "cloudwatch:PutDashboard",
      "cloudwatch:DeleteDashboards",
      "cloudwatch:DeleteAlarms"
    ]
    resources = ["*"]
  }
}

resource "aws_iam_policy" "mycloudwatch" {
    name        = "mycloudwatch"
    path        = "/"
    description = "CloudWatch Write Dashboard And Alarms"
    policy = "${data.aws_iam_policy_document.mycloudwatch.json}"
}

resource "aws_iam_role_policy_attachment" "mycloudwatch" {
    role       = "${var.role}"
    policy_arn = "${aws_iam_policy.mycloudwatch.arn}"
}

Module

count and if

in the variables.tf

variable "dns_zone_id" { default = "dont_create"}

in the main.tf
resource "aws_route53_record" "ec2record" {
    count = "${var.dns_zone_id == "dont_create" ? 0 : 1}"

Generic

elastic ip and depends on

you can also use a profile inside the ~/.aws/credentials file in linux and refer it

file project.tf (it can be any name because all the .tf files are evaluated)

provider "aws" {
  shared_credentials_file  = "${var.cred-file}"
  profile                  = "${var.profile}"
  region                   = "${var.region}"
}

resource "aws_instance" "example" {
  ami           = "ami-7172b611"
  instance_type = "t2.micro"
}

resource "aws_eip" "ip" {
    instance = "${aws_instance.example.id}"
    depends_on = ["aws_instance.example"]
}

file variables.tf

variable "region" {
  default = "sa-east-1"
}
variable "profile" {
  default = "default"
  description = "AWS credentials profile you want to use"
}
variable "cred-file" {
  default = "/home/vagrant/.aws/credentials"
  description = "the credentials files in your machine you can't use the ~ char"
}

many machines with the same code

#create the ec2 machine
resource "aws_instance" "genericinstances" {
  count = "${var.number}"
  ami = "ami-xxxxxx"
  instance_type = "t2.micro"
  associate_public_ip_address = "false"
  subnet_id = "subnet-xxxxxx"
  private_ip = "172.31.48.${count.index+4}"
  vpc_security_group_ids = ["sg-xxxxxx"]
  key_name = "mypemkey"
  tags {
        Name = "MachineNumber-${count.index}"
  }
}
# associate an elastic ip
resource "aws_eip" "ips" {
  count = "${var.number}"
  instance = "${element(aws_instance.genericinstances.*.id, count.index)}"
}
# define a dns record in it
resource "aws_route53_record" "records" {
   count = "${var.number}"
   zone_id = "xxxxxxxxxxx"
   name = "Mymachinename-${count.index}.mydomain.net"
   type = "A"
   ttl = "10"
   records = ["${element(aws_instance.genericinstances.*.private_ip , count.index)}"]
}

advanced userdata , this can be used inside an ec2 machine or a Launch configuration, the indentation is VERY IMPORTANT

  user_data = <<HEREDOC
     #!/bin/bash
     FILENAME=/home/ec2-user/logstash-config/logstash.conf
     for (( c=1; c<=8; c++ )) do sed -i '$ d' $FILENAME ; done
     echo '   hosts => ["${var.cloudelasticcom}:9243"] ' >> $FILENAME
     echo '   ssl => true ' >> $FILENAME
     echo '   user => "myusername" ' >> $FILENAME
     echo '   password => "mypassword" ' >> $FILENAME
     echo ' } ' >> $FILENAME
     echo '} ' >> $FILENAME
     docker restart logstash
HEREDOC

if you indent correctly you will have this color inside Atom
userdata-terraform.jpg
if you choose a wrong indentation you will have these colors
wrong-terraform-userdata.jpg

windows template with power shell to change the search name

resource "aws_instance" "winmgt" {
  ami           = "${var.win10AmiID}"
  instance_type = "t2.large"
  associate_public_ip_address = "false"
  subnet_id = "${var.Subnet-Destination-id}"
  vpc_security_group_ids = ["${aws_security_group.lab1.id}"]
  key_name = "${var.key_name}"
  tags {
        Name = "${var.EnvIdentifier}-win10"
        OperativeSystem = "Windows 10"
  }
  user_data = " <powershell> Invoke-WmiMethod -class win32_networkadapterconfiguration -name setdnssuffixsearchorder -argumentlist @('${var.region}.compute.internal', '${var.region}.ec2-utilities.amazonaws.com', '${var.EnvIdentifier}'), $null </powershell>"
}

Workaround the sns problem

as it is described in this page https://www.terraform.io/docs/providers/aws/r/sns_topic_subscription.html

Unsupported protocols include the following:

email -- delivery of message via SMTP
email-json -- delivery of JSON-encoded message via SMTP
These are unsupported because the endpoint needs to be authorized and does not generate an ARN until the target email address has been validated. This breaks the Terraform model and as a result are not currently supported.

so to workaround this problem you can do like this
resource "aws_sns_topic" "alarm" {
  name = "alarming"
  provisioner "local-exec" {
    command = "aws sns subscribe --topic-arn ${self.arn} --protocol email --notification-endpoint myemail@mydomain.mine"
  }
}

Tags

 tags = "${merge(map(
      "Name",              "DBServer",
      "BackupAMI",         "Yes",
      "CloudWatchAlarms",  "Yes",
      "OS",                "Windows",
      "VPC",               "mybuilding",
     ),
       "${var.scheduling}",
       "${var.backup}"
     )}"

in variables.tf
variable "scheduling" {
  type = "map"
  default = {
    Scheduling        = "Managed"
#    Schedule-Mon      = "UTC 0400-2359"
    Schedule-Weekday  = "UTC 0700-2000"
    Schedule-Sat      = "UTC 0700-1600"
  }
}

variable "backup" {
  type = "map"
  default = {
    BT-Backup             = "True"
    Backup-Daily          = "True"
    Backup-Incremental    = "4 hours"
    Retention-Daily       = "21 days"
    Retention-Incremental = "2 days"
  }
}

in terraform.tfvars
scheduling = {
  Scheduling        = "Manual"
}
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License