# Terraform Workshop


---

## What is Terraform

IaC (Infrastructure as Code) framework which enables programatic definition,
deployment and management of infrastructure resources for cloud and on-premises
in a declarative manner. It targets all major cloud platforms (GCP, AWS, Azure, DO etc.)

---

## Why do We Need it

* Standardization of deployment to ensure a consistent state
    * Version control
    * Deploying an additional clone env for testing

* Easier auditability to improve quality and security
    * Modular - reuse & ease of understanding
    * Resource Graph (dependency graph + parallel execution when possible)
    * Version control

* Enables use of hardened deployment pipelines

* Enables immutable infrastructure

---

## Human-Readible Configuration Language

HashiCorp Configuration Language (HCL) or JSON

```
provider "aws" {
  region = "us-west-2"
}

resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"  # Amazon Linux 2 AMI ID
  instance_type = "t2.micro"

  tags = {
    Name = "HelloWorldEC2Instance"
  }
}

output "instance_public_ip" {
  value = aws_instance.example.public_ip
}

```

---

# Workflow

* Write your configuration file

* Use `terraform init` to initialize a Terraform workspace

* Use the the `terraform plan` action to simulate deployment of resources and assess the outcome

* Use `terraform apply` to actually deploy resources

---

# Exercise

* Set up local credentials for your cloud platform of choice

* Write a file that deploys an EC2 instance (main.tf)

* Use `terraform init` to initialize 

* Use `terraform plan` and `terraform apply` in order to deploy the resource

* Remove the resource by using `terraform destroy`

* Take advantage of terraform docs and providers:

  * https://registry.terraform.io/ & https://developer.hashicorp.com/terraform

---

# Solution

```
# Specify the provider
provider "aws" {
  region = "us-west-2"
}

# Create an EC2 instance
resource "aws_instance" "my_ec2" {
  ami           = "ami-03e383d33727f4804"
  instance_type = "t2.micro"


  tags = {
    Name = "TestEC2Instance"
  }
}
```

---

# Extend Configuration

* Add a VPC

* Define security group that limits ingress and egress to port 22

* Add SSH key(s) which may connect to the instance

---

# Solution

```
# Specify the provider
provider "aws" {
  region = "us-west-2"
}

# Create a security group
resource "aws_security_group" "allow_ssh" {
  name        = "allow_ssh"
  description = "Allow SSH access"

  ingress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "default_egress" {
  name        = "default_egress"
  description = "Specify egress for instance"

  egress {
    from_port   = 22
    to_port     = 22
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_key_pair" "my_key" {
  key_name   = "my-key-pair"
  public_key = file("~/.ssh/my-key-pair.pub")  # Path to your public key file
}

# Create an EC2 instance
resource "aws_instance" "my_ec2" {
  ami           = "ami-03e383d33727f4804"
  instance_type = "t2.micro"

  associate_public_ip_address = true
  key_name = aws_key_pair.my_key.key_name

  security_groups = [
    aws_security_group.allow_ssh.name,
    aws_security_grou.default_egress.name
  ]

  tags = {
    Name = "TestEC2Instance"
  }
}
```

---

# Additional Notes

* Typically the terraform state is stored online in a manner that makes it retrievable by others

---

# SOPS for Secrets Management

* Download from https://github.com/getsops/sops

* Encrypt config file: `sops -e --pgp <key_id> credentials > credentials.enc`

* Decrypt and set: `eval $(sops -d credentials.enc | sed 's/: /=/g')`

