-
Notifications
You must be signed in to change notification settings - Fork 8
Terraform Guide AWS
Terraform is an IaC tool used to create and change your virtual infrastructure. Custodian team uses Terraform for testing policies. Creation of a Terraform code will require you to follow the procedure and general rules introduced below.
-
Pre-requisites
1.1. Create folders
1.2 Green/Red folder structure -
Rules for Terraform code creation
2.1. Split terraform resources by service into separate files
2.2. Content of "provider.tf" file
2.3. Content of "variables.tf" file
2.4. Content of "terraform.tfvars" file
2.5. A "resource" block name
2.6. Value of the argument "Name"
2.7. Tags
2.8. Instances AMI
2.9. Random password generation - Terraform language style conventions
- AWS provider versioning
- Terraform basic tutorials
Before you start writing a code, you need to create the necessary folders.
Perform the following steps:
1. In the local branch, in the folder "terraform", create a general folder with the name of the policy, e.g., "ecc-aws-000-example_policy"
.
2. In this folder, create three other folders:
- Folder with "green" infrastructure – name:
"green"
- Folder with a JSON file with permissions for a user to run Custodian policy – name: "
iam"
- Folder with "red" infrastructure – name:
“red”
This should look something like this:
ℹ️ Note: In some cases, red or green infrastructure building is not possible.
Green and red infrastructure folders have the same structure:
- Resources that will be created;
- Default variables;
- Terraform vars (terraform.tfvars);
- Provider configuration for connecting with AWS account.
For example:
If you have a script with multiple resources, it is recommended to create separate files for the main of them.
For example, it will be easier for understanding to have separate files containing information about the network (vpc.tf), IAM configuration (iam.tf), etc.
(More information about provider versioning in AWS provider versioning)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4"
}
}
}
provider "aws"{
profile = var.profile
region = var.default-region
default_tags {
tags = {
CustodiaRule = "ecc-aws-103-instance_without_termination_protection"
ComplianceStatus = "Green"
}
}
}
variable "default-region" {
type = string
description = "Default region for resources will be created"
}
variable "profile" {
type = string
description = "Profile name configured before running apply"
}
profile = "c7n"
default-region = "us-east-1"
ℹ️ Note: All regions and locations are used as an example and can be changed depending on your case.
The "resource" block name should be assigned according to the recommendations below:
- If the resource module creates a single resource of a specific service, the resource name should be
this
:
resource "aws_acm_certificate" "this" {
# ... remaining arguments omitted
}
- If you have multiple resources of a specific service, then more descriptive names should be assigned:
private
,public
, ormain
:
resource "aws_subnet" "public" {
# ... remaining arguments omitted
}
- If you have multiple resources but with the same or similar configurations, their functionality should be described in a comment before the resource name. You can also name them
bucket1
,bucket2
:
# resource description
resource "aws_iam_role" "role1" {
# ... remaining arguments omitted
}
Value of the argument "Name" must include:
- Rule ID;
- Resource description;
- Infrastructure identification:
"green"
or"red"
.
For example:
resource "aws_iam_user" "this" {
name = "002_user_green"
path = "/"
force_destroy = true
}
In some cases, a "name" cannot include a symbol "_"
or be started with numbers and should look as follows:
resource "resource" "this" {
bucket = "resource-000-green"
}
resource "resource" "this" {
name = "000resourcegreen"
# ... remaining arguments omitted
}
Tags should contain the rule name and compliance status - "green" or "red":
resource "resource" "this" {
name = "000_resource_green"
# ... remaining arguments omitted
tags = {
CustodiaRule = "ecc-aws-000-example_policy"
Description = "..."
ComplianceStatus = "Green"
}
}
ℹ️ Note: The line containing description is optional
Tags, as well as meta-arguments "depends_on" and "lifecycle", should be separated by a single empty line:
resource "resource" "this" {
name = "000_resource_green"
# ... remaining arguments omitted
tags = {
CustodianRule = "ecc-aws-000-example_policy"
Description = "..."
ComplianceStatus = "Green"
}
depends_on = {
...
}
lifecycle = {
...
}
}
Instances AMI should be specified as follows:
resource "aws_instance" "this" {
ami = data.aws_ami.this.id
# ... remaining arguments omitted
}
data "aws_ami" "this" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["amzn2-ami-hvm\*"]
}
}
All passwords (IDs where possible) should be randomly generated:
resource "random_password" "this" {
length = 12
special = true
number = true
override_special = "!#$%\*()-_=+[]{}:?"
}
resource "aws_db_instance" "this" {
# ... remaining arguments omitted
db_name = "rds105green"
username = "root"
password = random_password.this.result
}
The terraform fmt
command is used to rewrite Terraform configuration files to a canonical format and style. This command applies a subset of Terraform language style conventions, along with other minor adjustments for readability.
The canonical format may change in minor ways between Terraform versions, so after upgrading Terraform, it is recommended to proactively run terraform fmt
on modules.
AWS Provider has MAJOR versions (1, 2, 3, 4) and MINOR (4.1, 4.2.3, etc.). The latest major version of AWS provider should be used in "provider.tf".
If terraform stopped working with the update of the MINOR version for example: MAJOR version - 4 is used at this moment and terraform stopped working after the release of the new minor version, for example, 4.5. In this case, provider version should be changed to the old minor version on which it still works, for example (4.1.0).
In case of a new MAJOR version release, all terraform files must be checked and updated to the new MAJOR version of the provider.