HumanGov: Model Automated Multi-Tenant Architecture (MAMA) Part 1 of 3: MAMA in the Cloud (AWS EC2, AWS S3 and Amazon DynamoDB) using Terraform and AWS CLI on AWSCloud9

Background

This project is about establishing cloud infrastructure for a Model Automated Multi-Tenant Architecture (MAMA), HumanGov. Each tenant (state = tenant in this case) will have their own EC2 instance, their own S3 bucket, and their own DynamoDB. (For example, Missouri and Kansas will have separate infrastructures.) The states wanted a Reusable, Multi-Tenant Software as a Service (SaaS) Application Infrastructure for dinner, and MAMA will feed it to them. This is a three part project:
HumanGov: Model Automated Multi-Tenant Architecture (MAMA), A Three-Part Series

There will not be lengthy explanations here. This post assumes that you already reviewed the ten (10)-part series on Terraform. If you want more in-depth explanation/background/information about what is going on, you can check out this 10-part series: Terraform: 10-Part Series for Familiarization

1 of 8. Open the AWS Cloud9 environment

““

2 of 8. Setup folders and files for the project

Start from your "environment" folder in AWS Cloud9. The "terraform" folder will be the main project folder. The other folder "modules/aws_humangov_infrastructure" is for modules.

pwd cd human-gov-infrastructure mkdir terraform cd terraform touch variables.tf main.tf outputs.tf mkdir -p modules/aws_humangov_infrastructure cd modules/aws_humangov_infrastructure touch variables.tf main.tf outputs.tf
““

3 of 8. In "modules/aws_humangov_infrastructure", modify "variables.tf", "main.tf" and "outputs.tf"

"variables.tf"

variable "state_name" { description = "The name of the US State" }

"main.tf"

resource "aws_security_group" "state_ec2_sg" { name = "humangov-${var.state_name}-ec2-sg" description = "Allow traffic on ports 22 and 80" ingress { from_port = 22 to_port = 22 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } ingress { from_port = 80 to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] } tags = { Name = "humangov-${var.state_name}" } } resource "aws_instance" "state_ec2" { ami = "ami-007855ac798b5175e" instance_type = "t2.micro" key_name = "humangov-ec2-key" vpc_security_group_ids = [aws_security_group.state_ec2_sg.id] tags = { Name = "humangov-${var.state_name}" } } resource "aws_dynamodb_table" "state_dynamodb" { name = "humangov-${var.state_name}-dynamodb" billing_mode = "PAY_PER_REQUEST" hash_key = "id" attribute { name = "id" type = "S" } tags = { Name = "humangov-${var.state_name}" } } resource "random_string" "bucket_suffix" { length = 7 special = false upper = false } resource "aws_s3_bucket" "state_s3" { bucket = "humangov-${var.state_name}-s3-${random_string.bucket_suffix.result}" tags = { Name = "humangov-${var.state_name}" } } resource "aws_s3_bucket_ownership_controls" "state_s3" { bucket = aws_s3_bucket.state_s3.id rule { object_ownership = "BucketOwnerPreferred" } } resource "aws_s3_bucket_acl" "state_s3" { depends_on = [aws_s3_bucket_ownership_controls.state_s3] bucket = aws_s3_bucket.state_s3.id acl = "private" }

"outputs.tf"

output "state_ec2_public_dns" { value = aws_instance.state_ec2.public_dns } output "state_dynamodb_table" { value = aws_dynamodb_table.state_dynamodb.name } output "state_s3_bucket" { value = aws_s3_bucket.state_s3.bucket }
““
““
““

4 of 8. In the root project directory "terraform", modify "variables.tf", "main.tf" and "outputs.tf".

The most important thing here is navigation. Make sure that you're editing in the correct folder, else the logic will not flow per design.

"variables.tf" is for states. "main.tf" will feed off the modules/aws_humangov_infrastructure. "outputs.tf" will show the status of the created infrastructures.

"variables.tf"

variable "states" { description = "A list of state names" default = ["california","florida","texas"] }

"main.tf"

provider "aws" { region = "us-east-1" } module "aws_humangov_infrastructure" { source = "./modules/aws_humangov_infrastructure" for_each = toset(var.states) state_name = each.value }

"outputs.tf"

output "state_infrastructure_outputs" { value = { for state, infrastructure in module.aws_humangov_infrastructure : state => { ec2_public_dns = infrastructure.state_ec2_public_dns dynamodb_table = infrastructure.state_dynamodb_table s3_bucket = infrastructure.state_s3_bucket } } }
““
““
““

5 of 8. Create SSH key.

The EC2 configuration refers to an SSH key by the name of "humangov-ec2-key". Make sure it exists. You can create the key pair however you want to, but the CLI is convenient for this case.

mkdir ~/environment/human-gov-infrastructure/terraform/keys cd ~/environment/human-gov-infrastructure/terraform/keys aws ec2 create-key-pair --key-name humangov-ec2-key --query 'KeyMaterial' --output text > humangov-ec2-key.pem
““

6 of 8. Initialize and apply

Make sure that you navigate to the main project folder, to avoid unexpected results.

21 resources? Yes, because there are 3 states, and each state gets 7 resources created:
1. DynamoDB
2. EC2
3. S3 bucket
4. S3 bucket ACL
5. S3 bucket ownership controls
6. security group for EC2
7. random string for the S3 bucket suffix

The most interesting part is probably the S3 bucket ACL and S3 bucket ownership controls. The documentation for that is included in the Reference section below.

cd ~/environment/human-gov-infrastructure/terraform pwd terraform fmt terraform init terraform validate terraform plan terraform apply
““
““
““
““

7 of 8. Validate you can see the resources in cloud

You should see instances, S3 buckets, DynamoDB tables.

““
““
““

8 of 8. Cleanup.

Remove the resources

terraform destroy
““

Reference

Input Variables

Output Values

Modules

s3_bucket_acl

create-key-pair

Comments

Popular posts from this blog

Orphaned No More: Adopting AWS Lambda

Containing the Chaos! | A Three-Part Series Demonstrating the Usefulness of Containerization to HumanGov