From da658894955e419279fff456b568868a76662e20 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Wed, 1 Nov 2023 12:27:18 -0500 Subject: [PATCH 01/32] removed data block --- iam_role.tf | 3 --- 1 file changed, 3 deletions(-) diff --git a/iam_role.tf b/iam_role.tf index 420a47e..6ba1d55 100644 --- a/iam_role.tf +++ b/iam_role.tf @@ -1,6 +1,3 @@ -locals { - account_id = aws_vpc.this.owner_id -} #Create a policy to read from the specific parameter store #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy resource "aws_iam_policy" "ssm_parameter_policy" { From 39e0d64fdf229df554c179c2c8b9251b2f54bc4b Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Wed, 1 Nov 2023 12:41:03 -0500 Subject: [PATCH 02/32] create ec2 role for instance profile --- ec2_role.tf | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 ec2_role.tf diff --git a/ec2_role.tf b/ec2_role.tf new file mode 100644 index 0000000..86db034 --- /dev/null +++ b/ec2_role.tf @@ -0,0 +1,41 @@ +# #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role +resource "aws_iam_role" "ec2_role" { + name = "app-4-ec2-role" + + # Terraform's "jsonencode" function converts a + # Terraform expression result to valid JSON syntax. + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Sid = "" + Principal = { + Service = "ec2.amazonaws.com" + } + }, + ] + }) +} +#Attach role to policy +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment +resource "aws_iam_role_policy_attachment" "custom" { + role = aws_iam_role.ec2_role.name + policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" +} + +resource "aws_iam_role_policy_attachment" "ssm_policy_attachement" { + role = aws_iam_role.ec2_role.name + policy_arn = aws_iam_policy.ssm_parameter_policy.arn +} +resource "aws_iam_role_policy_attachment" "secret_policy_attachement" { + role = aws_iam_role.ec2_role.name + policy_arn = aws_iam_policy.secret_manager_policy.arn +} +#Attach role to an instance profile +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile +resource "aws_iam_instance_profile" "ec2_profile" { + name = "app-4-ec2-profile" + role = aws_iam_role.ec2_role.name +} \ No newline at end of file From 1f592dc680c3cd758b234b934e75beef1346e9ab Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Wed, 1 Nov 2023 12:41:52 -0500 Subject: [PATCH 03/32] added variables for ec2 instance --- variable.tf | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/variable.tf b/variable.tf index 6d8bd0b..b402141 100644 --- a/variable.tf +++ b/variable.tf @@ -36,4 +36,14 @@ variable "elasticache_auth" { description = "The auth token to the Amazon ElastiCache cluster. This value is passed to Terraform from the pipeline." type = string sensitive = true +} +variable "ami_name" { + description = "The ami name of the image from where the instances will be created" + default = ["amzn2-ami-amd-hvm-2.0.20230727.0-x86_64-gp2"] + type = list(string) +} +variable "instance_type" { + description = "The instance type of the EC2 instances" + default = "t3.medium" + type = string } \ No newline at end of file From c0fd8990c8641382e6f920b56d55b7e5b3df5816 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Thu, 2 Nov 2023 22:22:27 -0500 Subject: [PATCH 04/32] user data script to write to the elasticache cluster --- user_data/write_elasticache.tpl | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 user_data/write_elasticache.tpl diff --git a/user_data/write_elasticache.tpl b/user_data/write_elasticache.tpl new file mode 100644 index 0000000..f27016d --- /dev/null +++ b/user_data/write_elasticache.tpl @@ -0,0 +1,64 @@ +#!/bin/bash +yum update -y +yum install python-pip -y +yum install python3 -y +pip3 install redis-py-cluster +pip3 install boto3 +pip3 install botocore +echo "The region value is ${Region}" +AWS_REGION=${Region} +local_elasticache_ep=${elasticache_ep} +local_auth_token=${elasticache_auth_token} +local_elasticache_ep_port=${elasticache_ep_port} +cat <> /var/write_cache.py +from rediscluster import RedisCluster +import logging +import boto3 +import sys + +def main(): + CityName = input("Enter a City Name: ") + session = boto3.Session(region_name='$AWS_REGION') + auth_token = get_secret(session) + elasticache_endpoint = get_elasticache_endpoint(session) + elasticache_port = get_elasticache_port(session) + write_into_redis_cluster( + elasticache_endpoint, + elasticache_port, + auth_token, + CityName) + +def get_secret(session): + secret_client = session.client('secretsmanager') + try: + get_secret_value_response = secret_client.get_secret_value( + SecretId='$local_auth_token' + ) + except ClientError as e: + raise e + return get_secret_value_response + +def get_elasticache_endpoint(session): + ssm_client = session.client('ssm') + return ssm_client.get_parameter( + Name='$local_elasticache_ep', WithDecryption=True) + +def get_elasticache_port(session): + ssm_client = session.client('ssm') + return ssm_client.get_parameter( + Name='$local_elasticache_ep_port', WithDecryption=True) + +def write_into_redis_cluster(endpoint, port, auth, cityname): + logging.basicConfig(level=logging.INFO) + redis = RedisCluster(startup_nodes=[{ + "host": endpoint['Parameter']['Value'], + "port": port['Parameter']['Value']}], + decode_responses=True,skip_full_coverage_check=True,ssl=True, + password=auth['SecretString']) + if redis.ping(): + logging.info("Connected to Redis") + redis.set('City', cityname) + print("The city name entered is updated in the Redis cache cluster.") + redis.close() +main() +EOF \ No newline at end of file From ac9ebc14975a36892e08de861e00bad49df3f4c0 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Thu, 2 Nov 2023 22:22:46 -0500 Subject: [PATCH 05/32] user data to read from the elasticache cluster --- user_data/read_elasticache.tpl | 58 ++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 user_data/read_elasticache.tpl diff --git a/user_data/read_elasticache.tpl b/user_data/read_elasticache.tpl new file mode 100644 index 0000000..482bb6a --- /dev/null +++ b/user_data/read_elasticache.tpl @@ -0,0 +1,58 @@ +#!/bin/bash +yum update -y +yum install python-pip -y +yum install python3 -y +pip3 install redis-py-cluster +pip3 install boto3 +pip3 install botocore +echo "The region value is ${Region}" +AWS_REGION=${Region} +local_elasticache_ep=${elasticache_ep} +local_auth_token=${elasticache_auth_token} +local_elasticache_ep_port=${elasticache_ep_port} +cat <> /var/read_cache.py +from rediscluster import RedisCluster +from botocore.exceptions import ClientError +import logging +import boto3 + +def main(): + session = boto3.Session(region_name='$AWS_REGION') + auth_token = get_secret(session) + elasticache_endpoint = get_elasticache_endpoint(session) + elasticache_port = get_elasticache_port(session) + read_from_redis_cluster(elasticache_endpoint, elasticache_port, auth_token) + +def get_secret(session): + secret_client = session.client('secretsmanager') + try: + get_secret_value_response = secret_client.get_secret_value( + SecretId='$local_auth_token' + ) + except ClientError as e: + raise e + return get_secret_value_response + +def get_elasticache_endpoint(session): + ssm_client = session.client('ssm') + return ssm_client.get_parameter( + Name='$local_elasticache_ep', WithDecryption=True) + +def get_elasticache_port(session): + ssm_client = session.client('ssm') + return ssm_client.get_parameter( + Name='$local_elasticache_ep_port', WithDecryption=True) + +def read_from_redis_cluster(endpoint, port, auth): + logging.basicConfig(level=logging.INFO) + redis = RedisCluster(startup_nodes=[{ + "host": endpoint['Parameter']['Value'], + "port": port['Parameter']['Value']}], + decode_responses=True,skip_full_coverage_check=True,ssl=True, + password=auth['SecretString']) + if redis.ping(): + logging.info("Connected to Redis") + print("The city name entered is "+redis.get("City")) + redis.close() +main() +EOF \ No newline at end of file From 3ad4c9c533d0b7dec4a031051e450c4e4162a4c4 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sun, 5 Nov 2023 12:06:23 -0600 Subject: [PATCH 06/32] updated provider info --- random.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/random.tf b/random.tf index 1dab5e4..b8ccff4 100644 --- a/random.tf +++ b/random.tf @@ -1,4 +1,5 @@ #https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/auth.html#auth-overview +#https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/password resource "random_password" "auth" { length = 90 special = true From 13a4b22d175fc25a0de64386344390bdca0a39ad Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Mon, 11 Dec 2023 21:08:45 -0600 Subject: [PATCH 07/32] add ec2 instance --- ec2.tf | 81 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 ec2.tf diff --git a/ec2.tf b/ec2.tf new file mode 100644 index 0000000..4459502 --- /dev/null +++ b/ec2.tf @@ -0,0 +1,81 @@ +resource "aws_internet_gateway" "this-igw" { + vpc_id = aws_vpc.this.id + tags = { + "Name" = "app-4-gateway" + } +} +resource "aws_route" "internet-route" { + destination_cidr_block = "0.0.0.0/0" + route_table_id = aws_route_table.public.id + gateway_id = aws_internet_gateway.this-igw.id +} +# create a security group +resource "aws_security_group" "ec2_instance" { + name = "app-4-ec2" + description = "Allow inbound to and outbound access from the Amazon EC2 instance." + ingress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.vpc_cidr] + description = "Enable access from any resource inside the VPC." + } + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + description = "Enable access to the internet." + } + vpc_id = aws_vpc.this.id +} + +#create an EC2 in a public subnet +data "aws_ami" "amazon_ami" { + filter { + name = "name" + values = var.ami_name + } + filter { + name = "virtualization-type" + values = ["hvm"] + } + most_recent = true + owners = ["amazon"] +} +resource "aws_instance" "app-server-read" { + instance_type = var.instance_type + ami = data.aws_ami.amazon_ami.id + vpc_security_group_ids = [aws_security_group.ec2_instance.id] + iam_instance_profile = aws_iam_instance_profile.ec2_profile.name + associate_public_ip_address = true + subnet_id = aws_subnet.public[0].id + tags = { + Name = "app-4-server-read" + } + user_data = templatefile("user_data/read_elasticache.tpl", + { + Region = var.region, + elasticache_ep = aws_ssm_parameter.elasticache_ep.name, + elasticache_ep_port = aws_ssm_parameter.elasticache_port.name, + elasticache_auth_token = aws_secretsmanager_secret.elasticache_auth.name + }) +} +resource "aws_instance" "app-server-write" { + instance_type = var.instance_type + ami = data.aws_ami.amazon_ami.id + vpc_security_group_ids = [aws_security_group.ec2_instance.id] + iam_instance_profile = aws_iam_instance_profile.ec2_profile.name + associate_public_ip_address = true + subnet_id = aws_subnet.public[0].id + tags = { + Name = "app-4-server-write" + } + user_data = templatefile("user_data/write_elasticache.tpl", + { + Region = var.region, + elasticache_ep = aws_ssm_parameter.elasticache_ep.name, + elasticache_ep_port = aws_ssm_parameter.elasticache_port.name, + elasticache_auth_token = aws_secretsmanager_secret.elasticache_auth.name + }) +} \ No newline at end of file From c85f86112916741b0ee7fc1fc8652703b8ad6823 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Tue, 12 Dec 2023 15:50:17 -0600 Subject: [PATCH 08/32] fixed checkov errors --- ec2.tf | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/ec2.tf b/ec2.tf index 4459502..c4226d2 100644 --- a/ec2.tf +++ b/ec2.tf @@ -50,6 +50,11 @@ resource "aws_instance" "app-server-read" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true subnet_id = aws_subnet.public[0].id + ebs_optimized = true + monitoring = true + root_block_device { + encrypted = true + } tags = { Name = "app-4-server-read" } @@ -68,6 +73,11 @@ resource "aws_instance" "app-server-write" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true subnet_id = aws_subnet.public[0].id + ebs_optimized = true + monitoring = true + root_block_device { + encrypted = true + } tags = { Name = "app-4-server-write" } From 935465b02f34c63898366f1ef13b3181bab5de95 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Tue, 12 Dec 2023 21:22:41 -0600 Subject: [PATCH 09/32] checkov scan fix --- ec2.tf | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/ec2.tf b/ec2.tf index c4226d2..a395eef 100644 --- a/ec2.tf +++ b/ec2.tf @@ -50,19 +50,23 @@ resource "aws_instance" "app-server-read" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true subnet_id = aws_subnet.public[0].id - ebs_optimized = true - monitoring = true + ebs_optimized = true + monitoring = true root_block_device { encrypted = true } + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + } tags = { Name = "app-4-server-read" } user_data = templatefile("user_data/read_elasticache.tpl", { - Region = var.region, - elasticache_ep = aws_ssm_parameter.elasticache_ep.name, - elasticache_ep_port = aws_ssm_parameter.elasticache_port.name, + Region = var.region, + elasticache_ep = aws_ssm_parameter.elasticache_ep.name, + elasticache_ep_port = aws_ssm_parameter.elasticache_port.name, elasticache_auth_token = aws_secretsmanager_secret.elasticache_auth.name }) } @@ -73,19 +77,23 @@ resource "aws_instance" "app-server-write" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true subnet_id = aws_subnet.public[0].id - ebs_optimized = true - monitoring = true - root_block_device { + ebs_optimized = true + monitoring = true + root_block_device { encrypted = true } + metadata_options { + http_endpoint = "enabled" + http_tokens = "required" + } tags = { Name = "app-4-server-write" } user_data = templatefile("user_data/write_elasticache.tpl", { - Region = var.region, - elasticache_ep = aws_ssm_parameter.elasticache_ep.name, - elasticache_ep_port = aws_ssm_parameter.elasticache_port.name, + Region = var.region, + elasticache_ep = aws_ssm_parameter.elasticache_ep.name, + elasticache_ep_port = aws_ssm_parameter.elasticache_port.name, elasticache_auth_token = aws_secretsmanager_secret.elasticache_auth.name }) } \ No newline at end of file From 0ff737b96db8732cbcd357b83b59db752472f0a0 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Tue, 12 Dec 2023 21:28:44 -0600 Subject: [PATCH 10/32] checkov scan fix --- ec2.tf | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/ec2.tf b/ec2.tf index a395eef..ca2625e 100644 --- a/ec2.tf +++ b/ec2.tf @@ -49,9 +49,10 @@ resource "aws_instance" "app-server-read" { vpc_security_group_ids = [aws_security_group.ec2_instance.id] iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true - subnet_id = aws_subnet.public[0].id - ebs_optimized = true - monitoring = true + #checkov:skip=CKV_AWS_88: Required for Session Manager access + subnet_id = aws_subnet.public[0].id + ebs_optimized = true + monitoring = true root_block_device { encrypted = true } @@ -76,9 +77,10 @@ resource "aws_instance" "app-server-write" { vpc_security_group_ids = [aws_security_group.ec2_instance.id] iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true - subnet_id = aws_subnet.public[0].id - ebs_optimized = true - monitoring = true + #checkov:skip=CKV_AWS_88: Required for Session Manager access + subnet_id = aws_subnet.public[0].id + ebs_optimized = true + monitoring = true root_block_device { encrypted = true } From 2e6c5a5f9784b05ebda466775fba3a1cd855a865 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Wed, 13 Dec 2023 07:33:32 -0600 Subject: [PATCH 11/32] updated with correct feature image and link to note --- README.md | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 71840b9..05e8985 100644 --- a/README.md +++ b/README.md @@ -3,18 +3,28 @@ [![terraform-infra-provisioning](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml)[![checkov-static-analysis-scan](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml) -![Image](https://skdevops.files.wordpress.com/2023/10/85-image-0-1.png) +![Image](https://skdevops.files.wordpress.com/2023/12/87-image-0-1.png) # Motivation -Amazon ElastiCache service supports Redis and Memcached. If you want in an in-memory caching solution for your application, check out the [AWS-Docs](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html). In this repository I have the Terraform code to provision an Amazon ElastiCache for Redis cluster and all the supporting infrastructure components like Amazon VPC, subnets, security group, AWS KMS key, and AWS Secrets Manager secret. -
The process of provisioning is automated using GitHub Actions. I also followed a few best practices while creating the Amazon ElastiCache service, like enabling multi-availability zone, multi-node, and encryption in transit and at rest. +Amazon ElastiCache service supports Redis and Memcached. If you want in an in-memory caching solution for your application, check out the [AWS-Docs](https://docs.aws.amazon.com/AmazonElastiCache/latest/red-ug/WhatIs.html). In this repository I cover **two use cases.** -
I discussed the concept in detail in my notes at [-create-an-amazon-elasticache-for-redis-cluster-using-terraform](https://skundunotes.com/2023/10/21/create-an-amazon-elasticache-for-redis-cluster-using-terraform/). +
**Use-Case 1:** Create an Amazon ElastiCache for Redis cluster using Terraform, and +
**Use-Case 2:** Create an Amazon ElastiCache for Redis cluster and Amazon EC2 instances to access the cluster using Terraform. -
I used Bridgecrew Checkov to scan the Terraform code for security vulnerabilities. Here is a link if you are interested in adding code scanning capabilities to your GitHub Actions pipeline [-automate-terraform-configuration-scan-with-checkov-and-github-actions](https://skundunotes.com/2023/04/12/automate-terraform-configuration-scan-with-checkov-and-github-actions/). -
I also used Infracost to generate a cost estimate of building the architecture. If you want to learn more about adding Infracost estimates to your repository, head over to this note [-estimate AWS Cloud resource cost with Infracost, Terraform, and GitHub Actions](https://skundunotes.com/2023/07/17/estimate-aws-cloud-resource-cost-with-infracost-terraform-and-github-actions/). -
Lastly, I also automated the process of provisioning the resources using GitHub Actions pipeline and I discussed that in detail at [-CI-CD with Terraform and GitHub Actions to deploy to AWS](https://skundunotes.com/2023/03/07/ci-cd-with-terraform-and-github-actions-to-deploy-to-aws/). +
If you are interested in Use-case 1, please refer to the [create-amazon-elasticache branch.](https://github.com/kunduso/amazon-elasticache-redis-tf/tree/create-amazon-elasticache) + +For Use-case 2, this repository has the Terraform code to provision an Amazon ElastiCache for Redis cluster and all the supporting infrastructure components like Amazon VPC, subnets, security group, AWS KMS key, and AWS Secrets Manager secret. It also has addition AWS cloud resources like: +
- an **internet gateway** and update the path in the route table attached to the **public subnet** +
- an **IAM instance profile** and attach an **IAM role** with the two existing **IAM policies** to read from the **SSM parameter store** and **AWS Secrets manager**. These resources have the ElastiCache endpoint and auth_token stored that was created in Use-case 1. +
- two **Amazon EC2 instances** in the public subnet with separate user data scripts to install **Python libraries** and create Python files inside the instances. +
The process of provisioning is automated using **GitHub Actions**. + +
I discussed the concept in detail in my notes at [-Connect to an Amazon ElastiCache cluster from an Amazon EC2 instance using Python](https://skundunotes.com/2023/12/13/connect-to-an-amazon-elasticache-cluster-from-an-amazon-ec2-instance-using-python/). + +
I used **Bridgecrew Checkov** to scan the Terraform code for security vulnerabilities. Here is a link if you are interested in adding code scanning capabilities to your GitHub Actions pipeline [-automate-terraform-configuration-scan-with-checkov-and-github-actions](https://skundunotes.com/2023/04/12/automate-terraform-configuration-scan-with-checkov-and-github-actions/). +
I also used **Infracost** to generate a cost estimate of building the architecture. If you want to learn more about adding Infracost estimates to your repository, head over to this note [-estimate AWS Cloud resource cost with Infracost, Terraform, and GitHub Actions](https://skundunotes.com/2023/07/17/estimate-aws-cloud-resource-cost-with-infracost-terraform-and-github-actions/). +
Lastly, I also automated the process of provisioning the resources using **GitHub Actions** pipeline and I discussed that in detail at [-CI-CD with Terraform and GitHub Actions to deploy to AWS](https://skundunotes.com/2023/03/07/ci-cd-with-terraform-and-github-actions-to-deploy-to-aws/). ## Prerequisites -For this code to function without errors, I created an OpenID connect identity provider in Amazon Identity and Access Management that has a trust relationship with this GitHub repository. You can read about it [here](https://skundunotes.com/2023/02/28/securely-integrate-aws-credentials-with-github-actions-using-openid-connect/) to get a detailed explanation with steps. +For this code to function without errors, I created an **OpenID connect** identity provider in **Amazon Identity and Access Management** that has a trust relationship with this GitHub repository. You can read about it [here](https://skundunotes.com/2023/02/28/securely-integrate-aws-credentials-with-github-actions-using-openid-connect/) to get a detailed explanation with steps.
I stored the ARN of the IAM Role as a GitHub secret which is referred in the [`terraform.yml`](https://github.com/kunduso/amazon-elasticache-redis-tf/blob/eb148db2b9ff37cff9f1fb469d0c14b6479bd57a/.github/workflows/terraform.yml#L42) file.
Since I used Infracost in this repository, I stored the `INFRACOST_API_KEY` as a repository secret. It is referenced in the [`terraform.yml`](https://github.com/kunduso/amazon-elasticache-redis-tf/blob/eb148db2b9ff37cff9f1fb469d0c14b6479bd57a/.github/workflows/terraform.yml#L52) GitHub actions workflow file.
As part of the Infracost integration, I also created a `INFRACOST_API_KEY` and stored that as a GitHub Actions secret. I also managed the cost estimate process using a GitHub Actions variable `INFRACOST_SCAN_TYPE` where the value is either `hcl_code` or `tf_plan`, depending on the type of scan desired. From 05a926c073ba1fbaeab26098b8944d7cbff301c1 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:42:33 -0600 Subject: [PATCH 12/32] added variable for name --- variable.tf | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/variable.tf b/variable.tf index 00ed7e3..4a9d923 100644 --- a/variable.tf +++ b/variable.tf @@ -18,6 +18,11 @@ variable "secret_key" { sensitive = true default = "" } +variable "name" { + description = "The name of the application." + type = string + default = "app-4" +} variable "vpc_cidr" { description = "CIDR for the VPC." default = "10.20.32.0/25" @@ -41,8 +46,8 @@ variable "instance_type" { description = "The instance type of the EC2 instances" default = "t3.medium" } -variable "replication_group_id" { - description = "The name of the ElastiCache replication group." - default = "app-4-redis-cluster" - type = string -} \ No newline at end of file +# variable "replication_group_id" { +# description = "The name of the ElastiCache replication group." +# default = "app-4-redis-cluster" +# type = string +# } \ No newline at end of file From e2e47b1494a36795a83d5de66ad35f869d6305cd Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:43:01 -0600 Subject: [PATCH 13/32] converted to variable --- ssm_parameter.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ssm_parameter.tf b/ssm_parameter.tf index 9061c5c..81ef073 100644 --- a/ssm_parameter.tf +++ b/ssm_parameter.tf @@ -1,12 +1,12 @@ #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter resource "aws_ssm_parameter" "elasticache_ep" { - name = "/elasticache/app-4/${aws_elasticache_replication_group.app4.replication_group_id}/endpoint" + name = "/elasticache/${var.name}/${aws_elasticache_replication_group.app4.replication_group_id}/endpoint" type = "SecureString" key_id = aws_kms_key.encryption_rest.id value = aws_elasticache_replication_group.app4.configuration_endpoint_address } resource "aws_ssm_parameter" "elasticache_port" { - name = "/elasticache/app-4/${aws_elasticache_replication_group.app4.replication_group_id}/port" + name = "/elasticache/${var.name}/${aws_elasticache_replication_group.app4.replication_group_id}/port" type = "SecureString" key_id = aws_kms_key.encryption_rest.id value = aws_elasticache_replication_group.app4.port From edf01d6d6d5889bd5ecd917bf295427c88ae930a Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:48:49 -0600 Subject: [PATCH 14/32] updated reference --- cloudwatch.tf | 6 ++++-- data.tf | 4 ++-- ec2_role.tf | 4 ++-- elasticache.tf | 8 ++++---- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/cloudwatch.tf b/cloudwatch.tf index 1aec471..3807120 100644 --- a/cloudwatch.tf +++ b/cloudwatch.tf @@ -1,10 +1,12 @@ +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group resource "aws_cloudwatch_log_group" "slow_log" { - name = "/elasticache/${var.replication_group_id}/slow-log" + name = "/elasticache/${var.name}/slow-log" retention_in_days = 365 kms_key_id = aws_kms_key.encryption_rest.arn } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group resource "aws_cloudwatch_log_group" "engine_log" { - name = "/elasticache/${var.replication_group_id}/engine-log" + name = "/elasticache/${var.name}/engine-log" retention_in_days = 365 kms_key_id = aws_kms_key.encryption_rest.arn } \ No newline at end of file diff --git a/data.tf b/data.tf index 57db3ca..1949689 100644 --- a/data.tf +++ b/data.tf @@ -2,6 +2,6 @@ data "aws_caller_identity" "current" {} locals { principal_root_arn = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" principal_logs_arn = "logs.${var.region}.amazonaws.com" - slow_log_arn = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/elasticache/${var.replication_group_id}/slow-log" - engine_log_arn = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/elasticache/${var.replication_group_id}/engine-log" + slow_log_arn = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/elasticache/${var.name}/slow-log" + engine_log_arn = "arn:aws:logs:${var.region}:${data.aws_caller_identity.current.account_id}:log-group:/elasticache/${var.name}/engine-log" } \ No newline at end of file diff --git a/ec2_role.tf b/ec2_role.tf index 86db034..88ccfa0 100644 --- a/ec2_role.tf +++ b/ec2_role.tf @@ -1,6 +1,6 @@ # #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role resource "aws_iam_role" "ec2_role" { - name = "app-4-ec2-role" + name = "${var.name}-ec2-role" # Terraform's "jsonencode" function converts a # Terraform expression result to valid JSON syntax. @@ -36,6 +36,6 @@ resource "aws_iam_role_policy_attachment" "secret_policy_attachement" { #Attach role to an instance profile #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile resource "aws_iam_instance_profile" "ec2_profile" { - name = "app-4-ec2-profile" + name = "${var.name}-ec2-profile" role = aws_iam_role.ec2_role.name } \ No newline at end of file diff --git a/elasticache.tf b/elasticache.tf index f3b2af5..dad1ce0 100644 --- a/elasticache.tf +++ b/elasticache.tf @@ -1,10 +1,10 @@ resource "aws_elasticache_subnet_group" "elasticache_subnet" { - name = "app-4-cache-subnet" + name = "${var.name}-cache-subnet" subnet_ids = [for subnet in aws_subnet.private : subnet.id] } resource "aws_secretsmanager_secret" "elasticache_auth" { - name = "app-4-elasticache-auth" + name = "${var.name}-elasticache-auth" recovery_window_in_days = 0 kms_key_id = aws_kms_key.encryption_secret.id #checkov:skip=CKV2_AWS_57: Disabled Secrets Manager secrets automatic rotation @@ -18,8 +18,8 @@ resource "aws_secretsmanager_secret_version" "auth" { resource "aws_elasticache_replication_group" "app4" { automatic_failover_enabled = true subnet_group_name = aws_elasticache_subnet_group.elasticache_subnet.name - replication_group_id = var.replication_group_id - description = "ElastiCache cluster for app4" + replication_group_id = var.name + description = "ElastiCache cluster for ${var.name}" node_type = "cache.t2.small" parameter_group_name = "default.redis7.cluster.on" port = 6379 From f0d04855f736efd362747f55c992571fef4cdec0 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:49:15 -0600 Subject: [PATCH 15/32] separated rules from sg --- ec2.tf | 50 +++++++++++++++++++++-------------------------- security_group.tf | 39 ++++++++++++++++++++---------------- 2 files changed, 44 insertions(+), 45 deletions(-) diff --git a/ec2.tf b/ec2.tf index ca2625e..a79fe33 100644 --- a/ec2.tf +++ b/ec2.tf @@ -1,34 +1,28 @@ -resource "aws_internet_gateway" "this-igw" { - vpc_id = aws_vpc.this.id - tags = { - "Name" = "app-4-gateway" - } -} -resource "aws_route" "internet-route" { - destination_cidr_block = "0.0.0.0/0" - route_table_id = aws_route_table.public.id - gateway_id = aws_internet_gateway.this-igw.id -} # create a security group resource "aws_security_group" "ec2_instance" { - name = "app-4-ec2" + name = "${var.name}-ec2" description = "Allow inbound to and outbound access from the Amazon EC2 instance." - ingress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = [var.vpc_cidr] - description = "Enable access from any resource inside the VPC." - } - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - description = "Enable access to the internet." - } vpc_id = aws_vpc.this.id } +resource "aws_security_group_rule" "ec2_instance_ingress" { + type = "ingress" + security_group_id = aws_security_group.ec2_instance.id + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.vpc_cidr] + description = "Enable access from any resource inside the VPC." +} + +resource "aws_security_group_rule" "ec2_instance_egress" { + type = "egress" + security_group_id = aws_security_group.ec2_instance.id + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + description = "Enable access to the internet." +} #create an EC2 in a public subnet data "aws_ami" "amazon_ami" { @@ -61,7 +55,7 @@ resource "aws_instance" "app-server-read" { http_tokens = "required" } tags = { - Name = "app-4-server-read" + Name = "${var.name}-server-read" } user_data = templatefile("user_data/read_elasticache.tpl", { @@ -89,7 +83,7 @@ resource "aws_instance" "app-server-write" { http_tokens = "required" } tags = { - Name = "app-4-server-write" + Name = "${var.name}-server-write" } user_data = templatefile("user_data/write_elasticache.tpl", { diff --git a/security_group.tf b/security_group.tf index 375202a..258b03e 100644 --- a/security_group.tf +++ b/security_group.tf @@ -2,21 +2,26 @@ resource "aws_default_security_group" "default" { vpc_id = aws_vpc.this.id } resource "aws_security_group" "elasticache" { - name = "app-4-elasticache-sg" + name = "${var.name}-elasticache-sg" description = "Allow inbound to and outbound access from the Amazon ElastiCache cluster." - ingress { - from_port = 6379 - to_port = 6379 - protocol = "tcp" - cidr_blocks = [var.vpc_cidr] - description = "Enable communication to the Amazon ElastiCache for Redis cluster. " - } - egress { - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - description = "Enable access to the ElastiCache cluster." - } - vpc_id = aws_vpc.this.id -} \ No newline at end of file + vpc_id = aws_vpc.this.id +} +resource "aws_security_group_rule" "elasticache_ingress" { + type = "ingress" + security_group_id = aws_security_group.elasticache.id + from_port = 6379 + to_port = 6379 + protocol = "tcp" + cidr_blocks = [var.vpc_cidr] + description = "Enable communication to the Amazon ElastiCache for Redis cluster." +} + +resource "aws_security_group_rule" "elasticache_egress" { + type = "egress" + security_group_id = aws_security_group.elasticache.id + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + description = "Enable access to the ElastiCache cluster." +} From e7e912163dfc509d36127d554c787f50b54289ee Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:49:26 -0600 Subject: [PATCH 16/32] updated reference --- iam_role.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/iam_role.tf b/iam_role.tf index 5f438f6..0f498c5 100644 --- a/iam_role.tf +++ b/iam_role.tf @@ -1,7 +1,7 @@ #Create a policy to read from the specific parameter store #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy resource "aws_iam_policy" "ssm_parameter_policy" { - name = "app-4-ssm-parameter-read-policy" + name = "${var.name}-ssm-parameter-read-policy" path = "/" description = "Policy to read the ElastiCache endpoint and port number stored in the SSM Parameter Store." # Terraform's "jsonencode" function converts a @@ -29,7 +29,7 @@ resource "aws_iam_policy" "ssm_parameter_policy" { } #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy resource "aws_iam_policy" "secret_manager_policy" { - name = "app-4-secret-read-policy" + name = "${var.name}-secret-read-policy" path = "/" description = "Policy to read the ElastiCache AUTH Token stored in AWS Secrets Manager secret." # Terraform's "jsonencode" function converts a From 897d9234cebf38d33f2ad765e7b7842b73d39cee Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:54:17 -0600 Subject: [PATCH 17/32] added policy to kms key --- kms.tf | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 4 deletions(-) diff --git a/kms.tf b/kms.tf index d8e1599..4177323 100644 --- a/kms.tf +++ b/kms.tf @@ -3,10 +3,63 @@ resource "aws_kms_key" "encryption_secret" { enable_key_rotation = true description = "Key to encrypt secret" deletion_window_in_days = 7 - #checkov:skip=CKV2_AWS_64: Not including a KMS Key policy + + # Attach the KMS key policy + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowSecretsManagerUse" + Effect = "Allow" + Action = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*" + ] + Resource = "*" + Principal = { + Service = "secretsmanager.amazonaws.com" + } + }, + { + Sid = "AllowAdminAccessToKMSKey" + Effect = "Allow" + Action = "kms:*" + Resource = "*" + Principal = { + AWS = "*" + } + }, + { + Sid = "AllowIAMRolesToUseKey" + Effect = "Allow" + Action = [ + "kms:Encrypt", + "kms:Decrypt", + "kms:ReEncrypt*", + "kms:GenerateDataKey*" + ] + Resource = "*" + Principal = { + AWS = "*" + } + Condition = { + StringEquals = { + "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" + } + } + } + ] + }) + + tags = { + Name = "${var.name}-encryption-secret" + } } + resource "aws_kms_alias" "encryption_secret" { - name = "alias/elasticache-app-4-in-transit" + name = "alias/${var.name}-elasticache-in-transit" target_key_id = aws_kms_key.encryption_secret.key_id } resource "aws_kms_key" "encryption_rest" { @@ -14,15 +67,18 @@ resource "aws_kms_key" "encryption_rest" { description = "Key to encrypt cache at rest." deletion_window_in_days = 7 #checkov:skip=CKV2_AWS_64: KMS Key policy in a separate resource + tags = { + Name = "${var.name}-encryption-rest" + } } resource "aws_kms_alias" "encryption_rest" { - name = "alias/elasticache-app-4-at-rest" + name = "alias/${var.name}-elasticache-at-rest" target_key_id = aws_kms_key.encryption_rest.key_id } resource "aws_kms_key_policy" "encryption_rest_policy" { key_id = aws_kms_key.encryption_rest.id policy = jsonencode({ - Id = "encryption-rest" + Id = "${var.name}-encryption-rest" Statement = [ { Action = "kms:*" From 05e6038ed5d029c4584c0458ca9336bd25461b98 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:54:53 -0600 Subject: [PATCH 18/32] format --- ec2.tf | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/ec2.tf b/ec2.tf index a79fe33..c4fac3d 100644 --- a/ec2.tf +++ b/ec2.tf @@ -2,26 +2,26 @@ resource "aws_security_group" "ec2_instance" { name = "${var.name}-ec2" description = "Allow inbound to and outbound access from the Amazon EC2 instance." - vpc_id = aws_vpc.this.id + vpc_id = aws_vpc.this.id } resource "aws_security_group_rule" "ec2_instance_ingress" { - type = "ingress" - security_group_id = aws_security_group.ec2_instance.id - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = [var.vpc_cidr] - description = "Enable access from any resource inside the VPC." + type = "ingress" + security_group_id = aws_security_group.ec2_instance.id + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = [var.vpc_cidr] + description = "Enable access from any resource inside the VPC." } resource "aws_security_group_rule" "ec2_instance_egress" { - type = "egress" - security_group_id = aws_security_group.ec2_instance.id - from_port = 0 - to_port = 0 - protocol = "-1" - cidr_blocks = ["0.0.0.0/0"] - description = "Enable access to the internet." + type = "egress" + security_group_id = aws_security_group.ec2_instance.id + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + description = "Enable access to the internet." } #create an EC2 in a public subnet From 043a3067705239349d39c7c824bd1b7e654b4493 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Fri, 15 Nov 2024 22:55:07 -0600 Subject: [PATCH 19/32] update reference to module --- network.tf | 122 +++++++++++++++++++++++++++++------------------------ 1 file changed, 67 insertions(+), 55 deletions(-) diff --git a/network.tf b/network.tf index 4d6f623..37bf92f 100644 --- a/network.tf +++ b/network.tf @@ -1,56 +1,68 @@ -# https://docs.aws.amazon.com/glue/latest/dg/set-up-vpc-dns.html -resource "aws_vpc" "this" { - cidr_block = var.vpc_cidr - # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#enable_dns_support - enable_dns_support = true - # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#enable_dns_hostnames - enable_dns_hostnames = true - #checkov:skip=CKV2_AWS_11: Not creating a flow log for this VPC - tags = { - "Name" = "app-4" - } -} -data "aws_availability_zones" "available" { - state = "available" -} -resource "aws_subnet" "private" { - count = length(var.subnet_cidr_private) - vpc_id = aws_vpc.this.id - cidr_block = var.subnet_cidr_private[count.index] - availability_zone = data.aws_availability_zones.available.names[(count.index) % length(data.aws_availability_zones.available.names)] - tags = { - "Name" = "app-4-private-${count.index + 1}" - } -} -resource "aws_subnet" "public" { - count = length(var.subnet_cidr_public) - vpc_id = aws_vpc.this.id - cidr_block = var.subnet_cidr_public[count.index] - availability_zone = data.aws_availability_zones.available.names[(count.index) % length(data.aws_availability_zones.available.names)] - tags = { - "Name" = "app-4-public-${count.index + 1}" - } -} -resource "aws_route_table" "private" { - count = length(var.subnet_cidr_private) - vpc_id = aws_vpc.this.id - tags = { - "Name" = "app-4-private-route-table-${count.index + 1}" - } -} -resource "aws_route_table" "public" { - vpc_id = aws_vpc.this.id - tags = { - "Name" = "app-4-public" - } -} -resource "aws_route_table_association" "private" { - count = length(var.subnet_cidr_private) - subnet_id = element(aws_subnet.private.*.id, count.index) - route_table_id = aws_route_table.private[count.index].id -} -resource "aws_route_table_association" "public" { - count = length(var.subnet_cidr_public) - subnet_id = element(aws_subnet.public.*.id, count.index) - route_table_id = aws_route_table.public.id +# # https://docs.aws.amazon.com/glue/latest/dg/set-up-vpc-dns.html +# resource "aws_vpc" "this" { +# cidr_block = var.vpc_cidr +# # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#enable_dns_support +# enable_dns_support = true +# # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#enable_dns_hostnames +# enable_dns_hostnames = true +# #checkov:skip=CKV2_AWS_11: Not creating a flow log for this VPC +# tags = { +# "Name" = "app-4" +# } +# } +# data "aws_availability_zones" "available" { +# state = "available" +# } +# resource "aws_subnet" "private" { +# count = length(var.subnet_cidr_private) +# vpc_id = aws_vpc.this.id +# cidr_block = var.subnet_cidr_private[count.index] +# availability_zone = data.aws_availability_zones.available.names[(count.index) % length(data.aws_availability_zones.available.names)] +# tags = { +# "Name" = "app-4-private-${count.index + 1}" +# } +# } +# resource "aws_subnet" "public" { +# count = length(var.subnet_cidr_public) +# vpc_id = aws_vpc.this.id +# cidr_block = var.subnet_cidr_public[count.index] +# availability_zone = data.aws_availability_zones.available.names[(count.index) % length(data.aws_availability_zones.available.names)] +# tags = { +# "Name" = "app-4-public-${count.index + 1}" +# } +# } +# resource "aws_route_table" "private" { +# count = length(var.subnet_cidr_private) +# vpc_id = aws_vpc.this.id +# tags = { +# "Name" = "app-4-private-route-table-${count.index + 1}" +# } +# } +# resource "aws_route_table" "public" { +# vpc_id = aws_vpc.this.id +# tags = { +# "Name" = "app-4-public" +# } +# } +# resource "aws_route_table_association" "private" { +# count = length(var.subnet_cidr_private) +# subnet_id = element(aws_subnet.private.*.id, count.index) +# route_table_id = aws_route_table.private[count.index].id +# } +# resource "aws_route_table_association" "public" { +# count = length(var.subnet_cidr_public) +# subnet_id = element(aws_subnet.public.*.id, count.index) +# route_table_id = aws_route_table.public.id +# } + +module "vpc" { + source = "github.com/kunduso/terraform-aws-vpc?ref=v1.0.0" + vpc_cidr = var.vpc_cidr + enable_dns_support = "true" + enable_dns_hostnames = "true" + vpc_name = "app-4" + subnet_cidr_private = var.subnet_cidr_private + subnet_cidr_public = var.subnet_cidr_public + enable_internet_gateway = "true" + enable_flow_log = "true" } \ No newline at end of file From cec79d9c4355fc5382171064ec02e366f093ad74 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sat, 16 Nov 2024 08:51:14 -0600 Subject: [PATCH 20/32] upgrade provider version --- provider.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provider.tf b/provider.tf index bee5e8d..98a3b46 100644 --- a/provider.tf +++ b/provider.tf @@ -6,7 +6,7 @@ terraform { } random = { source = "hashicorp/random" - version = "3.5.1" + version = "3.6.3" } } } From ffe35c6cbcbe863770125f0fd2fcaba42bb5e534 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sat, 16 Nov 2024 21:04:06 -0600 Subject: [PATCH 21/32] updated terraform documentation links --- ec2_role.tf | 4 ++-- security_group.tf | 11 +++++------ ssm_parameter.tf | 1 + 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ec2_role.tf b/ec2_role.tf index 88ccfa0..f03017f 100644 --- a/ec2_role.tf +++ b/ec2_role.tf @@ -1,7 +1,6 @@ # #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role resource "aws_iam_role" "ec2_role" { name = "${var.name}-ec2-role" - # Terraform's "jsonencode" function converts a # Terraform expression result to valid JSON syntax. assume_role_policy = jsonencode({ @@ -24,11 +23,12 @@ resource "aws_iam_role_policy_attachment" "custom" { role = aws_iam_role.ec2_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } - +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment resource "aws_iam_role_policy_attachment" "ssm_policy_attachement" { role = aws_iam_role.ec2_role.name policy_arn = aws_iam_policy.ssm_parameter_policy.arn } +##https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment resource "aws_iam_role_policy_attachment" "secret_policy_attachement" { role = aws_iam_role.ec2_role.name policy_arn = aws_iam_policy.secret_manager_policy.arn diff --git a/security_group.tf b/security_group.tf index 258b03e..31d2142 100644 --- a/security_group.tf +++ b/security_group.tf @@ -1,11 +1,10 @@ -resource "aws_default_security_group" "default" { - vpc_id = aws_vpc.this.id -} +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group resource "aws_security_group" "elasticache" { name = "${var.name}-elasticache-sg" description = "Allow inbound to and outbound access from the Amazon ElastiCache cluster." - vpc_id = aws_vpc.this.id + vpc_id = module.vpc.vpc.id } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule resource "aws_security_group_rule" "elasticache_ingress" { type = "ingress" security_group_id = aws_security_group.elasticache.id @@ -15,7 +14,7 @@ resource "aws_security_group_rule" "elasticache_ingress" { cidr_blocks = [var.vpc_cidr] description = "Enable communication to the Amazon ElastiCache for Redis cluster." } - +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule resource "aws_security_group_rule" "elasticache_egress" { type = "egress" security_group_id = aws_security_group.elasticache.id @@ -24,4 +23,4 @@ resource "aws_security_group_rule" "elasticache_egress" { protocol = "-1" cidr_blocks = ["0.0.0.0/0"] description = "Enable access to the ElastiCache cluster." -} +} \ No newline at end of file diff --git a/ssm_parameter.tf b/ssm_parameter.tf index 81ef073..d42af08 100644 --- a/ssm_parameter.tf +++ b/ssm_parameter.tf @@ -5,6 +5,7 @@ resource "aws_ssm_parameter" "elasticache_ep" { key_id = aws_kms_key.encryption_rest.id value = aws_elasticache_replication_group.app4.configuration_endpoint_address } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter resource "aws_ssm_parameter" "elasticache_port" { name = "/elasticache/${var.name}/${aws_elasticache_replication_group.app4.replication_group_id}/port" type = "SecureString" From e52acddae99de3934320eda9edb46fdb1984c77d Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sat, 16 Nov 2024 21:05:31 -0600 Subject: [PATCH 22/32] converted to use vpc module to address #41 --- ec2.tf | 15 ++++++++----- elasticache.tf | 12 ++++++----- network.tf | 58 +------------------------------------------------- 3 files changed, 18 insertions(+), 67 deletions(-) diff --git a/ec2.tf b/ec2.tf index c4fac3d..380feda 100644 --- a/ec2.tf +++ b/ec2.tf @@ -1,9 +1,11 @@ # create a security group +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group resource "aws_security_group" "ec2_instance" { name = "${var.name}-ec2" description = "Allow inbound to and outbound access from the Amazon EC2 instance." - vpc_id = aws_vpc.this.id + vpc_id = module.vpc.vpc.id } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule resource "aws_security_group_rule" "ec2_instance_ingress" { type = "ingress" security_group_id = aws_security_group.ec2_instance.id @@ -13,7 +15,7 @@ resource "aws_security_group_rule" "ec2_instance_ingress" { cidr_blocks = [var.vpc_cidr] description = "Enable access from any resource inside the VPC." } - +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule resource "aws_security_group_rule" "ec2_instance_egress" { type = "egress" security_group_id = aws_security_group.ec2_instance.id @@ -24,7 +26,7 @@ resource "aws_security_group_rule" "ec2_instance_egress" { description = "Enable access to the internet." } -#create an EC2 in a public subnet +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami data "aws_ami" "amazon_ami" { filter { name = "name" @@ -37,6 +39,8 @@ data "aws_ami" "amazon_ami" { most_recent = true owners = ["amazon"] } +#create an EC2 in a public subnet +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance resource "aws_instance" "app-server-read" { instance_type = var.instance_type ami = data.aws_ami.amazon_ami.id @@ -44,7 +48,7 @@ resource "aws_instance" "app-server-read" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true #checkov:skip=CKV_AWS_88: Required for Session Manager access - subnet_id = aws_subnet.public[0].id + subnet_id = module.vpc.private_subnets[0].id ebs_optimized = true monitoring = true root_block_device { @@ -65,6 +69,7 @@ resource "aws_instance" "app-server-read" { elasticache_auth_token = aws_secretsmanager_secret.elasticache_auth.name }) } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/instance resource "aws_instance" "app-server-write" { instance_type = var.instance_type ami = data.aws_ami.amazon_ami.id @@ -72,7 +77,7 @@ resource "aws_instance" "app-server-write" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true #checkov:skip=CKV_AWS_88: Required for Session Manager access - subnet_id = aws_subnet.public[0].id + subnet_id = module.vpc.private_subnets[0].id ebs_optimized = true monitoring = true root_block_device { diff --git a/elasticache.tf b/elasticache.tf index dad1ce0..d0cceba 100644 --- a/elasticache.tf +++ b/elasticache.tf @@ -1,14 +1,16 @@ +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/elasticache_subnet_group resource "aws_elasticache_subnet_group" "elasticache_subnet" { name = "${var.name}-cache-subnet" - subnet_ids = [for subnet in aws_subnet.private : subnet.id] + subnet_ids = [for subnet in module.vpc.private_subnets : subnet.id] } - +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret resource "aws_secretsmanager_secret" "elasticache_auth" { name = "${var.name}-elasticache-auth" recovery_window_in_days = 0 kms_key_id = aws_kms_key.encryption_secret.id #checkov:skip=CKV2_AWS_57: Disabled Secrets Manager secrets automatic rotation } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/secretsmanager_secret_version resource "aws_secretsmanager_secret_version" "auth" { secret_id = aws_secretsmanager_secret.elasticache_auth.id secret_string = random_password.auth.result @@ -43,8 +45,8 @@ resource "aws_elasticache_replication_group" "app4" { log_format = "json" log_type = "engine-log" } - lifecycle { - ignore_changes = [kms_key_id] - } + # lifecycle { + # ignore_changes = [kms_key_id] + # } apply_immediately = true } \ No newline at end of file diff --git a/network.tf b/network.tf index 37bf92f..bc244a2 100644 --- a/network.tf +++ b/network.tf @@ -1,62 +1,6 @@ -# # https://docs.aws.amazon.com/glue/latest/dg/set-up-vpc-dns.html -# resource "aws_vpc" "this" { -# cidr_block = var.vpc_cidr -# # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#enable_dns_support -# enable_dns_support = true -# # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc#enable_dns_hostnames -# enable_dns_hostnames = true -# #checkov:skip=CKV2_AWS_11: Not creating a flow log for this VPC -# tags = { -# "Name" = "app-4" -# } -# } -# data "aws_availability_zones" "available" { -# state = "available" -# } -# resource "aws_subnet" "private" { -# count = length(var.subnet_cidr_private) -# vpc_id = aws_vpc.this.id -# cidr_block = var.subnet_cidr_private[count.index] -# availability_zone = data.aws_availability_zones.available.names[(count.index) % length(data.aws_availability_zones.available.names)] -# tags = { -# "Name" = "app-4-private-${count.index + 1}" -# } -# } -# resource "aws_subnet" "public" { -# count = length(var.subnet_cidr_public) -# vpc_id = aws_vpc.this.id -# cidr_block = var.subnet_cidr_public[count.index] -# availability_zone = data.aws_availability_zones.available.names[(count.index) % length(data.aws_availability_zones.available.names)] -# tags = { -# "Name" = "app-4-public-${count.index + 1}" -# } -# } -# resource "aws_route_table" "private" { -# count = length(var.subnet_cidr_private) -# vpc_id = aws_vpc.this.id -# tags = { -# "Name" = "app-4-private-route-table-${count.index + 1}" -# } -# } -# resource "aws_route_table" "public" { -# vpc_id = aws_vpc.this.id -# tags = { -# "Name" = "app-4-public" -# } -# } -# resource "aws_route_table_association" "private" { -# count = length(var.subnet_cidr_private) -# subnet_id = element(aws_subnet.private.*.id, count.index) -# route_table_id = aws_route_table.private[count.index].id -# } -# resource "aws_route_table_association" "public" { -# count = length(var.subnet_cidr_public) -# subnet_id = element(aws_subnet.public.*.id, count.index) -# route_table_id = aws_route_table.public.id -# } - module "vpc" { source = "github.com/kunduso/terraform-aws-vpc?ref=v1.0.0" + region = var.region vpc_cidr = var.vpc_cidr enable_dns_support = "true" enable_dns_hostnames = "true" From 35127bb82c0a631ba2033b9257429109ef8be917 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sat, 16 Nov 2024 21:06:21 -0600 Subject: [PATCH 23/32] tighened up kms key policy --- kms.tf | 109 ++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 73 insertions(+), 36 deletions(-) diff --git a/kms.tf b/kms.tf index 4177323..e5bd8a7 100644 --- a/kms.tf +++ b/kms.tf @@ -1,38 +1,52 @@ - +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key resource "aws_kms_key" "encryption_secret" { enable_key_rotation = true description = "Key to encrypt secret" deletion_window_in_days = 7 - - # Attach the KMS key policy + tags = { + Name = "${var.name}-encryption-secret" + } +} +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias +resource "aws_kms_alias" "encryption_secret" { + name = "alias/${var.name}-elasticache-in-transit" + target_key_id = aws_kms_key.encryption_secret.key_id +} +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key_policy +resource "aws_kms_key_policy" "encryption_secret_policy" { + key_id = aws_kms_key.encryption_secret.id policy = jsonencode({ - Version = "2012-10-17" + Id = "${var.name}-encryption-secret" Statement = [ { - Sid = "AllowSecretsManagerUse" - Effect = "Allow" Action = [ - "kms:Encrypt", - "kms:Decrypt", - "kms:ReEncrypt*", - "kms:GenerateDataKey*" + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" ] - Resource = "*" + Effect = "Allow" Principal = { - Service = "secretsmanager.amazonaws.com" + AWS = "${local.principal_root_arn}" } - }, - { - Sid = "AllowAdminAccessToKMSKey" - Effect = "Allow" - Action = "kms:*" Resource = "*" - Principal = { - AWS = "*" + Sid = "Enable IAM User Permissions" + Condition = { + StringEquals = { + "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" + } } }, { - Sid = "AllowIAMRolesToUseKey" + Sid = "AllowSecretsManagerUse" Effect = "Allow" Action = [ "kms:Encrypt", @@ -42,26 +56,13 @@ resource "aws_kms_key" "encryption_secret" { ] Resource = "*" Principal = { - AWS = "*" - } - Condition = { - StringEquals = { - "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" - } + Service = "secretsmanager.amazonaws.com" } } ] }) - - tags = { - Name = "${var.name}-encryption-secret" - } -} - -resource "aws_kms_alias" "encryption_secret" { - name = "alias/${var.name}-elasticache-in-transit" - target_key_id = aws_kms_key.encryption_secret.key_id } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key resource "aws_kms_key" "encryption_rest" { enable_key_rotation = true description = "Key to encrypt cache at rest." @@ -71,23 +72,59 @@ resource "aws_kms_key" "encryption_rest" { Name = "${var.name}-encryption-rest" } } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias resource "aws_kms_alias" "encryption_rest" { name = "alias/${var.name}-elasticache-at-rest" target_key_id = aws_kms_key.encryption_rest.key_id } +#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key_policy resource "aws_kms_key_policy" "encryption_rest_policy" { key_id = aws_kms_key.encryption_rest.id policy = jsonencode({ Id = "${var.name}-encryption-rest" Statement = [ { - Action = "kms:*" + Action = [ + "kms:Create*", + "kms:Describe*", + "kms:Enable*", + "kms:List*", + "kms:Put*", + "kms:Update*", + "kms:Revoke*", + "kms:Disable*", + "kms:Get*", + "kms:Delete*", + "kms:ScheduleKeyDeletion", + "kms:CancelKeyDeletion" + ] Effect = "Allow" Principal = { AWS = "${local.principal_root_arn}" } Resource = "*" Sid = "Enable IAM User Permissions" + Condition = { + StringEquals = { + "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" + } + } + }, + { + Sid = "Allow ElastiCache to use the key" + Effect = "Allow" + Principal = { + Service = "elasticache.amazonaws.com" + } + Action = [ + "kms:Decrypt", + "kms:Encrypt", + "kms:GenerateDataKey", + "kms:ReEncrypt*", + "kms:CreateGrant", + "kms:DescribeKey" + ] + Resource = "*" }, { Effect : "Allow", From 5484fa779eab6525134b15ce0d5d5491982844f1 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sat, 16 Nov 2024 21:15:51 -0600 Subject: [PATCH 24/32] checkov scan fixes --- kms.tf | 1 - network.tf | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/kms.tf b/kms.tf index e5bd8a7..617f704 100644 --- a/kms.tf +++ b/kms.tf @@ -67,7 +67,6 @@ resource "aws_kms_key" "encryption_rest" { enable_key_rotation = true description = "Key to encrypt cache at rest." deletion_window_in_days = 7 - #checkov:skip=CKV2_AWS_64: KMS Key policy in a separate resource tags = { Name = "${var.name}-encryption-rest" } diff --git a/network.tf b/network.tf index bc244a2..826f2ba 100644 --- a/network.tf +++ b/network.tf @@ -1,4 +1,6 @@ module "vpc" { + #CKV_TF_1: Ensure Terraform module sources use a commit hash + #checkov:skip=CKV_TF_1: This is a self hosted module where the version number is tagged rather than the commit hash. source = "github.com/kunduso/terraform-aws-vpc?ref=v1.0.0" region = var.region vpc_cidr = var.vpc_cidr From 4a240dcb33452ec64f31d6d9b9cd5715d1ec153d Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Sat, 16 Nov 2024 21:17:41 -0600 Subject: [PATCH 25/32] readability --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 05e8985..b08d8e7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-white.svg)](https://choosealicense.com/licenses/unlicense/)[![GitHub pull-requests closed](https://img.shields.io/github/issues-pr-closed/kunduso/amazon-elasticache-redis-tf)](https://github.com/kunduso/amazon-elasticache-redis-tf/pulls?q=is%3Apr+is%3Aclosed)[![GitHub pull-requests](https://img.shields.io/github/issues-pr/kunduso/amazon-elasticache-redis-tf)](https://GitHub.com/kunduso/amazon-elasticache-redis-tf/pull/) -[![GitHub issues-closed](https://img.shields.io/github/issues-closed/kunduso/amazon-elasticache-redis-tf)](https://github.com/kunduso/amazon-elasticache-redis-tf/issues?q=is%3Aissue+is%3Aclosed)[![GitHub issues](https://img.shields.io/github/issues/kunduso/amazon-elasticache-redis-tf)](https://GitHub.com/kunduso/amazon-elasticache-redis-tf/issues/) -[![terraform-infra-provisioning](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml)[![checkov-static-analysis-scan](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml) +[![License: Unlicense](https://img.shields.io/badge/license-Unlicense-white.svg)](https://choosealicense.com/licenses/unlicense/) [![GitHub pull-requests closed](https://img.shields.io/github/issues-pr-closed/kunduso/amazon-elasticache-redis-tf)](https://github.com/kunduso/amazon-elasticache-redis-tf/pulls?q=is%3Apr+is%3Aclosed) [![GitHub pull-requests](https://img.shields.io/github/issues-pr/kunduso/amazon-elasticache-redis-tf)](https://GitHub.com/kunduso/amazon-elasticache-redis-tf/pull/) +[![GitHub issues-closed](https://img.shields.io/github/issues-closed/kunduso/amazon-elasticache-redis-tf)](https://github.com/kunduso/amazon-elasticache-redis-tf/issues?q=is%3Aissue+is%3Aclosed) [![GitHub issues](https://img.shields.io/github/issues/kunduso/amazon-elasticache-redis-tf)](https://GitHub.com/kunduso/amazon-elasticache-redis-tf/issues/) +[![terraform-infra-provisioning](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml) [![checkov-static-analysis-scan](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml) ![Image](https://skdevops.files.wordpress.com/2023/12/87-image-0-1.png) From a97b23e79b7780c0b32908afbcf79f419b799e9d Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Mon, 18 Nov 2024 18:42:11 -0600 Subject: [PATCH 26/32] added ignore changes to elasticache --- elasticache.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/elasticache.tf b/elasticache.tf index d0cceba..b21cbae 100644 --- a/elasticache.tf +++ b/elasticache.tf @@ -45,8 +45,8 @@ resource "aws_elasticache_replication_group" "app4" { log_format = "json" log_type = "engine-log" } - # lifecycle { - # ignore_changes = [kms_key_id] - # } + lifecycle { + ignore_changes = [kms_key_id] + } apply_immediately = true } \ No newline at end of file From 5e4bffee7eac766a805e3d8d8c6b35d384cc1d40 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Mon, 18 Nov 2024 18:42:45 -0600 Subject: [PATCH 27/32] updated kms key and policy for #42 --- kms.tf | 66 ++++++++++++++++++---------------------------------------- 1 file changed, 20 insertions(+), 46 deletions(-) diff --git a/kms.tf b/kms.tf index 617f704..af3c5c2 100644 --- a/kms.tf +++ b/kms.tf @@ -9,59 +9,51 @@ resource "aws_kms_key" "encryption_secret" { } #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias resource "aws_kms_alias" "encryption_secret" { - name = "alias/${var.name}-elasticache-in-transit" + name = "alias/${var.name}-encryption-secret" target_key_id = aws_kms_key.encryption_secret.key_id } #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key_policy resource "aws_kms_key_policy" "encryption_secret_policy" { key_id = aws_kms_key.encryption_secret.id policy = jsonencode({ - Id = "${var.name}-encryption-secret" + Id = "${var.name}-encryption-secret" + Version = "2012-10-17" Statement = [ { - Action = [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion" - ] + Sid = "Enable IAM User Permissions" Effect = "Allow" Principal = { - AWS = "${local.principal_root_arn}" + AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" } + Action = "kms:*" Resource = "*" - Sid = "Enable IAM User Permissions" - Condition = { - StringEquals = { - "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" - } - } }, { - Sid = "AllowSecretsManagerUse" + Sid = "Allow access through AWS Secrets Manager for all principals in the account that are authorized to use AWS Secrets Manager" Effect = "Allow" + Principal = { + AWS = ["*"] + } Action = [ "kms:Encrypt", "kms:Decrypt", "kms:ReEncrypt*", + "kms:CreateGrant", + "kms:DescribeKey", "kms:GenerateDataKey*" ] Resource = "*" - Principal = { - Service = "secretsmanager.amazonaws.com" + Condition = { + StringEquals = { + "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" + "kms:ViaService" = "secretsmanager.${var.region}.amazonaws.com" + } } } ] }) } + #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key resource "aws_kms_key" "encryption_rest" { enable_key_rotation = true @@ -73,7 +65,7 @@ resource "aws_kms_key" "encryption_rest" { } #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias resource "aws_kms_alias" "encryption_rest" { - name = "alias/${var.name}-elasticache-at-rest" + name = "alias/${var.name}-encryption-rest" target_key_id = aws_kms_key.encryption_rest.key_id } #https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_key_policy @@ -83,31 +75,13 @@ resource "aws_kms_key_policy" "encryption_rest_policy" { Id = "${var.name}-encryption-rest" Statement = [ { - Action = [ - "kms:Create*", - "kms:Describe*", - "kms:Enable*", - "kms:List*", - "kms:Put*", - "kms:Update*", - "kms:Revoke*", - "kms:Disable*", - "kms:Get*", - "kms:Delete*", - "kms:ScheduleKeyDeletion", - "kms:CancelKeyDeletion" - ] + Action = ["kms:*"] Effect = "Allow" Principal = { AWS = "${local.principal_root_arn}" } Resource = "*" Sid = "Enable IAM User Permissions" - Condition = { - StringEquals = { - "kms:CallerAccount" = "${data.aws_caller_identity.current.account_id}" - } - } }, { Sid = "Allow ElastiCache to use the key" From 92f81274a70b5490ac44c64c7232389a0a2d1ca7 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Mon, 18 Nov 2024 18:43:06 -0600 Subject: [PATCH 28/32] using module to address vpc flow log #41 --- network.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/network.tf b/network.tf index 826f2ba..69d8cc9 100644 --- a/network.tf +++ b/network.tf @@ -1,7 +1,7 @@ module "vpc" { #CKV_TF_1: Ensure Terraform module sources use a commit hash #checkov:skip=CKV_TF_1: This is a self hosted module where the version number is tagged rather than the commit hash. - source = "github.com/kunduso/terraform-aws-vpc?ref=v1.0.0" + source = "github.com/kunduso/terraform-aws-vpc?ref=v1.0.1" region = var.region vpc_cidr = var.vpc_cidr enable_dns_support = "true" From c19994c40859837cf293b497dccfc50223b79881 Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Mon, 18 Nov 2024 18:52:32 -0600 Subject: [PATCH 29/32] updated for terraform docs #43 --- .github/workflows/documentation.yml | 25 +++++++++++++++++++++++++ README.md | 6 +++++- 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/documentation.yml diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 0000000..9067d15 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,25 @@ +#https://github.com/terraform-docs/gh-actions +name: generate-terraform-docs +on: + - pull_request +jobs: + docs: + runs-on: ubuntu-latest + permissions: + #checkov:skip=CKV2_GHA_1: This is required to add Terraform module details to the ReadMe.md + # Ensure top-level permissions are not set to write-all + contents: write + id-token: write + pull-requests: write + steps: + - uses: actions/checkout@v3 + with: + ref: ${{ github.event.pull_request.head.ref }} + + - name: Render terraform docs inside the README.md and push changes back to PR branch + uses: terraform-docs/gh-actions@v1.3.0 + with: + working-dir: . + output-file: README.md + output-method: inject + git-push: "true" \ No newline at end of file diff --git a/README.md b/README.md index b08d8e7..514290c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ [![License: Unlicense](https://img.shields.io/badge/license-Unlicense-white.svg)](https://choosealicense.com/licenses/unlicense/) [![GitHub pull-requests closed](https://img.shields.io/github/issues-pr-closed/kunduso/amazon-elasticache-redis-tf)](https://github.com/kunduso/amazon-elasticache-redis-tf/pulls?q=is%3Apr+is%3Aclosed) [![GitHub pull-requests](https://img.shields.io/github/issues-pr/kunduso/amazon-elasticache-redis-tf)](https://GitHub.com/kunduso/amazon-elasticache-redis-tf/pull/) [![GitHub issues-closed](https://img.shields.io/github/issues-closed/kunduso/amazon-elasticache-redis-tf)](https://github.com/kunduso/amazon-elasticache-redis-tf/issues?q=is%3Aissue+is%3Aclosed) [![GitHub issues](https://img.shields.io/github/issues/kunduso/amazon-elasticache-redis-tf)](https://GitHub.com/kunduso/amazon-elasticache-redis-tf/issues/) -[![terraform-infra-provisioning](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml) [![checkov-static-analysis-scan](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml) +[![terraform-infra-provisioning](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/terraform.yml) [![checkov-static-analysis-scan](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml/badge.svg?branch=main)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/code-scan.yml) [![Generate terraform docs](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/documentation.yml/badge.svg)](https://github.com/kunduso/amazon-elasticache-redis-tf/actions/workflows/documentation.yml) ![Image](https://skdevops.files.wordpress.com/2023/12/87-image-0-1.png) @@ -28,10 +28,14 @@ For this code to function without errors, I created an **OpenID connect** identi
I stored the ARN of the IAM Role as a GitHub secret which is referred in the [`terraform.yml`](https://github.com/kunduso/amazon-elasticache-redis-tf/blob/eb148db2b9ff37cff9f1fb469d0c14b6479bd57a/.github/workflows/terraform.yml#L42) file.
Since I used Infracost in this repository, I stored the `INFRACOST_API_KEY` as a repository secret. It is referenced in the [`terraform.yml`](https://github.com/kunduso/amazon-elasticache-redis-tf/blob/eb148db2b9ff37cff9f1fb469d0c14b6479bd57a/.github/workflows/terraform.yml#L52) GitHub actions workflow file.
As part of the Infracost integration, I also created a `INFRACOST_API_KEY` and stored that as a GitHub Actions secret. I also managed the cost estimate process using a GitHub Actions variable `INFRACOST_SCAN_TYPE` where the value is either `hcl_code` or `tf_plan`, depending on the type of scan desired. + + ## Usage Ensure that the policy attached to the IAM role whose credentials are being used in this configuration has permission to create and manage all the resources that are included in this repository.
Review the code including the [`terraform.yml`](./.github/workflows/terraform.yml) to understand the steps in the GitHub Actions pipeline. Also review the terraform code to understand all the concepts associated with creating an AWS VPC, subnets, internet gateway, route table, and route table association.
If you want to check the pipeline logs, click on the **Build Badge** (terrform-infra-provisioning) above the image in this ReadMe. +## Contributing +If you find any issues or have suggestions for improvement, feel free to open an issue or submit a pull request. Contributions are always welcome! ## License This code is released under the Unlincse License. See [LICENSE](LICENSE). \ No newline at end of file From 444fe6d5fea9c433ec1f641109a2232168c2baf0 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 19 Nov 2024 01:39:50 +0000 Subject: [PATCH 30/32] terraform-docs: automated action --- README.md | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/README.md b/README.md index 514290c..39b5d21 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,80 @@ For this code to function without errors, I created an **OpenID connect** identi
Since I used Infracost in this repository, I stored the `INFRACOST_API_KEY` as a repository secret. It is referenced in the [`terraform.yml`](https://github.com/kunduso/amazon-elasticache-redis-tf/blob/eb148db2b9ff37cff9f1fb469d0c14b6479bd57a/.github/workflows/terraform.yml#L52) GitHub actions workflow file.
As part of the Infracost integration, I also created a `INFRACOST_API_KEY` and stored that as a GitHub Actions secret. I also managed the cost estimate process using a GitHub Actions variable `INFRACOST_SCAN_TYPE` where the value is either `hcl_code` or `tf_plan`, depending on the type of scan desired. +## Requirements + +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | 5.20.1 | +| [random](#requirement\_random) | 3.6.3 | + +## Providers + +| Name | Version | +|------|---------| +| [aws](#provider\_aws) | 5.20.1 | +| [random](#provider\_random) | 3.6.3 | + +## Modules + +| Name | Source | Version | +|------|--------|---------| +| [vpc](#module\_vpc) | github.com/kunduso/terraform-aws-vpc | v1.0.1 | + +## Resources + +| Name | Type | +|------|------| +| [aws_cloudwatch_log_group.engine_log](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/cloudwatch_log_group) | resource | +| [aws_cloudwatch_log_group.slow_log](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/cloudwatch_log_group) | resource | +| [aws_elasticache_replication_group.app4](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/elasticache_replication_group) | resource | +| [aws_elasticache_subnet_group.elasticache_subnet](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/elasticache_subnet_group) | resource | +| [aws_iam_instance_profile.ec2_profile](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_instance_profile) | resource | +| [aws_iam_policy.secret_manager_policy](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_policy) | resource | +| [aws_iam_policy.ssm_parameter_policy](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_policy) | resource | +| [aws_iam_role.ec2_role](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_role) | resource | +| [aws_iam_role_policy_attachment.custom](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.secret_policy_attachement](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_role_policy_attachment) | resource | +| [aws_iam_role_policy_attachment.ssm_policy_attachement](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/iam_role_policy_attachment) | resource | +| [aws_instance.app-server-read](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/instance) | resource | +| [aws_instance.app-server-write](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/instance) | resource | +| [aws_kms_alias.encryption_rest](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/kms_alias) | resource | +| [aws_kms_alias.encryption_secret](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/kms_alias) | resource | +| [aws_kms_key.encryption_rest](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/kms_key) | resource | +| [aws_kms_key.encryption_secret](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/kms_key) | resource | +| [aws_kms_key_policy.encryption_rest_policy](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/kms_key_policy) | resource | +| [aws_kms_key_policy.encryption_secret_policy](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/kms_key_policy) | resource | +| [aws_secretsmanager_secret.elasticache_auth](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/secretsmanager_secret) | resource | +| [aws_secretsmanager_secret_version.auth](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/secretsmanager_secret_version) | resource | +| [aws_security_group.ec2_instance](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/security_group) | resource | +| [aws_security_group.elasticache](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/security_group) | resource | +| [aws_security_group_rule.ec2_instance_egress](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.ec2_instance_ingress](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.elasticache_egress](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/security_group_rule) | resource | +| [aws_security_group_rule.elasticache_ingress](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/security_group_rule) | resource | +| [aws_ssm_parameter.elasticache_ep](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/ssm_parameter) | resource | +| [aws_ssm_parameter.elasticache_port](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/resources/ssm_parameter) | resource | +| [random_password.auth](https://registry.terraform.io/providers/hashicorp/random/3.6.3/docs/resources/password) | resource | +| [aws_ami.amazon_ami](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/data-sources/ami) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/5.20.1/docs/data-sources/caller_identity) | data source | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| [access\_key](#input\_access\_key) | The access\_key that belongs to the IAM user. | `string` | `""` | no | +| [ami\_name](#input\_ami\_name) | The ami name of the image from where the instances will be created | `list(string)` |
[
"amzn2-ami-amd-hvm-2.0.20230727.0-x86_64-gp2"
]
| no | +| [instance\_type](#input\_instance\_type) | The instance type of the EC2 instances | `string` | `"t3.medium"` | no | +| [name](#input\_name) | The name of the application. | `string` | `"app-4"` | no | +| [region](#input\_region) | AWS Cloud infrastructure region. | `string` | `"us-east-2"` | no | +| [secret\_key](#input\_secret\_key) | The secret\_key that belongs to the IAM user. | `string` | `""` | no | +| [subnet\_cidr\_private](#input\_subnet\_cidr\_private) | CIDR blocks for the private subnets. | `list(any)` |
[
"10.20.32.0/27",
"10.20.32.32/27",
"10.20.32.64/27"
]
| no | +| [subnet\_cidr\_public](#input\_subnet\_cidr\_public) | CIDR blocks for the public subnets. | `list(any)` |
[
"10.20.32.96/27"
]
| no | +| [vpc\_cidr](#input\_vpc\_cidr) | CIDR for the VPC. | `string` | `"10.20.32.0/25"` | no | + +## Outputs + +No outputs. ## Usage Ensure that the policy attached to the IAM role whose credentials are being used in this configuration has permission to create and manage all the resources that are included in this repository. From 82dedf3ca530465dd8a462d73ea7f5f25027e60e Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Mon, 18 Nov 2024 19:41:21 -0600 Subject: [PATCH 31/32] suppressing checkov scan --- .github/workflows/code-scan.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/code-scan.yml b/.github/workflows/code-scan.yml index 5a97381..2e0ae35 100644 --- a/.github/workflows/code-scan.yml +++ b/.github/workflows/code-scan.yml @@ -34,6 +34,8 @@ jobs: # This will add both a CLI output to the console and create a results.sarif file output_format: cli,sarif output_file_path: console,results.sarif + #https://github.com/bridgecrewio/checkov/issues/6216 + skip_check: CKV2_GHA_1 - name: Upload SARIF file uses: github/codeql-action/upload-sarif@v2 From 0d5dac3ad0c73956855ac46f1aa99147e47336eb Mon Sep 17 00:00:00 2001 From: Sourav Kundu Date: Tue, 19 Nov 2024 06:02:06 -0600 Subject: [PATCH 32/32] corrected ec2 subnet #45 --- ec2.tf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ec2.tf b/ec2.tf index 380feda..7f21eb4 100644 --- a/ec2.tf +++ b/ec2.tf @@ -48,7 +48,7 @@ resource "aws_instance" "app-server-read" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true #checkov:skip=CKV_AWS_88: Required for Session Manager access - subnet_id = module.vpc.private_subnets[0].id + subnet_id = module.vpc.public_subnets[0].id ebs_optimized = true monitoring = true root_block_device { @@ -77,7 +77,7 @@ resource "aws_instance" "app-server-write" { iam_instance_profile = aws_iam_instance_profile.ec2_profile.name associate_public_ip_address = true #checkov:skip=CKV_AWS_88: Required for Session Manager access - subnet_id = module.vpc.private_subnets[0].id + subnet_id = module.vpc.public_subnets[0].id ebs_optimized = true monitoring = true root_block_device {