Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use vpc module #44

Merged
merged 21 commits into from
Nov 19, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions .github/workflows/documentation.yml
Original file line number Diff line number Diff line change
@@ -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:

Check failure on line 8 in .github/workflows/documentation.yml

View workflow job for this annotation

GitHub Actions / scan

CKV2_GHA_1: "Ensure top-level permissions are not set to write-all"

Check failure on line 8 in .github/workflows/documentation.yml

View workflow job for this annotation

GitHub Actions / scan

CKV2_GHA_1: "Ensure top-level permissions are not set to write-all"
#checkov:skip=CKV2_GHA_1: This is required to add Terraform module details to the ReadMe.md
Fixed Show fixed Hide fixed
# 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/[email protected]
with:
working-dir: .
output-file: README.md
output-method: inject
git-push: "true"
10 changes: 7 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -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) [![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)
Expand Down Expand Up @@ -28,10 +28,14 @@ For this code to function without errors, I created an **OpenID connect** identi
<br />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.
<br />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.
<br />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.
<!-- BEGIN_TF_DOCS -->
<!-- END_TF_DOCS -->
## 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.

<br />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.
<br />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).
6 changes: 4 additions & 2 deletions cloudwatch.tf
Original file line number Diff line number Diff line change
@@ -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
}
4 changes: 2 additions & 2 deletions data.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
63 changes: 31 additions & 32 deletions ec2.tf
Original file line number Diff line number Diff line change
@@ -1,36 +1,32 @@
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
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/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
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
from_port = 0
to_port = 0
protocol = "-1"
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
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
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ami
data "aws_ami" "amazon_ami" {
filter {
name = "name"
Expand All @@ -43,14 +39,16 @@ 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
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
#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 {
Expand All @@ -61,7 +59,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",
{
Expand All @@ -71,14 +69,15 @@ 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
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
#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 {
Expand All @@ -89,7 +88,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",
{
Expand Down
8 changes: 4 additions & 4 deletions ec2_role.tf
Original file line number Diff line number Diff line change
@@ -1,7 +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.
assume_role_policy = jsonencode({
Expand All @@ -24,18 +23,19 @@ 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
}
#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
}
14 changes: 8 additions & 6 deletions elasticache.tf
Original file line number Diff line number Diff line change
@@ -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 = "app-4-cache-subnet"
subnet_ids = [for subnet in aws_subnet.private : subnet.id]
name = "${var.name}-cache-subnet"
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 = "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
}
#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
Expand All @@ -18,8 +20,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
Expand Down
4 changes: 2 additions & 2 deletions iam_role.tf
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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
Expand Down
80 changes: 73 additions & 7 deletions kms.tf
Original file line number Diff line number Diff line change
@@ -1,38 +1,104 @@

#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
#checkov:skip=CKV2_AWS_64: Not including a 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/elasticache-app-4-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"
Version = "2012-10-17"
Statement = [
{
Sid = "Enable IAM User Permissions"
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root"
}
Action = "kms:*"
Resource = "*"
},
{
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 = "*"
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
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"
}
}
#https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/kms_alias
resource "aws_kms_alias" "encryption_rest" {
name = "alias/elasticache-app-4-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
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:*"
Action = ["kms:*"]
Effect = "Allow"
Principal = {
AWS = "${local.principal_root_arn}"
}
Resource = "*"
Sid = "Enable IAM User Permissions"
},
{
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",
Principal : {
Expand Down
Loading
Loading