# Hashicorp Terraform

{% hint style="success" %}
Check out my full terraform course on Cybr!&#x20;

<https://cybr.com/courses/terraform-on-aws-from-zero-to-cloud-infrastructure/>
{% endhint %}

## What is Terraform?

* [Terraform](https://www.terraform.io/) is an open-source, declarative Infrastructure as Code language from HashiCorp.
* [Providers](https://registry.terraform.io/browse/providers) are used to define the resources to build. These abstract the underlying API calls made to build, modify, and destroy resources by wrapping this into HCL syntax. In other words, you just worry about writing Terraform code without having to understand and work with the underlying APIs.&#x20;

## Installation

{% code lineNumbers="true" %}

```bash
# Installing via Homebrew on MacOS
brew tap hashicorp/tap
brew install hashicorp/tap/terraform
brew update
brew upgrade hashicorp/tap/terraformh

# Enabling tab completion
terraform -install-autocomplete

# Restarting shell
. ~/.zshrc    # bash is ~/.bashrc
```

{% endcode %}

## Commands

* Initialize the directory where Terraform files are stored: `terraform init`
* Verify the Terraform syntax is correct: `terraform validate`
* View the resources the code would build if run: `terraform plan`
* Build the resources: `terraform apply`
* Destroy the resources created with Terraform: `terraform destroy`

## Example

* Typically, Terraform code is defined in a `main.tf` file and variables found in that file can be declared in `variables.tf`
* Variables are not required and you could hard code everything into `main.tf` if desired.
* Here's an example of configuring an AWS S3 bucket in Terraform utilizing the [AWS Provider](https://registry.terraform.io/providers/hashicorp/aws/latest/docs).

{% code title="main.tf" lineNumbers="true" %}

```hcl
# Create the bucket
resource "aws_s3_bucket" "s3-bucket-1" {
  bucket = var.mybucketname
}

# Enable server-side encryption
resource "aws_s3_bucket_server_side_encryption_configuration" "s3-encryption-config" {
  bucket = aws_s3_bucket.s3-bucket-1.bucket # defines bucket name

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = var.sse-algorithm # defines encryption type
    }
  }

  depends_on = [
    aws_s3_bucket.s3-bucket-1 # ensures bucket is created before trying to apply encryption
  ]
}

# Configure bucket policy, set to deny HTTP requests
resource "aws_s3_bucket_policy" "s3-bucket-policy" {
  bucket = aws_s3_bucket.s3-bucket-1.id

  # defines bucket policy below, SecureTransport false means it blocks HTTP access
  policy = <<POLICY
  {
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::${var.mybucketname}/*",
            "Condition": {
                "Bool": {
                    "aws:SecureTransport": "false"
                }
            }
        }
    ]
}
POLICY
}

# Block public access to the bucket
resource "aws_s3_bucket_public_access_block" "s3-bucket-access-control" {
  bucket = aws_s3_bucket.s3-bucket-1.id

  block_public_acls       = var.s3-bucket-ac["block_public_acls"]
  block_public_policy     = var.s3-bucket-ac["block_public_policy"]
  ignore_public_acls      = var.s3-bucket-ac["ignore_public_acls"]
  restrict_public_buckets = var.s3-bucket-ac["restrict_public_buckets"]
}
```

{% endcode %}

{% code title="variables.tf" lineNumbers="true" %}

```hcl
variable "mybucketname" {
  description = "Set a unique bucket name"
  type        = string
}

variable "sse-algorithm" {
  description = "Specify the encryption type to use"
  type        = string
  default     = "AES256"
}

variable "s3-bucket-ac" {
  description = "Block public access"
  type        = map(any)
  default = {
    block_public_acls       = "true"
    block_public_policy     = "true"
    ignore_public_acls      = "true"
    restrict_public_buckets = "true"
  }
}
```

{% endcode %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://www.techwithtyler.dev/devsecops/hashicorp-terraform.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
